Layout children frozen after animation - android

I am animating a ConstraintLayout off screen, then back into screen. However, after animating the ConstraintLayout back into view the child elements (EditTexts and Button) are frozen.
I believe it is because the layout is just showing an image of itself, with the actual elements behind. How can I get the layout to 'redraw'?
Here is an example of the issue:
Here is my code:
slide_out_left.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
<translate android:duration="200" android:fromXDelta="0%" android:toXDelta="-100%"/>
</set>
slide_in_left.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
<translate android:duration="200" android:fromXDelta="-100%" android:toXDelta="0%"/>
</set>
View code:
public void slideCreateFormOutToLeft() {
Animation slideOutLeft = AnimationUtils.loadAnimation(getActivityContext(), R.anim.slide_out_left);
slideOutLeft.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
createTaskViewFormContainer.setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
createTaskViewFormContainer.startAnimation(slideOutLeft);
}
public void slideCreateFormInFromLeft() {
createTaskViewFormContainer.setVisibility(View.VISIBLE);
Animation slideInLeft = AnimationUtils.loadAnimation(getActivityContext(), R.anim.slide_in_left);
slideInLeft.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
createTaskViewFormContainer.startAnimation(slideInLeft);
}

From this Android documentation
Another disadvantage of the view animation system is that it only
modified where the View was drawn, and not the actual View itself. For
instance, if you animated a button to move across the screen, the
button draws correctly, but the actual location where you can click
the button does not change, so you have to implement your own logic to
handle this.
So the Buttons and EditTexts inside the createTaskViewFormContainer is not in the vicinity of your click area. This is a problem with ViewAnimation and it is recommended to use PropertyAnimation instead, like this:
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenWidth = displayMetrics.widthPixels;
createTaskViewFormContainer.animate().translationX(-screenWidth).start();
To bring the view back:
createTaskViewFormContainer.animate().translationX(0).start();

Related

get Y position percentage programmatically

I'm doing some translate animations with a view. I'm trying both ways: By xml and programmatically.
This is how I have defined the translation by xml:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="0%" android:toYDelta="-70%" android:duration="1000"/>
</set>
This way it works fine, but I've realized that I better need the programmatically way as using the animationListener I can define actions to occurr when the animation finishes.
This is how I do it programmatically:
slide_up = new TranslateAnimation(valuesContainer.getX(),
valuesContainer.getX(),
valuesContainer.getY(),
valuesContainer.getY() - 70);
slide_up.setDuration(1000);
slide_up.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
//SOMETHING HAPPENS
}
});
The problem comes when defining the fromYDelta and toYDelta values (the image just moves in the Y axis). In the xml, I do it using percentages (%) and it works the way I need, but I don't know how to set the values this same way but programmatically.
I have come to a solution combining both of this methods.
I define the animation in a xml like this, called f.e. slide_up_anim.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="0%" android:toYDelta="-70%" android:duration="1000"/>
</set>
And then, I set the AnimationListener for this animation this way:
slide_up = AnimationUtils.loadAnimation(getActivity(), R.anim.slide_up_anim);
slide_up.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
});
This way I can define the fromYDelta and toYDelta in percentage, and also listen for animation events.

setVisibility(View.GONE) doesn't disappear a view

In my activity, I have a start button, and when that's clicked it should fade out and finally disappear by setVisibility(View.GONE)
The problem is setting visibility to GONE doesn't disappear the view, it's still visible. I've purposefully made the view animation fade out to 0.1 (instead of 0) and I can see it in the background even after I've called setVisibility(View.GONE) on it.
The fadeout animation anim_fade_out.xml is:
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:fillAfter="true" android:fillEnabled="true">
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.1"
android:duration="200" />
</set>
The method is showTimer():
private void showTimer() {
final LinearLayout startButtonArea = (LinearLayout)findViewById(R.id.startButtonArea);
Animation animFadeOut = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_fade_out);
startButtonArea.startAnimation(animFadeOut);
animFadeOut.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
startButtonArea.setVisibility(View.GONE);
Log.d("Animation ended","startButtonArea SHOULD BE GONE BUT IT ISN'T");
}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationStart(Animation animation) {}
});
}
To reiterate, I know that the end alpha of the animation is 0.1 (it would be 0 usually) but I want to confirm that the view is really GONE and it isn't.
Because your fillAfter is true, the animation sets the properties after your onAnimationEnd is called. You can either change fillAfter to false, or do it like this:
#Override
public void onAnimationEnd(Animation animation) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startButtonArea.setVisibility(View.GONE);
Log.d("Animation ended","startButtonArea SHOULD BE GONE BUT IT ISN'T");
}
}, 0);
}

perform Fade_out animation android

I want to perform a fade out animation whenever a keyboard click matches with the image that is on the view.
Here is my code for the matching click:
Animation animation = AnimationUtils.loadAnimation(this, R.anim.fadeout);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
imageView.setAlpha(255);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
imageView.setVisibility(ImageView.GONE);
}
});
if(counterOfindex==random.length){
startAnimation();
}else{
startAnimation();
Log.e("removed_id=:", ""+viewId);
}
I want to slowly fade out the image once the right key letter on the keyboard has been clicked.
Here is my XML:
<?xml version="1.0" encoding="UTF-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/decelerate_interpolator">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:duration="4000"/>
</set>
Problem: Nothing is happening. The code runs just as it was running previously.

View.getX/Y and View.setX/Y below Android 3.0

I am working on a project that must work on Android 2.2 onwards, and I just realized I was using a 3.0+ method from View.
I have a menu that animates vertically sliding in/out when a button is pressed. When the animation finishes I update the View position with setY() method.
I tried to change it to getTop/setTop but it's not working properly, I suspect because getY is actually taking into account transformations and getTop is not (I guess animations are handled as transformations).
Any easy alternative for Froyo without modifying too much code?
This is the animation part:
animationSlideInDown = AnimationUtils.loadAnimation(this, R.anim.slide_out_down);
animationSlideOutUp = AnimationUtils.loadAnimation(this, R.anim.slide_in_up);
animationSlideInDown.setDuration(200);
animationSlideOutUp.setDuration(200);
animationSlideInDown.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
if (menuInitialPosition == -1) {
menuInitialPosition = menu.getY();
menuHeight = menu.getHeight();
} else {
menu.setY(menuInitialPosition);
}
}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
menu.setY(menuInitialPosition);
}
});
animationSlideOutUp.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
menu.setY(-menuHeight);
}
});
This is the slide_out transition:
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromYDelta="-100%"
android:toYDelta="0"
android:fillAfter="true"
android:fillEnabled="true"
android:duration="#android:integer/config_longAnimTime" />
Thanks!
If you want to get position of particular view on the screen than you can use :
int[] locationOnScreen = new int[2];
menu.getLocationOnScreen(locationOnScreen);
And for setting view to particular position you can use LayoutParams and set left and top margin for the view.

Creating animation on ImageView while changing image resource

I have only one ImageView in my layout and I am changing its resource when a gasture event detected. I just want to show an animation while changing resource of ImageView. Can I use ViewFlipper with one ImageView?
For a single imageview you can use this helper function:
public static void ImageViewAnimatedChange(Context c, final ImageView v, final Bitmap new_image) {
final Animation anim_out = AnimationUtils.loadAnimation(c, android.R.anim.fade_out);
final Animation anim_in = AnimationUtils.loadAnimation(c, android.R.anim.fade_in);
anim_out.setAnimationListener(new AnimationListener()
{
#Override public void onAnimationStart(Animation animation) {}
#Override public void onAnimationRepeat(Animation animation) {}
#Override public void onAnimationEnd(Animation animation)
{
v.setImageBitmap(new_image);
anim_in.setAnimationListener(new AnimationListener() {
#Override public void onAnimationStart(Animation animation) {}
#Override public void onAnimationRepeat(Animation animation) {}
#Override public void onAnimationEnd(Animation animation) {}
});
v.startAnimation(anim_in);
}
});
v.startAnimation(anim_out);
}
Here's an example using ImageSwitcher like #Konstantin Burov suggested:
Add this ImageSwitcher element to your xml layout:
<ImageSwitcher
android:id="#+id/slide_trans_imageswitcher"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ImageSwitcher>
Create in and out animations in res/anim/:
Out animation:
//left_to_right_out.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700"/>
</set>
And in animation:
//left_to_right_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700"/>
</set>
Initialize them in your code:
Animation in = AnimationUtils.loadAnimation(this, R.anim.left_to_right_in);
Animation out = AnimationUtils.loadAnimation(this, R.anim.left_to_right_out);
Initialize your ImageSwitcher:
private ImageSwitcher imageSwitcher;
imageSwitcher = (ImageSwitcher)findViewById(R.id.slide_trans_imageswitcher);
Attach the animations to it:
imageSwitcher.setInAnimation(in);
imageSwitcher.setOutAnimation(out);
Now everytime you set an image resource for imageSwitcher, it will switch in a slide animation.
For example we can change the image every X seconds:
private int animationCounter = 1;
private Handler imageSwitcherHandler;
imageSwitcherHandler = new Handler(Looper.getMainLooper());
imageSwitcherHandler.post(new Runnable() {
#Override
public void run() {
switch (animationCounter++) {
case 1:
imageSwitcher.setImageResource(R.drawable.image1);
break;
case 2:
imageSwitcher.setImageResource(R.drawable.image2);
break;
case 3:
imageSwitcher.setImageResource(R.drawable.image3);
break;
}
animationCounter %= 4;
if(animationCounter == 0 ) animationCounter = 1;
imageSwitcherHandler.postDelayed(this, 3000);
}
});
I found another way to animate it using transition drawable(I took idea from here)
public static void setImageDrawableWithAnimation(ImageView imageView,
Drawable drawable,
int duration) {
Drawable currentDrawable = imageView.getDrawable();
if (currentDrawable == null) {
imageView.setImageDrawable(drawable);
return;
}
TransitionDrawable transitionDrawable = new TransitionDrawable(new Drawable[] {
currentDrawable,
drawable
});
imageView.setImageDrawable(transitionDrawable);
transitionDrawable.startTransition(duration);
}
Analogous kotlin extension function:
fun ImageView.setImageDrawableWithAnimation(drawable: Drawable, duration: Int = 300) {
val currentDrawable = getDrawable()
if (currentDrawable == null) {
setImageDrawable(drawable)
return
}
val transitionDrawable = TransitionDrawable(arrayOf(
currentDrawable,
drawable
))
setImageDrawable(transitionDrawable)
transitionDrawable.startTransition(duration)
}
If your drawables contains transparent parts, this flag could be useful to prevent old drawable visibility:
transitionDrawable.setCrossFadeEnabled(true);
Consider using Rotate3dAnimation available in the API demo app.
View > Animation > 3D transition
You can also check this question on SO

Categories

Resources