Correctly animating an Android ImageView (possibly using a Matrix) - android

So, I have a Layout that contains a Button and an ImageView. When you press the button the ImageView should slide out from the button like I just pulled down a rolldown curtain (bushing other views below it down). Basically what the image below show. When you press the button again the ImageView should, unlike the gif, smoothly animates up again.
.
Using this SO question I've managed to animate the height from 0 to full size but in the wrong direction. I set the scaleType to "Matrix" and the default behaviour when setting the height is to show the part from the top down to [height].
For the animation I'll need the opposite. So if I would set the height to 50dp it would show the bottom 50dp. Then I can move the ImageView down at the same time it's being revealed, thus giving the rolldown curtain effect.
I've looked throught all the different layout and view options and found nothing that seems to do this. So I'm guessing I need to specify the transformation matrix. I looked through the android.graphics.Matrix class but it's a little but too complicated for me. I simply have no idea how to use it.
If there is another, easier, way to do this then that would be fantastic but if not then I really need help with the matrix.
I'm also including the code here:
The Rolldown View XML
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/sliding_accordion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="#drawable/acc_image"
android:contentDescription="#string/accord"
android:scaleType="matrix"
android:layout_below="#+id/acc_button"
android:layout_marginTop="-10dp"
android:layout_centerHorizontal="true"/>
<Button
android:id="#+id/acc_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
The implementation in code.
(Note, the MyCustomAnimation class is a copy-paste version of the class found here)
//Called from all constructors
private void create()
{
final Context context = getContext();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.widget_accordion, this, false);
final Button theButton = (Button) layout.findViewById(R.id.topic_button);
final ImageView accordionView = (ImageView) layout.findViewById(R.id.sliding_accordion);
accordionView.setVisibility(INVISIBLE);
theButton.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
if (accordionView.getVisibility() == View.VISIBLE)
{
MyCustomAnimation a = new MyCustomAnimation(accordionView, 1000, MyCustomAnimation.COLLAPSE);
height = a.getHeight();
accordionView.startAnimation(a);
}
else
{
MyCustomAnimation a = new MyCustomAnimation(accordionView, 1000, MyCustomAnimation.EXPAND);
a.setHeight(height);
accordionView.startAnimation(a);
}
}
});
this.addView(layout);
}

This took a long time perfect. But I managed to do it after a lot of experimenting.
I animate the margins of the drawer but because of the unexpected behavior of negative margins the button that opens the drawer can not be positioned on top.
When the drawer is closed the XML looks like so:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/accordion"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.animationtest.drawer.Drawer
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/topic_drawer"
android:layout_centerHorizontal="true"
android:layout_marginTop="0dp"
android:visibility="invisible"/>
<com.animationtest.drawer.Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/topic_btn"
android:layout_marginTop="58dp"/>
</RelativeLayout>
Then when the button is pressed the top_margin of the drawer is increased until it has come to whatever position is needed (in this case drawerHeight - someOffset).
I used android.view.animation.Animation to animate the widget my applyTransformation function looks something like this (Note that mLayoutParams are the drawer params):
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int valueDifference = Math.abs(startValue - endValue);
float valueChange = interpolatedTime * valueDifference;
if(currentState.equals(State.COLLAPSED)) {
// is closed and I want to open it
mLayoutParams.topMargin = Math.round(interpolatedTime * valueDifference);
}
else {
// is opened and I want to close it
mLayoutParams.topMargin = valueDifference - Math.round(interpolatedTime * valueDifference);
}
drawerView.requestLayout(); //this is my drawer
}
Finally, to hide the top of the drawer as it moves, I overrode my DrawerView's dispatchDraw method to looks like so:
#Override
protected void dispatchDraw(Canvas canvas) {
float height = getHeight();
float top = height - ((LayoutParams) getLayoutParams()).topMargin;
Path path = new Path();
RectF rectF = new RectF(0.0f, top, getWidth(), height);
path.addRoundRect(rectF, 0.0f, 0.0f, Path.Direction.CW);
canvas.clipPath(path);
super.dispatchDraw(canvas);
}
One final note:
Because of the Button's position one would need to set the widgets margin as a negative number for it to align correctly in a list or layout. In this case it would have to be -58dp.

Related

Why setPivotX() just replace views?

In code - after first part of animation pivot of view is changing and...view position too!(it is strange behavior)
Here's code(stipulation - one ValueAnimator):
ValueAnimator animator = ValueAnimator.ofFloat(0,180);
float firstAnimLineX = ((47.5f * Resources.getSystem().getDisplayMetrics().density));
float firstAnimLineY = ((2.5f * Resources.getSystem().getDisplayMetrics().density));
float secondAnimLineX = ((47.5f * Resources.getSystem().getDisplayMetrics().density));
float secondAnimLineY = ((47.5f * Resources.getSystem().getDisplayMetrics().density));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
view.setPivotX((Float) animator.getAnimatedValue()>180/2?firstAnimLineX : secondAnimLineX);
view.setPivotY((Float) animator.getAnimatedValue()>180/2?firstAnimLineY : secondAnimLineY);
view.setRotation((Float) animator.getAnimatedValue());
}
});
XML file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/frameLayout">
<ImageView
android:layout_width="50dp"
android:layout_height="5dp"
android:layout_gravity="center_horizontal"
android:id="#+id/line"
/>
</FrameLayout>
</RelativeLayout>
And here is what i want to do(left part; right part - it's what realy happens)(yellow point - pivot):
I watched source code of setPivotX but it doesn't says me anything.
Maybe i should call someone of invalidate-methods of view?
I recreated this code and ran it on my Android phone. It gives the exact animation you are looking for.
I created an Image to match your 'match-stick' image.
I made it 400 px wide by 40 high for an example.
I gave it the id: 'bar'
ImageView bar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bar = findViewById(R.id.bar);
bar.getLayoutParams().width = 400; // I set the dimensions here.
bar.getLayoutParams().height = 40; // I set the dimensions here.
bar.setX(0); bar.setY(0); // Then I positioned it in upper left corner.
bar.setPivotX(380); // I set the pivot a little inside the image so that it looks kinda like it is pivoting on a nail.
bar.setPivotY(20);
bar.animate().rotation(-90).setDuration(2000); // Here it animates from your first image above, to your second image in 2 seconds.
// Here I used a postDelay to allow the first animation to finish its' 2 seconds 'before' calling the second animation. No need for an animate() - listener now.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
bar.setY(360); // This re-positions the original image to the
// location where the animation ended.
bar.setRotation(90); // Because the original image was horizontal, this turns it vertical.
// Now we finish the animation to your 3rd image above.
bar.animate().rotation(0).setDuration(2000);
}
},2100);
}

Android: LinearLayout slide off screen animation

I have two layouts (green on top, red on bottom) in a vertical LinearLayout (parent) looking similar to this:
.
When focus goes from the green to red, I would like the green to slide up off the screen and have the red simultaneously slide up with it and fill the whole screen. And when focus moves from red back up I want the green to slide back into the screen and return to the original configuration. I have tried looking at many other questions but none have had the solution I need. I tried just changing visibility between gone and visible but I want it to be a smooth animation. I've tried using parentLayout.animate().translationY(greenLayout.getHeight()) on the outer LinearLayout and that does give the animation I want but then the red does not expand to fill the screen, like this:
.
I know this question is similar to this one but that question is really old and only had one answer which didn't work for me.
My solution has a lot of different pieces, so I'll start with the full XML and java code, and then talk about the important bits:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:id="#+id/green"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#0f0" />
<View
android:id="#+id/red"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#f00"/>
</LinearLayout>
In the XML, the only really important part is that the red view uses a height of 0dp and weight of 1. This means it takes up all extra vertical space, which will be important when we get rid of the green view.
public class MainActivity extends AppCompatActivity {
private int originalHeight;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final View green = findViewById(R.id.green);
final View red = findViewById(R.id.red);
green.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
green.getViewTreeObserver().removeGlobalOnLayoutListener(this);
originalHeight = green.getHeight();
}
});
green.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
animateHeightOfView(green, originalHeight, 0);
}
});
red.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
animateHeightOfView(green, 0, originalHeight);
}
});
}
private void animateHeightOfView(final View view, int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int height = (int) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams params = view.getLayoutParams();
params.height = height;
view.setLayoutParams(params);
}
});
animator.start();
}
}
In the Java, the two main parts are the ViewTreeObserver.OnGlobalLayoutListener and the animateHeightOfView() method.
The OnGlobalLayoutListener exists to capture the green view's original height. We have to use a listener to do this instead of just writing originalHeight = green.getHeight() inside onCreate() because the green view isn't actually laid out at that point, so getHeight() would return 0 if we tried that.
The animateHeightOfView() method leverages the ValueAnimator class to animate the height of whatever view you pass to it. Since there's no direct setter for a view's height, we can't use simpler methods like .animate(). We set up the ValueAnimator to produce int values on every frame, and then we use a ValueAnimator.AnimatorUpdateListener to modify the view's LayoutParams to set the height.
Feel free to play with it. I'm using click listeners to trigger the animation, and you mentioned focus, but you should be able to call animateHeightOfView() in a different way if it suits you.

How can I get ImageView position with support Right To Left direction

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.

How does one Animate Layout properties of ViewGroups?

I have the following layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
<FrameLayout android:id="#+id/viewgroup_left"
android:layout_height="match_parent"
android:layout_weight="2"
android:layout_width="0dp">
... children ...
</FrameLayout>
<LinearLayout android:id="#+id/viewgroup_right"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_width="0dp"
android:orientation="vertical">
... children ...
</LinearLayout>
</LinearLayout>
I end up with something like this:
+------------------------+------------+
| | |
| | |
| Left | Right |
| | |
| | |
+------------------------+------------+
When a certain toggle is toggled, I want to animate Left so that its width expands to fill the entire screen. At the same time, I would like to animate the width of Right so that it shrinks to zero. Later, when the toggle is toggled again, I need to restore things to the above state.
I've tried writing my own Animation that calls View.getWidth() but when I animate back to that value (by setting View.getLayoutParams().width) it is wider than when it began. I suspect I'm just doing it wrong. I have also read all the documentation on the Honeycomb animation stuff, but I don't want to translate or scale... I want to animate the layout width property. I can't find an example of this.
What is the correct way to do this?
Since noone helped you yet and my first answer was such a mess I'll try to give you the right answer this time ;-)
Actually I like the idea and I think this is a great visual effect which might be useful for a bunch of people. I would implement an overflow of the right view (I think the shrink looks strange since the text is expanding to the bottom).
But anyway, here's the code which works perfectly fine (you can even toggle while it's animating).
Quick explanation:
You call toggle with a boolean for your direction and this will start a handler animation call loop. This will increase or decrease the weights of both views based on the direction and the past time (for a smooth calculation and animation). The animation call loop will invoke itself as long it hasn't reached the start or end position.
The layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="10"
android:id="#+id/slide_layout">
<TextView
android:layout_weight="7"
android:padding="10dip"
android:id="#+id/left"
android:layout_width="0dip"
android:layout_height="fill_parent"></TextView>
<TextView
android:layout_weight="3"
android:padding="10dip"
android:id="#+id/right"
android:layout_width="0dip"
android:layout_height="fill_parent"></TextView>
</LinearLayout>
The activity:
public class TestActivity extends Activity {
private static final int ANIMATION_DURATION = 1000;
private View mSlidingLayout;
private View mLeftView;
private View mRightView;
private boolean mAnimating = false;
private boolean mLeftExpand = true;
private float mLeftStartWeight;
private float mLayoutWeightSum;
private Handler mAnimationHandler = new Handler();
private long mAnimationTime;
private Runnable mAnimationStep = new Runnable() {
#Override
public void run() {
long currentTime = System.currentTimeMillis();
float animationStep = (currentTime - mAnimationTime) * 1f / ANIMATION_DURATION;
float weightOffset = animationStep * (mLayoutWeightSum - mLeftStartWeight);
LinearLayout.LayoutParams leftParams = (LinearLayout.LayoutParams)
mLeftView.getLayoutParams();
LinearLayout.LayoutParams rightParams = (LinearLayout.LayoutParams)
mRightView.getLayoutParams();
leftParams.weight += mLeftExpand ? weightOffset : -weightOffset;
rightParams.weight += mLeftExpand ? -weightOffset : weightOffset;
if (leftParams.weight >= mLayoutWeightSum) {
mAnimating = false;
leftParams.weight = mLayoutWeightSum;
rightParams.weight = 0;
} else if (leftParams.weight <= mLeftStartWeight) {
mAnimating = false;
leftParams.weight = mLeftStartWeight;
rightParams.weight = mLayoutWeightSum - mLeftStartWeight;
}
mSlidingLayout.requestLayout();
mAnimationTime = currentTime;
if (mAnimating) {
mAnimationHandler.postDelayed(mAnimationStep, 30);
}
}
};
private void toggleExpand(boolean expand) {
mLeftExpand = expand;
if (!mAnimating) {
mAnimating = true;
mAnimationTime = System.currentTimeMillis();
mAnimationHandler.postDelayed(mAnimationStep, 30);
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slide_test);
mLeftView = findViewById(R.id.left);
mRightView = findViewById(R.id.right);
mSlidingLayout = findViewById(R.id.slide_layout);
mLeftStartWeight = ((LinearLayout.LayoutParams)
mLeftView.getLayoutParams()).weight;
mLayoutWeightSum = ((LinearLayout) mSlidingLayout).getWeightSum();
}
}
Just adding my 2 cents here to Knickedi's excellent answer - just in case someone needs it:
If you animate using weights you will end up with issues with clipping/non-clipping on contained views and viewgroups. This is especially true if you use viewgroups with weight as fragment containers. To overcome it, you might as well need to animate margins of the problematic child views and viewgroups / fragment containers.
And, to do all these things together, its always better to go for ObjectAnimator and AnimatorSet (if you can use them), along with some utility classes like MarginProxy
A different way to the solution posted by #knickedi is to use ObjectAnimator instead of Runnable. The idea is to use ObjectAnimator to adjust the weight of both left and right views. The views, however, need to be customised so that the weight can be exposed as a property for the ObjectAnimator to animate.
So first, define a customised view (using a LinearLayout as an example):
public class CustomLinearLayout extends LinearLayout {
public CustomLinearLayout(Context context) {
super(context);
}
public CustomLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setMyWeight(float value) {
LinearLayout.LayoutParams p = (LinearLayout.LayoutParams)getLayoutParams();
p.weight = value;
requestLayout();
}
}
Then, update the layout XML to use this custom linear layout.
Then, when you need to toggle the animation, use ObjectAnimator:
ObjectAnimator rightView = ObjectAnimator.ofFloat(viewgroup_right, "MyWeight", 0.5f, 1.0f);
ObjectAnimator leftView = ObjectAnimator.ofFloat(viewgroup_left, "MyWeight", 0.5f, 0.0f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(1000); // 1 second of animation
animatorSet.playTogether(rightView, leftView);
animatorSet.start();
The above code assumes both views are linear layout and are half in weight to start with. The animation will expand the right view to full weight (so the left one is hidden). Note that ObjectAnimator is animated using the "MyWeight" property of the customised linear layout. The AnimatorSet is used to tie both left and right ObjectAnimators together, so the animation looks smooth.
This approach reduces the need to write runnable code and the weight calculation inside it, but it needs a customised class to be defined.

Android animate Translate in android 2.2

i have two image views which translates on click.
the animation works properly for one view but for second image view , my animation is not according to coordinates provided.
when i click top image view (img1) it animates properly toward bottom image view (img2) . But when i click the bottom image view, it animates from somewhere down and move towards image view 2 initial position only. though the expected behaviour is, it should animate from its position to top image view (img1) initial position.
My xml is
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/letter_f"
android:layout_alignParentTop="true"
android:id="#+id/imgview1"
android:background="#drawable/chart"/>
<ImageView android:layout_height="100dp"
android:layout_width="100dp"
android:id="#+id/imgview2"
android:src="#drawable/letter_g"
android:background="#drawable/chart"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
and my java class file is
public class AnimationDemo extends Activity implements OnClickListener
{
private ImageView img1;
private ImageView img2;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
img1 = (ImageView)findViewById(R.id.imgview1);
img2 = (ImageView)findViewById(R.id.imgview2);
img1.setOnClickListener(this);
img2.setOnClickListener(this);
}
#Override
public void onClick(View arg0)
{
int x1,y1; // Coordinates of first image view
int x2,y2; //Coordinates of second image view
ImageView img = (ImageView)arg0;
x1 = img1.getLeft();
y1 = img1.getTop();
x2 = img2.getLeft();
y2 = img2.getTop();
TranslateAnimation slide;
if(arg0 == img1)
{
//translate from img view 1 to img view 2
slide = new TranslateAnimation(Animation.ABSOLUTE,x1,Animation.ABSOLUTE, x2,Animation.ABSOLUTE, y1,Animation.ABSOLUTE,y2 );
}
else
{
// translate from img view 2 to img view 1
slide = new TranslateAnimation(Animation.ABSOLUTE,x2,Animation.ABSOLUTE, x1,Animation.ABSOLUTE, y2,Animation.ABSOLUTE,y1);
}
slide.setDuration(1000);
slide.setFillAfter(true);
img.startAnimation(slide);
}
}
Your troubles are due to your locations. I believe when animations are moved with absolute pixels it is relative to itself. So on your second animation you were in essence moving it from x2=220 to x1=0, and y2=419 to y1=0. So it was moving from (currentX+220, currentY+419) to (currentX +0, currentY +0) which = itself
To solve this instance simply negate and switch the values of the second slide declaration like so:
TranslateAnimation slide;
if(arg0 == img1)
{
//translate from img view 1 to img view 2
slide = new TranslateAnimation(Animation.ABSOLUTE,x1,Animation.ABSOLUTE, x2,Animation.ABSOLUTE, y1,Animation.ABSOLUTE,y2 );
}
else
{
// translate from img view 2 to img view 1
// slide = new TranslateAnimation(Animation.ABSOLUTE,x2,Animation.ABSOLUTE, x1,Animation.ABSOLUTE,y2,Animation.ABSOLUTE,y1);
slide = new TranslateAnimation(Animation.ABSOLUTE,0,Animation.ABSOLUTE, (-x2),Animation.ABSOLUTE,0,Animation.ABSOLUTE, (-y2));
}
This only happens because your top left sprite is at 0,0 though. You have to seriously rethink how you're moving your sprites around. Just remember, the TranslateAnimation moves them relative to their current positions, basically setting the sprites original location to (0,0).
Could be wrong, but hope it helps. It worked for me...
Sorry it took so long to get back to you, I lost your post and couldn't find it again for some reason. Glad you had commented earlier!

Categories

Resources