How to expand a layout height with animation? - android

I couldn't find a good example for how to do this.
I have a RelativeLayout set with x height.
I want to add a button which expands the height to x+y height.
can someone refer me to a good example on how to do it programmatically?

You marked the solution that was closest. This is the exact solution. I had the same problem. Hopefully this answer will help others.
InstantiateResizeAnimation
ResizeAnimation resizeAnimation = new ResizeAnimation(
view,
targetHeight,
startHeight
);
resizeAnimation.setDuration(duration);
view.startAnimation(resizeAnimation);
ResizeAnimation class should look like this
public class ResizeAnimation extends Animation {
final int targetHeight;
View view;
int startHeight;
public ResizeAnimation(View view, int targetHeight, int startHeight) {
this.view = view;
this.targetHeight = targetHeight;
this.startHeight = startHeight;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int newHeight = (int) (startHeight + targetHeight * interpolatedTime);
//to support decent animation, change new heigt as Nico S. recommended in comments
//int newHeight = (int) (startHeight+(targetHeight - startHeight) * interpolatedTime);
view.getLayoutParams().height = newHeight;
view.requestLayout();
}
#Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
#Override
public boolean willChangeBounds() {
return true;
}
}

You need a scale animation here is the official documentation
this is in code
private void animate() {
ImageView imageView = (ImageView) findViewById(R.id.ImageView01);
ScaleAnimation scale = new ScaleAnimation((float)1.0, (float)1.5, (float)1.0, (float)1.5);
scale.setFillAfter(true);
scale.setDuration(500);
imageView.startAnimation(scale);
}

Please check below new edited answer as below. But here you need to know the exact new height.
public class LayoutAnimationActivity extends Activity {
RelativeLayout ril1;
Button btn;
int initialHeight;
int actualHeight;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
ril1 = (RelativeLayout) findViewById(R.id.relativeLayout1);
btn = new Button(this);
btn.setWidth(100);
btn.setHeight(200);
btn.setText("Button");
actualHeight = 210;
Ani a = new Ani();
a.setDuration(2000);
ril1.startAnimation(a);
}
class Ani extends Animation {
public Ani() {}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int newHeight;
newHeight = (int) (initialHeight * interpolatedTime);
ril1.removeAllViews();
btn.setWidth(100);
btn.setHeight(300);
btn.setText("as");
ril1.addView(btn);
ril1.getLayoutParams().height = newHeight;
ril1.requestLayout();
}
#Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
initialHeight = actualHeight;
}
#Override
public boolean willChangeBounds() {
return true;
}
};
}

Two simple ways to do this without an Animation class:
1) Set android:animateLayoutChanges="true" in you xml layout file
2) Use a ViewProperty animator
layout.setPivot(0);
layout.animate().scaleY(scaleFactor).setDuration(500);
The pivot tells the view where to scale from, default is in the middle, which in my experience is almost never what you want. The duration is optional (default = 1000).

final Button button1 = (Button) view.findViewById(R.id.button);
final CollapseAnimator animator = new CollapseAnimator(topLayout);
final ViewTreeObserver.OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int mHeight = button1.getMeasuredHeight();
KLog.i("onGlobalLayout() mHeight:" + mHeight);
animator.setValues(mHeight*2, mHeight);
}
};
button1.getViewTreeObserver().addOnGlobalLayoutListener(listener);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
view.post(new Runnable() {
#Override
public void run() {
button1.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
animator.collapse();
}
});
}
});
and class
public class CollapseAnimator {
private View view;
private boolean collapse=true;
private int duation=300;
private int destHeight=300;
private ValueAnimator animator;
private int originHeight=0;
private int from=0;
private int to=0;
public CollapseAnimator(View view ) {
this.view = view;
}
public void setValues(int destHeight,int originHeight){
this.destHeight = destHeight;
this.originHeight=originHeight;
from=originHeight;
to=originHeight;
}
public void collapse(){
from=to;
if(collapse){
to=destHeight;
collapse=false;
}else{
to=originHeight;
collapse=true;
}
KLog.i("from:" + from+",to:"+to);
animator = ValueAnimator.ofInt(from, to);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.height = val;
view.setLayoutParams(layoutParams);
}
});
animator.setDuration(duation);
animator.start();
}
}

Related

more button between two recycler view

I have two recycler views in one screen and in between of them, there is one more button like this.
I want to update the height of recycler view of the upper one to MATCH PARENT with animation, So I had tried this.
binding.moreLl.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ValueAnimator anim = ValueAnimator.ofInt();
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = binding.fragmentWalletRv.getLayoutParams();
layoutParams.height = val;
binding.fragmentWalletRv.setLayoutParams(layoutParams);
}
});
anim.setDuration(500);
anim.start();
}
});
But unfortunately i cant get the expected result. So please guide me how i can do that thing.
Thanks in advance.
If you just want to have an animation when layout changes, no need to use a custom animation.
Try adding default layout change animation by enabling
android:animateLayoutChanges="true"
to the parent layout in xml.
On your more button click, only change the LayoutParams of the Recyclerview.
To change the speed of animation
LinearLayout layout = mContentView.findViewById(R.id.parent_layout);
LayoutTransition lt = layout.getLayoutTransition();
lt.setDuration(2000);
public class SlideAnimation extends Animation {
int mFromHeight;
int mToHeight;
View mView;
public SlideAnimation(View view, int fromHeight, int toHeight) {
this.mView = view;
this.mFromHeight = fromHeight;
this.mToHeight = toHeight;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation transformation) {
int newHeight;
if (mView.getHeight() != mToHeight) {
newHeight = (int) (mFromHeight + ((mToHeight - mFromHeight) * interpolatedTime));
mView.getLayoutParams().height = newHeight;
mView.requestLayout();
}
}
#Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
#Override
public boolean willChangeBounds() {
return true;
}
}
Use above animation like below
rv1 = findViewById(R.id.rv1);
Animation animation = new SlideAnimation(rv1, rv1.getHeight(), 500);
animation.setInterpolator(new AccelerateInterpolator());
animation.setDuration(500);
rv1.setAnimation(animation);
rv1.startAnimation(animation);

Move a view by translate animation Android

I am trying to move a view on the screen to a random point by clicking it, then have it stay there and move again by click, however, the view only does the correct movement when starting at 0,0 coordinates, once changed, it is animating from random position to random position and finishing on a third random position.
here is my snippet, can some one please run this and see if it works properly? and if not, what am i missing?
public class MainActivity extends ActionBarActivity {
ImageView image;
Rect rect;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
final int height = displaymetrics.heightPixels;
final int width = displaymetrics.widthPixels;
image = (ImageView) findViewById(R.id.image);
findViewById(R.id.image).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final int newLeft = ((int)Math.round(Math.random()*width))/2;
final int newTop = ((int)Math.round(Math.random()*height))/2;;
final int newRight = ((int)Math.round(Math.random()*width))/2;;
final int newBottom = ((int)Math.round(Math.random()*height))/2;;
rect = new Rect(newLeft, newTop, newRight, newBottom);
doSomeAnimation(rect);
}
});
}
public void doSomeAnimation(final Rect rect) {
final FrameLayout.LayoutParams imageParasms = (FrameLayout.LayoutParams) image.getLayoutParams();
TranslateAnimation animation = new TranslateAnimation(
imageParasms.leftMargin, rect.left, imageParasms.topMargin, rect.top);
animation.setDuration(1000);
animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
FrameLayout.LayoutParams imageParasms = (FrameLayout.LayoutParams) image.getLayoutParams();
imageParasms.width = rect.width();
imageParasms.height = rect.height();
imageParasms.leftMargin = rect.left;
imageParasms.topMargin = rect.top;
image.setLayoutParams(imageParasms);
image.requestLayout();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
image.startAnimation(animation);
}
It's better to use ValueAnimator, because TranslateAnimation uses matrix, and its very hard do deal with previous matrix values, I look source codes and understand that its better to use ValueAnimator, becauses have more control on how values are changing, I implemented it in different way, check this
public class MainActivity extends FragmentActivity {
ImageView image;
Random rnd = new Random();
int leftMargin;
int topMargin;
boolean xRunning;
boolean yRunning;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
final int height = displaymetrics.heightPixels;
final int width = displaymetrics.widthPixels;
image = (ImageView) findViewById(R.id.image);
findViewById(R.id.image).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int newLeft = rnd.nextInt(height);
int newTop = rnd.nextInt(width);
Point pt = new Point(newLeft, newTop);
doSomeAnimation(pt);
}
});
//This Handler is used for optimization, for setting a layout in one place, instead of calling
//it in every onAnimationUpdate method
image.post(new Runnable() {
#Override
public void run() {
if(xRunning && yRunning) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) image.getLayoutParams();
params.leftMargin = leftMargin;
params.topMargin = topMargin;
image.setLayoutParams(params);
}
image.postDelayed(this, 30);
}
});
}
public void doSomeAnimation(final Point pt) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) image.getLayoutParams();
ValueAnimator xAnim = ValueAnimator.ofFloat(pxFromDp(this, params.leftMargin), pt.x);
xAnim.setDuration(1000);
xAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
leftMargin = (int) dpFromPx(MainActivity.this, (float) animation.getAnimatedValue());
}
});
xAnim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
xRunning = false;
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
xAnim.start();
xRunning = true;
ValueAnimator yAnim = ValueAnimator.ofFloat(pxFromDp(this, params.topMargin), pt.y);
yAnim.setDuration(1000);
yAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
topMargin = (int) dpFromPx(MainActivity.this, (float) animation.getAnimatedValue());
}
});
yAnim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
yRunning = false;
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
yAnim.start();
yRunning = true;
}
public static float dpFromPx(final Context context, final float px) {
return px / context.getResources().getDisplayMetrics().density;
}
public static float pxFromDp(final Context context, final float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
}

animate a view from a particular point to fill whole screen and the re size it back to that point

I Know how to animate a view to whole screen and animate back to its original size. here is the link to do this Re sizing through animation
But the problem is that this technique works only when if my view is place at the start of the screen.
What i want is that if my view of height and width (50,50) is placed in center of screen below some button and i click that view it should animate to fill the whole screen and when clicked again it animates back to its original size (50,50)
If you're using LinearLayout, try to set AnimationListener for this animation and toggle the visibility of the button appropriately. Set button's visibility to View.GONE onAnimationStart when 'expanding' view and to View.VISIBLE onAnimationEnd when 'collapsing' it. Using RelativeLayout can be the solution for this problem too.
For animation:
public class ExpandCollapseViewAnimation extends Animation {
int targetWidth;
int targetHeight;
int initialWidth;
int initialHeight;
boolean expand;
View view;
public ExpandCollapseViewAnimation(View view, int targetWidth, int targetHeight ,boolean expand) {
this.view = view;
this.targetWidth = targetWidth;
this.targetHeight = targetHeight;
this.initialWidth = view.getWidth();
this.initialHeight = view.getHeight();
this.expand = expand;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int newWidth, newHeight;
if (expand) {
newWidth = this.initialWidth
+ (int) ((this.targetWidth - this.initialWidth) * interpolatedTime);
newHeight = this.initialHeight
+ (int) ((this.targetHeight - this.initialHeight) * interpolatedTime);
} else {
newWidth = this.initialWidth
- (int) ((this.initialWidth - this.targetWidth) * interpolatedTime);
newHeight = this.initialHeight
- (int) ((this.initialHeight - this.targetHeight) * interpolatedTime);
}
view.getLayoutParams().width = newWidth;
view.getLayoutParams().height = newHeight;
view.requestLayout();
}
#Override
public void initialize(int width, int height, int parentWidth,
int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
#Override
public boolean willChangeBounds() {
return true;
}
}
And layout 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:orientation="vertical">
<Button android:id="#+id/btn"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_horizontal"
android:text="Test"/>
<View android:id="#+id/centered_view"
android:layout_width="50dp"
android:layout_height="50dp"
android:clickable="true"
android:layout_gravity="center_horizontal"
android:background="#FF0000"/>
</LinearLayout>
This code works:
animatedView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!expand) expandView();
else collapseView();
}
});
private void expandView() {
expand = true;
animatedView.clearAnimation();
Display display = this.getWindowManager().getDefaultDisplay();
int maxWidth = display.getWidth();
int maxHeight = display.getHeight();
ExpandCollapseViewAnimation animation = new ExpandCollapseViewAnimation(animatedView, maxWidth,maxHeight, expand);
animation.setDuration(500);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
btn.setVisibility(View.GONE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
});
animatedView.startAnimation(animation);
animatedView.invalidate();
}
private void collapseView() {
expand = false;
animatedView.clearAnimation();
ExpandCollapseViewAnimation animation = new ExpandCollapseViewAnimation(
animatedView, dpToPx(this, 50),dpToPx(this, 50), expand);
animation.setDuration(500);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
btn.setVisibility(View.VISIBLE);
}
});
animatedView.startAnimation(animation);
animatedView.invalidate();
}

Android/Monodroid ApplyTransformation Not Called

I am using a custom animation to expand and contract my view, found on another answer here on SO. My problem is, ApplyTransformation never gets called therefore, nothing happens.
Is there anything else I'm supposed to be doing?
private void BrandTextClicked (object sender, EventArgs e)
{
Animation animation = null;
if (expanded) {
animation = new ExpandAnimation (listView, 0, height);
} else {
animation = new ExpandAnimation(listView, height, 0);
}
animation.Duration = 500;
animation.Interpolator = new AccelerateInterpolator(1);
listView.Animation = animation;
animation.StartNow ();
listView.Invalidate ();
expanded = !expanded;
}
...
public class ExpandAnimation : Animation {
private int mStartHeight;
private int mDeltaHeight;
private View mContent;
public ExpandAnimation(View content, int startHeight, int endHeight) : base() {
mContent = content;
mStartHeight = startHeight;
mDeltaHeight = endHeight - startHeight;
}
public override void Initialize (int width, int height, int parentWidth, int parentHeight)
{
base.Initialize (width, height, parentWidth, parentHeight);
}
protected override void ApplyTransformation(float interpolatedTime, Transformation t) {
ViewGroup.LayoutParams lp = mContent.LayoutParameters;
lp.Height = (int) (mStartHeight + mDeltaHeight *
interpolatedTime);
mContent.LayoutParameters = lp;
mContent.RequestLayout();
}
public override bool WillChangeBounds() {
return true;
}
}
I ended up using Android.Animation package/namespace and ValueAnimation like so:
ValueAnimator animator = null;
if (expanded) {
handle.SetImageResource(Android.Resource.Drawable.ArrowDownFloat);
animator = ValueAnimator.OfObject (new HeightEvaluator (listView), height, 0);
} else {
handle.SetImageResource(Android.Resource.Drawable.ArrowUpFloat);
animator = ValueAnimator.OfObject (new HeightEvaluator (listView), 0, height);
}
animator.SetDuration(500);
animator.SetInterpolator(new AccelerateInterpolator (1));
animator.Start ();
expanded = !expanded;

Animate view added on WindowManager

I have a view (customView) added to the WindowManager.
WindowManager mWm = (WindowManager)activity.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams(WindowManager.LayoutParams.FILL_PARENT, 0, PixelFormat.TRANSPARENT);
mWl.dimAmount = 0.0f;
mWm.addView(customView, mWl);
Inside the custom view, I will call a translate animation when close button is pressed.
//// This is the handler for the animation ////
final Handler translateHandler = new Handler();
final Runnable mtranslateUp = new Runnable() {
public void run() {
Log.v("TEST","mtranslateUp Runnable");
startAnimation(translateUp);
}
};
//// This is the listener for the close button////
View.OnClickListener closeButtonListener = new View.OnClickListener() {
public void onClick(View v) {
translateHandler.post(mtranslateUp);
}
};
//// This is the translate up animation ////
translateUp = new TranslateAnimation(0,0,0,-200);
translateUp.setFillAfter(true);
translateUp.setDuration(1000);
translateUp.setAnimationListener(new AnimationListener(){
#Override
public void onAnimationEnd(Animation animation) {
Log.v("TEST","translateUp onAnimationEnd");
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationStart(Animation animation) {
Log.v("TEST","translateUp onAnimationStart");
}}
);
If the customView is added to an activity, these code works fine!
When the customView is added to a WindowManager, the Log inside the onAnimationStart didn't show but the Log inside the Runnable can be shown.
Can anybody tells how to do animation on a view that is added to the WindowManager?
You should animate the view LayoutParameters. For example I use a method to update the view layout:
public void updateViewLayout(View view, Integer x, Integer y, Integer w, Integer h){
if (view!=null) {
WindowManager.LayoutParams lp = (WindowManager.LayoutParams) view.getLayoutParams();
if(x != null)lp.x=x;
if(y != null)lp.y=y;
if(w != null && w>0)lp.width=w;
if(h != null && h>0)lp.height=h;
mWindowService.updateViewLayout(view, lp);
}
}
Obviously mWindowService is context.getSystemService(Context.WINDOW_SERVICE).
I trigger this method in the animation:
public static void overlayAnimation(final View view2animate, int viewX, int endX) {
ValueAnimator translateLeft = ValueAnimator.ofInt(viewX, endX);
translateLeft.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
updateViewLayout(view2animate, val, null, null, null);
}
});
translateLeft.setDuration(ANIMATION_DURATION);
translateLeft.start();
}
I was facing similar problem with a View attached to WindowManager.Try adding ViewGroup to WindoManager than View directly. It should work.
windowManager need a animation by android system. so the custom animation will not work
I had a problem.
When i use updateViewLayout in onAnimationUpdate, and i set the LayoutParams's width, the animation has dropped frames.
But i set the LayoutParams's x or y, the animation is ok.
like the below code:
mViewWidth = 800;
mViewHeight = 800;
final int oldX = mFloatWindowParams.x;
final int oldWidth = mFloatWindowParams.width;
final int oldHeight = mFloatWindowParams.height;
final int deltaWidth = mViewWidth - oldWidth;
final int deltaHeight = mViewHeight - oldHeight;
final boolean isWidthLarger = deltaWidth > deltaHeight;
int first = isWidthLarger ? oldWidth : oldHeight;
int end = isWidthLarger ? mViewWidth : mViewHeight;
ValueAnimator va = ValueAnimator.ofInt(first, end);
va.setDuration(1000);
va.setInterpolator(new LinearInterpolator());
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
int value = (Integer) animation.getAnimatedValue();
float fraction = animation.getAnimatedFraction();
Log.i("onAnimationUpdate", value + "");
if (isWidthLarger) {
mFloatWindowParams.width = value;
mFloatWindowParams.height = oldHeight + (int) (deltaHeight * fraction);
} else {
mFloatWindowParams.width = oldWidth + (int) (deltaWidth * fraction);
mFloatWindowParams.height = value;
}
mFloatWindowParams.x = oldX - (int) (deltaWidth * fraction);
mWindowManager.updateViewLayout(mRootView, mFloatWindowParams);
}
});
va.start();

Categories

Resources