7

I've tried various solutions from this topic (see. Android: Expand/collapse animation ) and none of them really worked for me. I'm sure that the most voted ones are good and the reason that it won't work is that I don't understand something.

The main point of my problem is, that when I click on the element 'relativeZaplon' it expands very well, yet when I want to collapse it, it does not correspond.

MainActivity

 public class MainActivity extends AppCompatActivity {

    private boolean isVisible = false;
    private RelativeLayout mRelativeZaplon;
    private RelativeLayout mRelativeToSlide;
    private ExpandOrCollapse mAnimationManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mAnimationManager = new ExpandOrCollapse();
        mRelativeZaplon = (RelativeLayout) findViewById(R.id.relativeZaplon);
        mRelativeToSlide = (RelativeLayout) findViewById(R.id.relativevToSlide);
        mRelativeZaplon.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isVisible) {
                    mAnimationManager.collapse(mRelativeToSlide, 1000, 200);
                    isVisible = false;
                } else if (!isVisible){
                    mAnimationManager.expand(mRelativeToSlide, 1000, 200);
                    isVisible = true;
                }
            }
        });
    }
}

Expand/Collapse Class

    public class ExpandOrCollapse {

    public static void expand(final View v, int duration, int targetHeight) {
        int prevHeight  = v.getHeight();
        v.setVisibility(View.VISIBLE);
        ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, targetHeight);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                v.getLayoutParams().height = (int) animation.getAnimatedValue();
                v.requestLayout();
            }
        });
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.setDuration(duration);
        valueAnimator.start();
    }

    public static void collapse(final View v, int duration, int targetHeight) {
        int prevHeight  = v.getHeight();
        ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, targetHeight);
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                v.getLayoutParams().height = (int) animation.getAnimatedValue();
                v.requestLayout();
            }
        });
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.setDuration(duration);
        valueAnimator.start();
    }
}

XML

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:background="@color/colorPrimaryDark"
        android:id="@+id/relativevToSlide"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone">
    </RelativeLayout>
    <RelativeLayout
        android:id="@+id/relativeZaplon"
        android:background="@color/colorAccent"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:layout_below="@+id/relativevToSlide"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true">
    </RelativeLayout>
</LinearLayout>
2
  • could you be more specific about what does not work? Are you getting an error? Commented Nov 25, 2016 at 10:56
  • @AHoneyBustard hi ya, yes i'm sorry. I've already edited post :) cheers.
    – pjrki
    Commented Nov 25, 2016 at 11:14

3 Answers 3

7

This is my version of the method, you don´t have to set any height, it will expand or collapse any view depending on its visibility.

public static void expand(final View v, int duration) {
    final boolean expand = v.getVisibility()!=View.VISIBLE;

    int prevHeight  = v.getHeight();
    int height = 0;
    if (expand) {
        int measureSpecParams = View.MeasureSpec.getSize(View.MeasureSpec.UNSPECIFIED);
        v.measure(measureSpecParams, measureSpecParams);
        height = v.getMeasuredHeight();
    }

    ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, height);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            v.getLayoutParams().height = (int) animation.getAnimatedValue();
            v.requestLayout();
        }
    });

    valueAnimator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
            if (expand){
                v.setVisibility(View.VISIBLE);
            }
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            if (!expand){
                v.setVisibility(View.INVISIBLE);
            }
        }

        @Override
        public void onAnimationCancel(Animator animation) {

        }

        @Override
        public void onAnimationRepeat(Animator animation) {

        }
    });
    valueAnimator.setInterpolator(new DecelerateInterpolator());
    valueAnimator.setDuration(duration);
    valueAnimator.start();
}

Just call the method like this:

expand(YOURVIEWID,500);
0
3

It is because

            if (isVisible) {
                mAnimationManager.collapse(mRelativeToSlide, 1000, 200);
                isVisible = false;
            } else if (!isVisible){
                mAnimationManager.expand(mRelativeToSlide, 1000, 200);
                isVisible = true;
            }

collapse() and expand() do the same thing, they are both expand Animations in this case. You need to pass a different value to your collapse() method; The simple solution is

    mAnimationManager.collapse(mRelativeToSlide, 1000, -200);

But there are some more issues with your coding style, for example you could just get rid of your collapse() method because calling expand two times like this would also work :

            if (isVisible) {
                mAnimationManager.expand(mRelativeToSlide, 1000, -200);
                isVisible = false;
            } else if (!isVisible){
                mAnimationManager.expand(mRelativeToSlide, 1000, 200);
                isVisible = true;
            }

I suggest you post it on Code Review.

1
  • Thank you very much. I feel like a dummy i didn't see that. This solution resolved the problem.
    – pjrki
    Commented Nov 25, 2016 at 13:18
1

I'll explain the way I chose to animate layout changes.

Android has a special Animation class named ScaleAnimation by the help of which we can smoothly expand or collapse views.

Show view by expanding diagonally:

ScaleAnimation expand = new ScaleAnimation(
   0, 1.0f,
   0, 1.0f,
Animation.RELATIVE_TO_PARENT, 0,
Animation.RELATIVE_TO_PARENT, 0);
expand.setDuration(250);

view.startAnimation(expand)

where the constructor used is:

ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)

So you can change values accordingly.

For example, the below example would animate view horizontally:

ScaleAnimation expand = new ScaleAnimation(
   0, 1.1f,
   1f, 1f,
   Animation.RELATIVE_TO_PARENT, 0,
   Animation.RELATIVE_TO_PARENT, 0);
expand.setDuration(250);

You can change fromX,toX, fromY & toY according to the need.

For example if view is shown and you have to just expand it, put fromX and fromY to 1.0f, and toX, toY according to the need.

Now, using the same class you can create a more cool effect for showing view by expanding view a little bit extra and then shrinking it to original size. For this purpose, AnimationSet will be used. So it would create a kind of bubble effect.

Below example is for creating bubble effect for showing the view:

AnimationSet expandAndShrink = new AnimationSet(true);
ScaleAnimation expand = new ScaleAnimation(
   0, 1.1f,
   0, 1.1f,
Animation.RELATIVE_TO_PARENT, 0,
Animation.RELATIVE_TO_PARENT, 0);
expand.setDuration(250);

ScaleAnimation shrink = new ScaleAnimation(
   1.1f, 1f,
   1.1f, 1f,
Animation.RELATIVE_TO_PARENT, 0,
Animation.RELATIVE_TO_PARENT, 0);
shrink.setStartOffset(250);
shrink.setDuration(120);

expandAndShrink.addAnimation(expand);
expandAndShrink.addAnimation(shrink);
expandAndShrink.setFillAfter(true);
expandAndShrink.setInterpolator(new AccelerateInterpolator(1.0f));

view.startAnimation(expandAndShrink);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.