I have an image, which is a bee. I want to add an animation that make the bee look like it is randomly flying up and down within a specified area. The bee should only fly within paddingTop="200dp" to paddingTop="370dp". When it reaches the left of the screen, it should fly back to the right of the screen. And it should be non-stop moving from both sides. However, I can only make it fly or move horizontally with a specified time period.
<ImageView
android:id="#+id/bee"
android:paddingTop="200dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/beeFaceRight" />
The code in Main.java
ObjectAnimator animation;
ImageView bee;
protected void onCreate(Bundle savedInstanceState) {
bee = (ImageView) findViewById(R.id.bee);
animation = ObjectAnimator.ofFloat(bee, "translationX", 100f);
animation.setDuration(2000);
animation.start();
}
I have tried this, but it does not work.
ObjectAnimator objectX;
ObjectAnimator objectY;
AnimatorSet animatorXY;
objectX = ObjectAnimator.offFloat(bee, "translationX", 0);
objectY = ObjectAnimator.offFloat(bee, "translationY", 200);
animatorXY.playTogether(objectX, objectY);
animatorXY.setDuration(500);
animatorXY.start();
Related
I want to get the position of my ImageView programmatically. That position is for imageView in pixels relative to screen NOT to parent. actually I found some solutions when searching they working While the Layout Direction is left-to-right, but when I change direction to right-to-left it gives me strange values( is this isseu).
How can i get the position when the activity is rtl supporting.
some solution I have found:
1) private int getRelativeTop(View myView) {
if (myView.getParent() == myView.getRootView())
return myView.getTop();
else
return myView.getTop() + getRelativeTop((View) myView.getParent());}
2) image.getLocationOnScreen(int[] locaiton);
UPDATE
In my activity i have three imageviews , i move (translte animation) image3 from image1 to image2 . start moving from position image1 to position image2, when i use ltr it is animate correctlly but when i change supportrtl="true" i do not see the animation at all.
this is xml file
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="#+id/rootParent"
android:orientation="vertical"
android:layout_height="match_parent">
<ImageView
android:id="#+id/piece_FLOAT"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="#drawable/piece1"
android:translationZ="#dimen/activity_horizontal_margin" />
<ImageView
android:id="#+id/piece_1"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="8dp"
android:src="#drawable/piece1" />
<ImageView
android:id="#+id/piece_2"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="8dp"
android:src="#drawable/piece1" />
</LinearLayout>
this is java class
public class AnimateActivity extends AppCompatActivity {
ImageView imageViewfrom, imageViewto;
ImageView imageViewFLOAT;
LinearLayout L_33;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_animate);
imageViewfrom = (ImageView)findViewById(R.id.piece_1);
imageViewto = (ImageView)findViewById(R.id.piece_2);
imageViewFLOAT = (ImageView)findViewById(R.id.piece_FLOAT);
assert imageViewfrom != null;
assert imageViewto != null;
imageViewfrom.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int[] ToLocation = new int[2];
imageViewto.getLocationOnScreen(ToLocation);
float xTO = ToLocation[0];//imageViewto.getX(); //ToLocation[0];
float yTO = ToLocation[1];//imageViewto.getY();//ToLocation[1];
int[] FromLocation = new int[2];
imageViewfrom.getLocationOnScreen(FromLocation);
float xFROM = FromLocation[0];//imageViewfrom.getX();///FromLocation[0];
float yFROM = FromLocation[1]; //imageViewfrom.getY();//FromLocation[1];
Log.e("xFrom =" + xFROM, "xTo =" + xTO );
Log.e("yFrom =" + yFROM, "yTo =" + yTO );
// Log.e("offset =" + topOffset, "xTo =" + 0);
ValueAnimator animatorX = ObjectAnimator.ofFloat(imageViewFLOAT, "x", xFROM, xTO).setDuration(1500);
ValueAnimator animatorY = ObjectAnimator.ofFloat(imageViewFLOAT, "y", yFROM, yTO).setDuration(1500);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(animatorX, animatorY);
animatorSet.start();
// Animation an = new TranslateAnimation(xFROM, xTO, yFROM , yTO);
// an.setDuration(1500);
// an.setFillAfter(true);// to keep the state after animation is finished
// imageViewFLOAT.startAnimation(an);// to start animation obviously
}
});
}
}
when I use ltr it work very will but add some pixels. when I use rtl the animation did not seen. why this happen?
thanks for any help .
The issue here isn't really in finding the View's location, as that shouldn't be affected by the layout direction. The real problem is that View animations - especially those involving translations - apparently don't work well with RTL layouts. This is not surprising, since View animations have been around since the first versions of Android, but RTL support was only added in API level 17.
The solution is to use Property Animations instead.
For example, in your snippet, you're actually only translating that ImageView along the x-axis, so we can replace your entire TranslateAnimation setup with one line:
ObjectAnimator.ofFloat(imageViewFLOAT, "x", xFROM, xTO).setDuration(1500).start();
This creates an ObjectAnimator that modifies imageViewFLOAT's x-coordinate - by calling its setX() method - in the range [xFROM...xTO] over a duration of 1500 milliseconds, and immediately starts it.
Using an AnimatorSet, we can combine multiple animations to play together, so you can simultaneously perform a y-translation, as well. For example:
AnimatorSet as = new AnimatorSet();
as.playTogether(ObjectAnimator.ofFloat(imageViewFLOAT, "x", xFROM, xTO),
ObjectAnimator.ofFloat(imageViewFLOAT, "y", yFROM, yTO));
as.setDuration(1500).start();
Property animations and their classes are rather straightforward, and can do pretty much anything that the old View animations could. Updating your code to use these should be a simple fix for your RTL animation issues.
I have an image for my layout background. I want it to start moving to the right, and every frame that disappears from the right, should reappear on the left. Therefore, the image will keep moving continously with only one frame of the photo. How can I do that?
The easiest and fastest way to do so, it's to having two ImageViews in a ViewGroup and animate them with two differents animations. By getting the container's width, the first will move from its position (START) to the right edge (PARENT_WIDTH), and the second will follow from outside the container (-PARENT_WIDTH) to inside (START). Finally, make the animations repeat INFINITE will do the illusion of a real loop.
private ViewGroup parent;
private ImageView imgInner, imgOutter;
#Override
public void onCreate(...) {
...
parent = (ViewGroup) findViewById(R.id.parent_loop);
imgInner = (ImageView) findViewById(R.id.image_loop_inner);
imgOutter = (ImageView) findViewById(R.id.image_loop_outter);
...
setImageLoop();
}
private void setImageLoop() {
// Need a thread to get the real size or the parent
// container, after the UI is displayed
imgInner.post(new Runnable() {
#Override
public void run() {
TranslateAnimation outAnim =
new TranslateAnimation(
0f, parent.getWidth(), 0f, 0f);
// move from 0 (START) to width (PARENT_SIZE)
outAnim.setInterpolator(new LinearInterpolator());
outAnim.setRepeatMode(Animation.INFINITE); // repeat the animation
outAnim.setRepeatCount(Animation.INFINITE);
outAnim.setDuration(2000);
TranslateAnimation inAnim =
new TranslateAnimation(
- parent.getWidth(), 0f, 0f, 0f);
// move from out width (-PARENT_SIZE) to 0 (START)
inAnim.setInterpolator(new LinearInterpolator());
inAnim.setRepeatMode(Animation.INFINITE);
inAnim.setRepeatCount(Animation.INFINITE);
inAnim.setDuration(2000); // same duration as the first
imgInner.startAnimation(outAnim); // start first anim
imgOutter.startAnimation(inAnim); // start second anim
}
});
}
The container ViewGroup has match_parent on its width, but it could be changed, and therefore the START attribute will be replaced by something like parent.getLeft(). This layout could be a LinearLayout, a RelativeLayout, or whatever. For example, I used this:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="250dp"
...>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
.../>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
.../>
</FrameLayout>
Which gives my this output (keep in mind the gif makes it look choppy when it is really not):
Updated the code:
img = (ImageView) findViewById(R.id.imageView1);
TranslateAnimation animation = new TranslateAnimation(-95.0f, 740.0f,
0.0f, 0.0f); // new TranslateAnimation(xFrom,xTo, yFrom,yTo)
animation.setDuration(5000); // animation duration
animation.setRepeatCount(5); // animation repeat count
img.startAnimation(animation); // start animation
I have a progress bar view like this:
<ProgressBar
android:id="#+id/progress_bar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="100"/>
It lasts 3 second, so how to use interpolator to make update smoothly?
ObjectAnimator animation = ObjectAnimator.ofInt(what_is_in_here?);
animation.setDuration(3000); // second
animation.setInterpolator(new DecelerateInterpolator());
animation.start();
I really appreciate your help. Thank you very much in advance.
I found out the solution:
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
ObjectAnimator animation = ObjectAnimator.ofInt(progressBar, "progress", 100, 0);
animation.setDuration(3500); // 3.5 second
animation.setInterpolator(new DecelerateInterpolator());
animation.start();
Here is a detailed explanation:
create an animation object:
ObjectAnimator animation = ObjectAnimator.ofInt(progressBar, "progress", 100, 0);
progressBar: reference to the ProgressBar in the layout;
"progress": the name of the property to be animated;
100: starting point of the animation;
0: ending point of the animation.
and set an interpolation:
animation.setInterpolator(new DecelerateInterpolator());
It is possible to use different interpolators for our animation, like for example:
LinearInterpolator: where the rate of change is constant.
DecelerateInterpolator: where the rate of change starts out quickly and and then decelerates.
AccelerateInterpolator: where the rate of change starts out slowly and and then accelerates.
OvershootInterpolator: where the change flings forward and overshoots the last value then comes back.
For other interpolators check the interface android.view.animation.Interpolator.
I expect the button move down 200px (from 0,0 to 0, 200)
and after 1 second, move up again to original position.
But following code acts like start from (0,200) to (0,400), not start from (0,0)
If I put one animation into AnimationSet, it works fine. But it works strange if I put more than two animations in the AnimationSet.
What's the problem?
public class MainActivity extends Activity {
private static final int DISTANCE = 200;
private static final long DURATION = 1000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.button1);
TranslateAnimation aniMove = new TranslateAnimation(0, 0, 0, DISTANCE);
aniMove.setDuration(DURATION);
TranslateAnimation aniMoveBack = new TranslateAnimation(0, 0, DISTANCE, 0);
aniMoveBack.setDuration(DURATION);
aniMoveBack.setStartOffset(DURATION + 1000);
AnimationSet aniSet = new AnimationSet(true);
aniSet.addAnimation(aniMove);
aniSet.addAnimation(aniMoveBack);
btn.startAnimation(aniSet);
}
}
Here is XML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="0dp" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
AnimationSet represents a group of Animations that should be played together. The
transformation of each individual animation are composed together into
a single transform.
AnimationSet could not be used in this way, it could combine the feature of multi animations. Using AnimationSet you can perform alpha and rotate animation at the same time.
If you want to play 2 animations in order, you should start the second animation in onAnimationEnd() of the first animation.
I found the solution.
Coordinates in TranslateAnimation() parameter is not absolute one.
Because I called setStartOffset(N), aniMoveBack animation will start from the end of aniMove coordinate.
It is relative position.
So, the code should be fixed like this..
TranslateAnimation aniMoveBack = new TranslateAnimation(0, 0, 0, -DISTANCE);
I have the following View setup in one of my Activities:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/photoLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="#+id/photoImageView"
android:src="#drawable/backyardPhoto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:scaleType="centerInside"
android:padding="45dip"
>
</ImageView>
</LinearLayout>
Without an animation set, this displays just fine. However I want to display a very simple animation. So in my Activity's onStart override, I have the following:
#Override
public void onStart() {
super.onStart();
mPhotoImageView = (ImageView) findViewById(R.id.photoImageView);
float offset = -25;
int top = mPhotoImageView.getTop();
TranslateAnimation anim1 = new TranslateAnimation(
Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0,
Animation.ABSOLUTE, top, Animation.ABSOLUTE, offset);
anim1.setInterpolator(new AnticipateInterpolator());
anim1.setDuration(1500);
anim1.setStartOffset(5000);
TranslateAnimation anim2 = new TranslateAnimation(
Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0,
Animation.ABSOLUTE, offset, Animation.ABSOLUTE, top);
anim2.setInterpolator(new BounceInterpolator());
anim2.setDuration(3500);
anim2.setStartOffset(6500);
mBouncingAnimation = new AnimationSet(false);
mBouncingAnimation.addAnimation(anim1);
mBouncingAnimation.addAnimation(anim2);
mPhotoImageView.setAnimation(mBouncingAnimation);
}
The problem is that when the Activity displays for the first time, the initial position of the photo is not in the center of the screen with padding around. It seems like the first frame of the animation is loaded already. Only after the animation is completed, does the photoImageView "snap" back to the intended location.
I've looked and looked and could not find how to avoid this problem. I want the photoImageView to start in the center of the screen, and then the animation to happen, and return it to the center of the screen. The animation should happen by itself without interaction from the user.
mPhotoImageView.getTop() will return 0 in onCreate(), you need to wait until after the first layout/draw has happened to get the correct position of your View.