How to smoothen Linear layout height animation, having heavy content - android

Animation animation = new Animation() {
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
ViewGroup.LayoutParams params = slidingPane.getLayoutParams();
int calculatedHeight = expandedHeight - ((int) (expandedHeight * interpolatedTime));
if (calculatedHeight <= collapsedHeight) {
calculatedHeight = collapsedHeight;
}
params.height = calculatedHeight;
slidingPane.setLayoutParams(params);
slidingPane.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
animation.setDuration(ANIMATION_DURATION);
animation.setAnimationListener(animationListener);
slidingPane.startAnimation(animation);
SlidingPane is a LinearLayout and it has a ListView as a child. ListView contains images in every row.
Now this code is working absolutely fine, but animation is not smooth. If I remove images from listview then it works fine.
I have already tried following things based on the answers on SO on similar questions -
1. Hide the content of sliding pane before animation and then again make them visible on animation end. It helps but behavior looks very odd
2. Set android:animateLayoutChanges="true" in xml, but its not animating anything
Is there anyway to solve this problem?

Instead of manually changing the height on each animation step, you should try to use the more systematic animation, like ValueAnimator, or ObjectAnimator:
slidingPane.animate().scaleY(0f).setInterpolator(new AccelerateDecelerateInterpolator()).setDuration(ANIMATION_DURATION);
You can use pivotY/pivotY on the view to control the anchor point of the scale animation.
Related docs:
https://developer.android.com/reference/android/animation/ValueAnimator.html
https://developer.android.com/reference/android/animation/ObjectAnimator.html
https://developer.android.com/guide/topics/graphics/prop-animation.html

Related

ChangeBounds Android Transition

I have a recyclerview in my app, and each row contains a button which shows a text in the same cell, under the button. I have used ChangeBounds transition to make the text appear with a smooth animation, increasing the row height until the text is completely shown. So when a button is clicked, I do:
TransitionManager.beginDelayedTransition(row, transition)
holder.hiddenText.setVisibility(View.VISIBLE)
It works well, but whith a problem. The hidden text appears with an animation which increases its height, as expected. But the row height is not animated, and it jumps from the original height until the final height without any animation.
Is there any way to achieve a height transition over the row, to increase at the same time as the text?
If you want animation to take effect for row also, then you need to perform beginDelayedTransition() on a one layer higher of the row, which in your case maybe is the actual RecyclerView.
Try this on your row's layout
public static void expand(final View v) {
v.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
final int targetHeight = v.getMeasuredHeight();
// Older versions of android (pre API 21) cancel animations for views with a height of 0.
v.getLayoutParams().height = 1;
v.setVisibility(View.VISIBLE);
Animation a = new Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
v.getLayoutParams().height = interpolatedTime == 1
? LayoutParams.WRAP_CONTENT
: (int)(targetHeight * interpolatedTime);
v.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
a.setDuration((int)(targetHeight / v.getContext().getResources().getDisplayMetrics().density));
v.startAnimation(a);
}
Linear or Relative layout of row's will animate and expand. Hope this solves your problem

Animate a ListView unto the view

I am trying to achieve the effect of a piece of paper coming out of a slot with a list of items on it. I came up with one approach but as I am working on it I can't keep on thinking there must be a better way.
My approach:
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/orderDetailListView">
</ListView>
</LinearLayout>
Animation code:
final int newMargin = <some value>;
Animation a = new Animation() {
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
LayoutParams params = listView.getLayoutParams();
params.leftMargin = (int)(newMargin * interpolatedTime);
yourView.setLayoutParams(params);
}
};
listView.startAnimation(a);
My question:
Is there a better way? I am not asking a suggestive question I merely want to know if there is a built in function of some sort that will make a view appear gradually from a set point.
It seems like you are trying to achieve a simple translation animation. One way of approaching this situation is to use the Property Animation Api introduced in Api level 10 (and generously backported to api level 1 with Jake Wharton's nine old androids library).
A simple example could be the following
ObjectAnimator.ofFloat(theViewObject, "translationY", -theViewObject.getHeight(), 0)
.setDuration(2000) // 2 seconds
.start();
sometimes, calls like getHeight() or getRight() etc, return 0. This is because the view hasn't actually been drawn yet. To accomodate for this you can register a callback to know when the view has been drawn.
// Listen for when the view has been drawn so we can get its dimensions
final ViewTreeObserver viewTreeObserver = theViewObject.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
ObjectAnimator.ofFloat(
theViewObject, "translationY", -theViewObject.getHeight(), 0)
.setDuration(2000) // 2 seconds
.start();
// stop listening for updates to the view so that this is only called once
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
viewTreeObserver.removeOnGlobalLayoutListener(this);
} else {
viewTreeObserver.removeGlobalOnLayoutListener(this);
}
}
});
}

Scaling a right aligned layout doesn't work as expected

I have a RelativeLayout with a ImageView inside it, it is aligned to the right of the screen with
android:layout_alignParentRight="true"
I then apply an animation to the layout, that will scale it to twice it size (on X-axis), but for some reason the alignment is broken and the layout (and image within it) stretches outside of the screen to the right. I was expecting it to grow to the left since it is aligned to the parent right.
I guess I could apply a translate to -X at the same time, but there are problems with this as well (1. it´s a bit complicated to compute, 2. the fillAfter never seems to work when using an AnimationSet).
Does anyone know how to solve this problem smoothly? :)
Apparently, Androids scaling is doing all sorts of bad stuff, for example it does not scale a 9-patch correct. Here is a custom animation for scaling that will solve the above and is compatible with 9-patch images. I also got some info here for the basics, this is just a rewrite of his solution: How to implement expandable panels in Android?
public class ExpandAnimation extends Animation
{
private final int mStartWidth;
private final int mDeltaWidth;
private View view;
public ExpandAnimation(View view, int startWidth, int endWidth)
{
mStartWidth = startWidth;
mDeltaWidth = endWidth - startWidth;
this.view = view;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t)
{
android.view.ViewGroup.LayoutParams lp = view.getLayoutParams();
lp.width = (int) (mStartWidth + mDeltaWidth * interpolatedTime);
view.setLayoutParams(lp);
view.invalidate();
}
#Override
public boolean willChangeBounds()
{
return true;
}
}

Can I partially hide a layout?

As I've a master in MS Paint, I will just upload a picture selfdescripting what I'm trying to achieve.
I've searched, but I'm not really sure what do I've to search. I've found something called Animations. I managed to rotate, fade, etc an element from a View (with this great tutorial http://www.vogella.com/articles/AndroidAnimation/article.html)
But this is a bit limited for what I'm trying to achieve, and now, I'm stuck, because I don't know how is this really called in android development. Tried words like "scrollup layouts" but I didn't get any better results.
Can you give me some tips?
Thank you.
You can see a live example, with this app: https://play.google.com/store/apps/details?id=alexcrusher.just6weeks
Sincerely,
Sergi
Use something like this as your layout (Use Linear, Relative or other layout if you wish):
<LinearLayout
android:id="#+id/lty_parent">
<LinearLayout
android:id="#+id/lyt_first" />
<LinearLayout
android:id="#+id/lyt_second"/>
</LinearLayout>
And then in an onClick method on whatever you want to use to control it, set the Visibility between Visible and Gone.
public void buttonClickListener(){
((Button) findViewById(R.id.your_button))
.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (lyt_second.getVisibility() == View.GONE) {
lyt_second.setVisibility(View.VISIBILE);
}
else {
lyt_second.setVisibility(View.GONE);
}
});
Which is fine if you just want a simple appear/disappear with nothing fancy. Things get a little bit more complicated if you want to animate it, as you need to play around with negative margins in order to make it appear to grow and shrink, like so:
We use the same onClick method that we did before, but this time when we click it starts up a custom SlideAnimation for the hidden/visible view.
#Override
public void onClick(View v) {
SlideAnimation slideAnim = new SlideAnimation(lyt_second, time);
lyt_second.startAnimation(slideAnim);
}
The implementation of the SlideAnimation is based on a general Animation class, which we extend and then Override the transformation.
public SlideAnimation(View view, int duration) {
//Set the duration of the animation to the int we passed in
setDuration(duration);
//Set the view to be animated to the view we passed in
viewToBeAnimated = view;
//Get the Margin Parameters for the view so we can edit them
viewMarginParams = (MarginLayoutParams) view.getLayoutParams();
//If the view is VISIBLE, hide it after. If it's GONE, show it before we start.
hideAfter = (view.getVisibility() == View.VISIBLE);
//First off, start the margin at the bottom margin we've already set.
//You need your layout to have a negative margin for this to work correctly.
marginStart = viewMarginParams.bottomMargin;
//Decide if we're expanding or collapsing
if (marginStart == 0){
marginEnd = 0 - view.getHeight();
}
else {
marginEnd = 0;
}
//Make sure the view is visible for our animation
view.setVisibility(View.VISIBLE);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
// Setting the new bottom margin to the start of the margin
// plus the inbetween bits
viewMarginParams.bottomMargin = marginStart
+ (int) ((marginEnd - marginStart) * interpolatedTime);
// Request the layout as it happens so we can see it redrawing
viewToBeAnimated.requestLayout();
// Make sure we have finished before we mess about with the rest of it
} else if (!alreadyFinished) {
viewMarginParams.bottomMargin = marginEnd;
viewToBeAnimated.requestLayout();
if (hideAfter) {
viewToBeAnimated.setVisibility(View.GONE);
}
alreadyFinished = true;
}
hideAfter = false;
}
}
EDIT: If anyone had used this code before and found that if you click on the button that starts the animation more than once before the animation was finished, it would mess up the animation from then on, causing it to always hide the view after the animation finished. I missed the reset of the hideAfter boolean near the bottom of the code, added it now.
you can do this manually by using setvisibility feature on the event onClick()
or
use this
dynamically adding two views one below other

Android Layout Animation won't work

I have a LinearLayout (LayoutContentView) which can contain one or two view (SubView1 and SubView2) (they are eitherTextView or ImageView).
This layout is in another LinearLayout (MyScreenLayout).
I want to make an animation on LayoutContentView so it can move and show just a part of it in MyScreenLayout.
Both of these layouts have setClipChildren(false); so it can let it's children draw outside it-self.
Depending on different parameters, I can change the size of the content, and the size of the content I will show.
Basically, I expend from top to bottom to show the two subviews and unexpend for bottom to top to show only the second subview. Before I expend, I increase the size of the LayoutContentView, so it can show the two subviews, and after I unexpend, I decrease the size of the LayoutContentView, so it can only show the second subview, and it let space on the screen for other elements.
Here is my method for expending and un-expending LayoutContentView :
mLayoutContentView.clearAnimation();
float yFrom = 0.0F;
float yTo = 0.0F;
float xFrom = 0.0F;
float xTo = 0.0F;
if (expend) { // if we expend
// I change the height of my LayoutContentView so it we can show it's two subviews
final android.view.ViewGroup.LayoutParams lp = mLayoutContentView.getLayoutParams();
lp.height = subView1H + subView2H;
setLayoutParams(lp);
invalidate();
// we start the animation so it shows only the second subview
yFrom = -subView1H;
// and we animate from top to bottom until it shows the two subviews
yTo = 0;
} else { // if we un-expend
// we animate from bottom to top starting by showing the two subviews
yFrom = 0;
// and progressively hiding the first subview and showing only the second subview
yTo = -subView1H;
}
Animation anim = new TranslateAnimation(xFrom, xTo, yFrom, yTo);
anim.setDuration(1000);
anim.setFillAfter(true);
anim.setFillEnabled(true);
anim.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
if (!expend) {
// if we un expend at the end of the animation we can set the size of LayoutContentView to the size of the second subview again
final android.view.ViewGroup.LayoutParams lp = mLayoutContentView.getLayoutParams();
lp.height = subView2H;
mLayoutContentView.setLayoutParams(lp);
invalidate();
}
}
});
mLayoutContentView.startAnimation(anim);
The way I made my animation I need it to apply on LayoutContentView, the layout which contain two subview, and with startAnimation() it doesn't do the animation.
I tried to use a LayoutAnimationController, but instead of doing the animation on the LayoutContentView, it does it on each of its children...
I also tried to do the animation on each children myself, but I don't know why, the second subview isn't shown.
Each time I've tried to use HierarchyViewer, but it's does see the change made by the animation.
Does anyone know a solution or have faced the same problem and found a good solution ?
EDIT :
Well it seems that if you set a background color to your TextView and move them with animation, the background move but even if you have set the fill after parameter to your animation, the background moves back to it's original position or something like that, and therefore as I set a background color to both of my SubViews, somewhat one of the SubView's background hide the background of the other...
And there also a problem if after the animation, one of the SubView is still outside the its layout, there is also a problem during the animation, so I add a limitation to what I intended to here too.

Categories

Resources