I have a small game in my application, if you get something right balloons float up the screen, the balloons are views moved by 2 ObjectAnimators in an animation set, and on my main debugging device it works fine but on other devices (including tablets) it looks aweful the values are all over the place and the views violently sway from one side to the next.
here is a snippet of what im doing:
//2 square balloons floating
sb = (ImageView)findViewById(R.id.squareballoon);
sb.setVisibility(View.VISIBLE);
sb2 = (ImageView)findViewById(R.id.squareballoon2);
sb2.setVisibility(View.VISIBLE);
sp.play(inflate, 1, 1, 0, 0, 1);
//left balloon
ObjectAnimator sqbalAnim3 = ObjectAnimator.ofFloat(sb,"x",-500,500);
sqbalAnim3.setDuration(700);
sqbalAnim3.setRepeatCount(5);
sqbalAnim3.setRepeatMode(ValueAnimator.REVERSE);
ObjectAnimator sqbalAnim = ObjectAnimator.ofFloat(sb,"y",2000,-1800);
sqbalAnim.setDuration(3000);
sqbalAnim.setRepeatMode(ValueAnimator.RESTART);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(sqbalAnim, sqbalAnim3);
animSetXY.start();
//right balloon
ObjectAnimator sqbalAnim4 = ObjectAnimator.ofFloat(findViewById(R.id.squareballoon2),"x",-1500,-500);
sqbalAnim4.setDuration(700);
sqbalAnim4.setRepeatCount(5);
sqbalAnim4.setRepeatMode(ValueAnimator.REVERSE);
ObjectAnimator sqbal2Anim = ObjectAnimator.ofFloat(findViewById(R.id.squareballoon2),"y",1800,-1800);
sqbal2Anim.setDuration(3000);
sqbal2Anim.setRepeatMode(ValueAnimator.RESTART);
AnimatorSet animSetXY2 = new AnimatorSet();
animSetXY2.playTogether(sqbal2Anim,sqbalAnim4);
animSetXY2.start();
//balloon animation end
animSetXY2.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
sp.play(dropSound,1,1,0,0,1);
sb.setBackgroundResource(R.drawable.burst);
pop = (AnimationDrawable) sb.getBackground();
pop.start();
sb2.setBackgroundResource(R.drawable.burst);
pop = (AnimationDrawable) sb2.getBackground();
pop.start();
}
});
return true;}
//end of square balloons
ive read i can use a fraction rather than explicit values, can anybody help me out with this or point in the right direction,
any and all suggestions welcome, many thanks
I guess your problem is in parameters you are using (hardcoding) like:
ObjectAnimator.ofFloat(sb,"x",-500,500);
ObjectAnimator.ofFloat(sb,"y",2000,-1800);
Since such values are only good for the device (screen actually) you are testing on. Other devices has other screens with other resolutions and you should consider it. Also you should maybe calc values from dp to pixels. What are 500 and 2000 actually? If its pixels then most probably thats the problem.
Take a look here (for dp to px):
What is the difference between "px", "dp", "dip" and "sp" on Android?
Android: 'dp' to 'px' conversion?
Related
I am trying to figure out how to animate an image from left to right, and then from right to left.
For example imagine the following image:
At full resolution, the width of the image would exceed the width of the screen. So initially, only the left side of the image should be visible, but as the animation is running, slowly the right side becomes visible, eg.:
Once the right side of the image was fully uncovered, the animation starts in reverse:
Any ideas how to achieve this?
Android APIs or any techniques would be of great help.
Using ObjectAnimator.
Well, I didn't really know, how to size image in without cropping, so I made view's width 1000dp.
Here is solution:
ImageView imageView = findViewById(R.id.imageView);
imageView.post(() -> {
Point point = new Point();
getWindowManager().getDefaultDisplay().getSize(point);
float width = imageView.getMeasuredWidth();
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0, -(width - point.x));
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
objectAnimator.setDuration(10000);
objectAnimator.start();
});
Let me explain.
First, I get size of device.
Point point = new Point();
getWindowManager().getDefaultDisplay().getSize(point);
Then, I get width of view and creating ObjectAnimator
float width = imageView.getMeasuredWidth();
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0, -(width - point.x));
First argument is a view, that will be animated. Second argument tells objectAnimator what method (in this case setter) to use. We use translationX, so objectAnimator use setTranslationX().
All other arguments tells objectAnimator from where to where it should animate.
We substracting point.x from width for animation stops when edge of image is shown. Else, imageView will slide to the left until image disappears.
For example:
ObjectAnimator.ofFloat(imageView, "translationX", 0, 200, 100, 300);
says that image should go by axis X to the point 0, then 200, then 100 and in the end 300.
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
tells that after animation done, do it again, but in reverse.
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
tells that animation must repeat itself infinitely.
objectAnimator.setDuration(10000);
Duration of the animation in milliseconds.
Try with TranslateAnimation:
First, you have to know how big is the view:
ImageView picture = findViewById(R.id.picture);
int pictureWidth = picture.getWidth();
private void animation(View view, float pictureWidth) {
Animation offSet = new TranslateAnimation(0, - moveTo, 0, 0);
offSet.setInterpolator(new AccelerateDecelerateInterpolator()); // just to make a smooth movement
offSet.setDuration(durationInMillis);
}
The code above will move to the left showing the right side of the image,
you can add something similar to reverse the movement.
There are for sure better and more complete solutions, this is just (I think) the easier.
I wish to have an animated background like this gif:
.
I don't have a mac or adobe after effects software to create a lottie json for such animation, and i want a more command over animation than simply using a gif. From what i have read over the internet, I have to use either TransitionManager or TranslationAnimation , but i am unable to figure out the correct code for it.
I am also interested in knowing if there is a plugin, or some way to make minor edits to already available lottie files like background color change , items color change, items removal, etc just like the way we could do for simple vector images(Using Android Studio, or at the very least, some free software). I found this lottie file which was doing a very great job for me, but i couldn't modify its colors
found it! When i logged the values of some variables like view.getX() or view.getRootView().getX(), i was able to figure out, that my view will have its location as 0,0 . so After that it was all a need for finding the screen size to finally make this infinite cloud moving animation. I am not sure if this function is good in terms of memory or performance , but on my device, its running smoothly.
private void showCloudMovingContinuouslyAnimation(View v) {
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int runtimeScreenWidth = displayMetrics.widthPixels;
int totalDuration = runtimeScreenWidth*5;
int viewPositionX = 0, viewPositionY = 0;
TranslateAnimation outToRight = new TranslateAnimation(
viewPositionX, (runtimeScreenWidth / 2f) + 50,
viewPositionY, viewPositionY);
outToRight.setDuration(totalDuration / 2);
outToRight.setRepeatCount(Animation.INFINITE);
TranslateAnimation inFromLeft = new TranslateAnimation(
-((runtimeScreenWidth / 2f) + 50), viewPositionX,
viewPositionY, viewPositionY
);
inFromLeft.setDuration(totalDuration / 2);
inFromLeft.setRepeatCount(Animation.INFINITE);
boolean shouldRemainThereAfterAnimationFinishes = true;// useful when animating for single time
AnimationSet animationSet=new AnimationSet(true);
animationSet.setInterpolator(new LinearInterpolator());
animationSet.setRepeatCount(Animation.INFINITE);
animationSet.addAnimation(inFromLeft);
animationSet.addAnimation(outToRight);
v.startAnimation(animationSet); // start animation
}
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'm sure there is an easy way to do this but I'm stuck.
Let's say I have a list of points :
Point[] list = {pointA, pointB, pointC, ...}
I'd like to animate an ImageView through each point
So I tried this :
id = 0;
AnimatorListenerAdapter animEnd = new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
id++;
if(id != list.length) {
iv.animate()
.translationX(list[id].getX())
.translationY(list[id].getY())
.setDuration(200)
.setListener(this);
}
}
};
iv.animate()
.translationX(list[id].getX()).translationY(list[id].getY())
.setDuration(200).setListener(animEnd);
It works but there 's a slight delay between each animation.
Any idea? Thanks !
You probably get the delays between your animation steps because you always start a fresh animation on each transition from step to step. To overcome this situation you have multiple options.
Keyframes
Here you can find a technique called Keyframe Animation, which is a very common animation technique and is probably exactly what you want.
A Keyframe object consists of a time/value pair that lets you define a specific state at a specific time of an animation. Each keyframe can also have its own interpolator to control the behavior of the animation in the interval between the previous keyframe's time and the time of this keyframe.
Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);
In your case you could map the points in your list to a list of Keyframe instances and ...
Point[] list = {pointA, pointB, pointC, ...}
List<Keyframe> kfs = new ArrayList<Keyframe>();
foreach (Point p : points) {
Keyframe kf = new Keyframe.ofFloat(p.x); // or what ever
kfs.add(kf);
}
... later pass these keyframes to some factory method to create some PropertyValuesHolder, like ofFloat that has the following signature:
public static PropertyValuesHolder ofFloat (
Property<?, Float> property,
float... values
)
The second parameter is a variable argument list which also accepts arrays as inputs. Thus it should be possible to pass your kfs to the method as a second argument, somehow.
In your case i would craft the following methods, since you are developing for dalvik VM you cannot use java8 lambda expressions:
// maps points to X/Y float values
List<Float> toArrayX(Point[] points) { ... }
List<Float> toArrayY(Point[] points) { ... }
// maps float values to Keyframes
List<Keyframe> toKeyframes(List<Float> floats) { ... }
void createAnimation(Point[] points) {
List<Keyframe> xs = toKeyframes(toArrayX(points));
PropertyValuesHolder phvX = PropertyValuesHolder
.ofKeyframe("translationX", xs);
List<Keyframe> ys = toKeyframes(toArrayY(points));
PropertyValuesHolder phvY = PropertyValuesHolder
.ofKeyframe("translationY", ys);
linkPropertyValuesHolder(phvX);
linkPropertyValuesHolder(phvY);
}
void linkPropertyValuesHolder(PropertyValuesHolder phv) {
// setup target
ObjectAnimator anim = ObjectAnimator
.ofPropertyValuesHolder(target, phv)
anim.setDuration(5000ms);
}
Interpolators
Alternatively you can specify the transitions given by the points through an Interpolator instance.
An interpolator defines the rate of change of an animation. This allows the basic animation effects (alpha, scale, translate, rotate) to be accelerated, decelerated, repeated, etc.
An interpolator maps a fractional float between 0.0 and 1.0 to another fractional float between 0.0 and 1.0. Like the following three; LinearInterpolator, AccelerateDecelerateInterpolator and BounceInterpolator:
Images from here
Path Interpolator
With PathInterpolators it is possible to draw arbritary interpolators using Path instances. The drawn path will be used to drive the animation. In your case you could create two paths, one for the x and another one for the y translation.
However, take care when constructing interpolators from paths, because
... the Path must conform to a function y = f(x).
The Path must not have gaps in the x direction and must not loop back on itself such that there can be two points sharing the same x coordinate. It is alright to have a disjoint line in the vertical direction:
So take a look at the following code snippet that is taken from here, creates a valid path and could be used as input for the PathInterpolator constructor.
Path path = new Path();
path.lineTo(0.25f, 0.25f);
path.moveTo(0.25f, 0.5f);
path.lineTo(1f, 1f);
Custom Interpolator
When the given interpolators are not flexible enough, you can also just implement the Interpolator interface and create a new instance from it afterwards. The interface is very narrow and it only provides a single method called getInterpolation with the following signature.
public abstract float getInterpolation (float input)
Code vs. XML
Another last option is to move all the animation configuration into XML instead of baking these details directly into the binary distribution of the code. However, each of the given options will require a different setup to be manageable through XML, if possible.
Hope this helps, but it is only pseudo code. I didn't test the code... so no warranties for correctness.
There are 4 types of animations in android - rotate, alpha,scale and translate.
I want to prepare curved translate animation.
Is it possible.?
What Android version do you use? Since API level 11 you can use custom Animators which can easily implement your curve translation.
If you use a version below that there is afaik only the possibility to manually concatenate multiple linear translations using the translate animation and setting animation listeners
EDIT:
Example:
View view;
animator = ValueAnimator.ofFloat(0, 1); // values from 0 to 1
animator.setDuration(5000); // 5 seconds duration from 0 to 1
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = ((Float) (animation.getAnimatedValue()))
.floatValue();
// Set translation of your view here. Position can be calculated
// out of value. This code should move the view in a half circle.
view.setTranslationX((float)(200.0 * Math.sin(value*Math.PI)));
view.setTranslationY((float)(200.0 * Math.cos(value*Math.PI)));
}
});
I hope it works. Just copied & pasted (and shortened and changed) the code from one of my apps.
Here are the animators I use:
Purpose: Move View "view" along Path "path"
Android v21+:
// Animates view changing x, y along path co-ordinates
ValueAnimator pathAnimator = ObjectAnimator.ofFloat(view, "x", "y", path)
Android v11+:
// Animates a float value from 0 to 1
ValueAnimator pathAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
// This listener onAnimationUpdate will be called during every step in the animation
// Gets called every millisecond in my observation
pathAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
float[] point = new float[2];
#Override
public void onAnimationUpdate(ValueAnimator animation) {
// Gets the animated float fraction
float val = animation.getAnimatedFraction();
// Gets the point at the fractional path length
PathMeasure pathMeasure = new PathMeasure(path, true);
pathMeasure.getPosTan(pathMeasure.getLength() * val, point, null);
// Sets view location to the above point
view.setX(point[0]);
view.setY(point[1]);
}
});
Similar to: Android, move bitmap along a path?
Consider the following web link. It is a game in C. You need to isolate the projectile() function and try to understand the variables defined within it. Once you get that try implementing it in your own code.
http://www.daniweb.com/software-development/c/code/216266