I am trying to animate an ImageView using TranslateAnimation from it's current position (0,Yscreensize/2) to the other side of the screen (Xscreensize,imageview.getY()) but I can't manage it to work. here is my code:
dart = (ImageView) findViewById(R.id.dart);
Display disp = getWindowManager().getDefaultDisplay();
Point poi = new Point();
disp.getSize(poi);
sizex = poi.x;
sizey = poi.y;
ViewTreeObserver vto = dart.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
dart.getViewTreeObserver().removeOnPreDrawListener(this);
finalHeight = dart.getMeasuredHeight();
dart.setY(sizey / 2 - finalHeight);
return true;
}
}); // till now - got screen size and set dart imageview to Y middle.
Now when I am trying to use the animation:
TranslateAnimation animation = new TranslateAnimation(dart.getX(), sizex, dart.getY(), dart.getY());
animation.setDuration(10000);
dart.startAnimation(animation); // from current x to screen size, from currenty to currenty.
this will not work and the dart just dissappear. what can I do?
Make the variable for the animation a class variable (to ensure it won't be garbage collected to soon). In order to make the ImageView stop its movement before it leaves the screen, you need an additional class variable
float finalWidth;
Then change your OnPreDrawListener like this:
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
{
public boolean onPreDraw()
{
dart.getViewTreeObserver().removeOnPreDrawListener(this);
float finalHeight = dart.getMeasuredHeight();
// if you want the view to stop before it leaves the screen
float finalWidth = dart.getMeasuredWidth();
animation = new TranslateAnimation(0, sizex - finalWidth, 0, 0);
animation.setDuration(10000);
// use this if you want the changes to persist
// animation.setFillAfter(true);
dart.setY(sizey / 2 - finalHeight);
return true;
}
});
I used a button to call 'startAnimation()'. The only problem when testing with an emulator is that the ImageView keeps running until it reaches the emulator window egde. So it disappears below the hardware controls region on the right side. In order to make it stop earlier, I tested with
Rect myRect = new Rect();
dart.getWindowVisibleDisplayFrame(myRect);
sizex = myRect.width() * 0.9f;
sizey = myRect.height();
which almost did the trick. It's just an approximation, all right, but getting the exact dimensions of the display - taking into account paddings or insets - seems to be difficult. At least below API 20.
Hope this helps anyway :)
Related
I am new in android. I want to make ludo game. and I sets all things related to this game. but I want to move TOKEN from one place to another for different screens like (Nexus 6, Samsung Note 5, Moto G3, etc...). But issue is that for every screen size (Width x Height) are different. that's why I am not set proper x and y position on screen. I referenced screen Height and Width for taking next position (x and y) on screen to move TOKEN on screen. I am taking static image for Ludo Dashboard. That's why i am not getting how to move.
for example:
My Screen is as below,
from origin position to Home position :
In this situation, for every screens translation was changed. because i am taking reference screen Height and Width for move.
for that code is below,
DisplayMetrics displaymetrics = getResources().getDisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
this.constant.Height = displaymetrics.heightPixels;
this.constant.Width = displaymetrics.widthPixels;
private float getheight(float val) {
return (this.constant.Height * val) / 800;
}
private float getwidth(float val) {
return (this.constant.Width * val) / 480;
}
ObjectAnimator animTranslateY = ObjectAnimator.ofFloat(img,
"translationY", blue_1.getY() + getheight(67));
animTranslateY.setDuration(GameConstants.DURATION);
ObjectAnimator animTranslateX = ObjectAnimator.ofFloat(img,
"translationX", blue_1.getX() + getwidth(128));
animTranslateX.setDuration(GameConstants.DURATION);
AnimatorSet anim = new AnimatorSet();
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
anim.play(animTranslateX);
anim.play(animTranslateY);
anim.start();
from Home to Common Rout :
In this situation, its work fine. bt for different screen its moving differ.
So, my question is that How can i move and what should be reference for move image form one position to another position. I takes too many time for this. Please help me.
So, I tried to come up with a solution that uses simple unitary method to solve your problem. I am not sure if it works, I did not try it by coding it actually!
I am assuming that you have set the background static image to scale its size (width) to 100% of the screen, your static image is a square(usually a ludo board is). Also I am considering here that screenwidth is smaller than screenheight. If it is the other way around then exchange the formulae symbols.
let
screenH = screen height in pixels;
screenW = screen width in pixels;
bgW = width of staticbackgroundimage in pixels;
bgH = height of staticbackgroundimage in pixels;
so now, if you want to move 'p' pixels in the background static ludo image horizontally then let us say you will have to move x pixels on the screen. x can be calculated as follows:
x= p*screenW/bgW;
Also, if you want to move 'q' pixels in the background static ludo image vertically then let us say you will have to move y pixels on the screen. y can be calculated as follows:
image height on the screen will be(in pixels):
screenHimage=bgH*screenW/bgW;
y=q*screenHimage/bgH;
So now move x and y pixels on the screen if you want to move p and q pixels in the original image.
I hope this works.
I have set up a game where Actor fireflies randomly fly across the screen, while glowing on and off — and a user can drag them into a mason jar. Pretty happy I've got this working, but I'd like to add a bit more detail. I'd like to add a two-step animation so that it looks like their wings are flapping.
I know how to do this with the Animation class, making use of TextureAtlas and TextureRegion. But that was prior to me heading in this Drag n Drop direction.
My issue, I think, is that I'm using skins, and they might not play nice with Animations.
///////////////////
Portions of my code.
///////////////////
Some of the items I declare up top:
private TextureAtlas textureAtlas;
private Texture texture;
private TextureRegion[] regions = new TextureRegion[3];
private Animation ffFlapping;
Setting up my TextureAtlas:
textureAtlas = new TextureAtlas(Gdx.files.internal("Player Animation/player_animation.png.atlas"));
texture = new Texture(Gdx.files.internal("Player Animation/player_animation.png.png"));
Setting up the skin:
final Skin skin = new Skin();
skin.addRegions(textureAtlas);
Doing the animation:
TextureRegion[] ffAnimation = new TextureRegion[2];
ffAnimation[0] = (textureAtlas.findRegion("firefly-0"));
ffAnimation[1] = (textureAtlas.findRegion("firefly-1"));
ffFlapping = new Animation(0.01f, ffAnimation);
For loop to create all my fireflies:
// ********************************************
// iterate through the number of fireflies
// we want to draw out using fireflyCount
// ********************************************
for (int fireflyIndex = 0; fireflyIndex < fireflyCount; fireflyIndex++) {
// YELLOW FIREFLY HERE
String fireflyName = "firefly" + fireflyIndex;
// if I replace ffFlapping below with object, I get no errors,
// but also no animation
skin.add(fireflyName, ffFlapping);
final Firefly ff = new Firefly(skin, fireflyName);
System.out.println("Fireflies objects:" + fireflyIndex);
// Not sure this affected the color, but it starts the alpha at 0
ff.setColor(150, 150, 150, 0);
ff.setOrigin(ff.getWidth()/2, ff.getHeight()/2);
stage.addActor(ff);
// This was set up in the attempt to continue movement if user misses target
final MoveToAction actionRight = new MoveToAction();
final MoveToAction actionLeft = new MoveToAction();
// setting up right and left targets, with a random Y position
float toRight = Gdx.graphics.getWidth() + 60;
float toLeft = (Gdx.graphics.getWidth() -Gdx.graphics.getWidth())-60f;
// sets up speed of glow, and the random time firefly is off, and also on
float glow = MathUtils.random(.5f, 1f);
float delayRandomOff = MathUtils.random(2.3f, 4.5f);
float delayRandomOn = MathUtils.random(.5f, .9f);
// sets up first variable to randomly choose between toRight and toLeft
// assigns direction to that value
float randomDirection = MathUtils.random.nextBoolean() ? toRight : toLeft;
float direction = randomDirection;
SequenceAction sequence = new SequenceAction();
AlphaAction aa = new AlphaAction();
Action alphaStartOn = Actions.delay(delayRandomOn, Actions.fadeOut(glow));
Action alphaStartOff = Actions.delay(delayRandomOff, Actions.fadeIn(glow));
// toRight is the x value ... it goes (x, y, duration)
Action startRight = Actions.moveTo(toRight, MathUtils.random(50, Gdx.graphics.getHeight() - 40), MathUtils.random(10f, 45f));
// toLeft is the x value ... it goes (x, y, duration)
// 170 makes sure they don't fly on top of mason jar
Action startLeft = Actions.moveTo(toLeft, MathUtils.random(170, Gdx.graphics.getHeight() - 40), MathUtils.random(10f, 45f));
Action faceOpposite = Actions.rotateBy(180f);
Action faceOpposite2 = Actions.rotateBy(180f);
// THIS ENDLESSLY LOOPS THEM ON THE SCREEN
Action loopRight = Actions.forever(Actions.sequence(faceOpposite, startRight, faceOpposite2, startLeft));
Action loopLeft = Actions.forever(Actions.sequence(startLeft, faceOpposite, startRight, faceOpposite2));
Action loopGlow1 = Actions.forever(Actions.sequence(alphaStartOn, alphaStartOff));
Action loopGlow2 = Actions.forever(Actions.sequence(alphaStartOff, alphaStartOn));
// THIS IS DEFINITELY TRIGGERING THE MOVEMENT
if(direction == toRight) {
ff.addAction(loopRight);
ff.addAction(loopGlow1);
} else {
ff.addAction(loopLeft);
ff.addAction(loopGlow2);
}
// MAKE EACH FIREFLY DRAGGABLE, and SET LARGER SIZE as you drag
dragAndDrop.addSource(new DragAndDrop.Source(ff) {
public DragAndDrop.Payload dragStart (InputEvent event, float x, float y, int pointer) {
DragAndDrop.Payload payload = new DragAndDrop.Payload();
payload.setObject("Firefly captured");
payload.setDragActor(ff);
ff.clearActions();
getActor().setSize(80, 80);
// Firefly freezes on drag, and enlarges ... disappears if dropped in jar
// Does not visually drag with cursor since it was part of animation.
return payload;
}
// IF YOU DON'T DROP FIREFLY ON TARGET, MAKE SURE IT STAYS ON STAGE
// AND GOES BACK TO THE NORMAL SIZE
#Override
public void dragStop(InputEvent event, float x, float y, int pointer, DragAndDrop.Payload payload, DragAndDrop.Target target) {
if(target == null)
stage.addActor(ff);
ff.addAction(actionLeft);
getActor().setSize(50, 50);
}
});
// MAKE EACH FIREFLY DRAGGABLE, and SET LARGER SIZE as you drag
dragAndDrop.addSource(new DragAndDrop.Source(ff) {
public DragAndDrop.Payload dragStart (InputEvent event, float x, float y, int pointer) {
DragAndDrop.Payload payload = new DragAndDrop.Payload();
payload.setObject("Firefly captured");
payload.setDragActor(ff);
ff.clearActions();
getActor().setSize(80, 80);
// Firefly freezes on drag, and enlarges ... disappears if dropped in jar
// Does not visually drag with cursor since it was part of animation.
return payload;
}
// IF YOU DON'T DROP FIREFLY ON TARGET, MAKE SURE IT STAYS ON STAGE
// AND GOES BACK TO THE NORMAL SIZE
#Override
public void dragStop(InputEvent event, float x, float y, int pointer, DragAndDrop.Payload payload, DragAndDrop.Target target) {
if(target == null)
stage.addActor(ff);
ff.addAction(actionLeft);
getActor().setSize(50, 50);
}
});
} // ***** END OF FOR LOOP ***********
And here's my Firefly code:
public class Firefly extends Image {
private float x = MathUtils.random(20, Gdx.graphics.getWidth() -40);
private float y = MathUtils.random(200, Gdx.graphics.getHeight() - 40);
private float width = 70;
private float height = 70;
public Firefly(Skin skin, String drawableName) {
super(skin, drawableName);
this.setBounds(x, y, width, height);
}
} // firefly
The error I'm getting is:
com.badlogic.gdx.utils.GdxRuntimeException: No Drawable, NinePatch, TextureRegion, Texture, or Sprite registered with name: firefly-2
///////////////////////////////
Any tips are very much appreciated.
In the meantime, I'm creating a new feature branch and keeping at it.
My guess is that I need to somehow make my two-step animation into some kind of Drawable.
Thanks!
— Bill
After few hours of trying I'm looking for some hints on how to add snap-scroll mechanism to MPAndroid. Basically I want the 5 visible bars to align so they are fully visible and centered. I now imported the library source code because it looks like there's no other way to change the code in computeScroll (BarLineChartTouchListener).
Edit:
To clarify - I'm showing around 20 bars but chart is zoomed so user can scroll horizontally. What bothers me it is not getting aligned automatically so first visible bar might be clipped in half. I'm looking for snapping effect where it will round the position to the nearest multiplication of the bar width, leaving 5 fully visible bars.
I ended up adding the following function in BarLineChartBase.java. I know it's far from elegant, but seems to do the job. It's limited to targetApi > 11, because of the ValueAnimator. For lower API (which I don't cater for) you might need to have a look at nineoldandroids or some other animation loop technique.
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void alignX() {
int count = this.getValueCount();
int xIndex = this.getLowestVisibleXIndex() + Math.round( (this.getHighestVisibleXIndex() - this.getLowestVisibleXIndex()) / 2.0f );
float xsInView = this.getXAxis().getValues().size() / this.getViewPortHandler().getScaleX();
Transformer mTrans = this.getTransformer(YAxis.AxisDependency.LEFT);
float[] pts = new float[] { xIndex - xsInView / 2f, 0 };
mTrans.pointValuesToPixel(pts);
final Matrix save = new Matrix();
save.set(this.getViewPortHandler().getMatrixTouch());
final float x = pts[0] - this.getViewPortHandler().offsetLeft();
final int frames = 20;
ValueAnimator valueAnimator = new ValueAnimator().ofInt(0, frames);
valueAnimator.setDuration(500);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int prev = -1;
#Override
public void onAnimationUpdate(ValueAnimator animation) {
if( (int) animation.getAnimatedValue() > prev ) {
save.postTranslate( -x / (float)frames, 0);
BarLineChartBase.this.getViewPortHandler().refresh(save, BarLineChartBase.this, true);
}
prev = (int) animation.getAnimatedValue();
}
});
valueAnimator.start();
}
I trigger it at the end of computeScroll function in BarLineChartTouchListener.
I kept names of variables as I copied code from functions like MoveViewJob, ViewPortHandler etc. Since it's only aligning in x axis - I removed Y axis calculations and used zeros instead. Any optimizations welcome, especially from the author #PhilippJahoda.
I am using showCaseView legacy(which has the animation of the hand) in my android app. But, the gesture doesnt seem to start 'relative' to the view. Instead, it seems to be absolute to the screen. This is the following which i am using:
final ShowcaseView sv;
ShowcaseView.ConfigOptions co = new ShowcaseView.ConfigOptions();
co.hideOnClickOutside = false;
co.block=true;
sv = ShowcaseView.insertShowcaseView(R.id.pen, this," R.string.showcase_title"," R.string.showcase_message", co);
View v=(View)findViewById(R.id.pen);
sv.animateGesture(0, 0, 0, -500, false);
This is the top of my emulator, the animation STARTS from here:
This shows a hand at the top left corner of the screen. (my guess is that the view's locations are being returned 0.
What is the problem ?
Your best bet is probably going to be to use DisplayMetrics to place the hand, that's what I've done and it seems to work well.
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int height = displaymetrics.heightPixels;
int width = displaymetrics.widthPixels;
float offsetEndY = height / 2 + 50;
float offsetEndX = -width;
float offsetStartY = height / 2 + 50;
float offsetStartX = -width / 2;
if (sv == null) {
sv = ShowcaseView.insertShowcaseView(width, 0, activity, "Menu", "Swipe to access more options", mOptions)
.setTextColors(Color.BLUE, Color.BLACK);
sv.animateGesture(offsetStartX, offsetStartY, offsetEndX, offsetEndY);
I had the same problem and I from logging showcase positions at different stages I found that proper position is strangely calculated some (very short) time after show() is called.
When I was calling
showcaseView.show();
showcaseView.animateGesture(0, 0, 0, -400);
this DIDN'T work.
Easy solution is show hand gesture with some delay (200 ms was enough in my case - tested on many devices):
showcaseView.show();
showcaseView.postDelayed(new Runnable() {
#Override
public void run() {
showcaseView.animateGesture(0, 0, 0, -400);
}
}, 200);
In my app, when the user touches the screen, a circle is drawn, and if a circle has already been drawn at point a, then another circle cannot be drawn there.
when I use canvas.drawCircle(...), it's innacurate. if I tap close to the top of the screen, then it is just very minutely missing where I tapped it (slightly to the left or right). The farther I go down the farther up my circle is from where I touched. If I'm touching the left side of the screen, the circle goes to the right of the touch point, and if I touch the right side of the screen, the circle is on the left.
Here's my code:
public void onCreate(...){
super.onCreate();
setcontentView(...);
drawnX = new ArrayList<Float>();
drawnY = new ArrayList<Float>();
layout = (ImageView)findViewById(R.id.layout);
layout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent me) {
newY = me.getY();
newX = me.getX();
int action = me.getAction();
if (action==0){
Log.v(tag, "New Touch");
Log.i(tag, String.valueOf("Action " + action +
" happened at X,Y: " + "("+newX+","+newY + ")"));
getDistance(newX, newY);
}
return true;
}
});
#Override
public void onResume(){
super.onResume();
display = getWindowManager().getDefaultDisplay();
screenHeight = display.getHeight();
screenWidth = display.getWidth();
bitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888);
canvas = new Canvas(bitmap);
paint = new Paint();
circleRadius = screenHeight/50;
}
public void getDistance(float xNew, float yNew){
// here I compare the new touch x and y values with the x and y values saved
// in the Array Lists I made above. If distance is > circleRadius, then:
drawPoint(xNew, yNew)
}
public void drawPoint(final float x, final float y){
minDistance = Float.NaN;
new Thread(new Runnable(){
#Override
public void run(){
paint.setColor(Color.RED);
canvas.drawCircle(x, y, circleRadius, paint);
layout.post(new Runnable(){
#Override
public void run(){
layout.setImageDrawable(new BitmapDrawable(bitmap));
//I have also tried setImageBitmap and setBackgroundDrawable
}
});
}
}).start();
}
Int the process of all of this, I also do some logging in the drawPoint, and it shows that the x and y coordinates match that which are gotten in the onTouch.
I've also tried maknig it a LinearLayout, but that had the same effect.
And, the bitmap size matches the screen size and canvas size. also, for testing I did
canvas.drawARGB(...)
and it covered the whole screen, so I know it's not just that the bitmap is not stretching to the bottom. The layout's height is less than the height of everything else, and the width of the layout is the same as everything else, but when I use layout.getHeight and layout.getWidth in my onResume, they always return 0, so I can't really use that.
I really have no clue what's causing it. I also tried it on two emulators and got the same response. Any help would be greatly appreciated.
Also, if I tap on the drawn circle (toward the bottom of the screen), another circle will then be drawn above that one, but if I tap where I previously tapped, then a new circle will not be drawn, which really is what's suppose to happen. the circle is just not showing on the screen correctly.
I found the answer.
Oddly enough, even though the width of the bitmap matched the width of the layout, when I did a little more testing, I found the dimensions didn't actually fit together on the left and right either.
I wasn't using the layout.getWidth() and layout.getHeight() due to it returning 0 in onResume()
But, I thought the different height from display.getHeight() very well may be causing the problem, so I did essentially:
new Handler().postDelayed(getLayoutSizeRunnable, 5000);
where getLayoutSizeRunnable was essentially:
screenWidth = layout.getWidth();
screenHeight = layout.getHeight();
Then everything worked perfectly.
And for the usage in my app, I'll use an if statement so the first time a touch point is made, the layout size will be calculated, and the bitmap will be created based on it.