8

I have a layout that I want to expand after button click, as shown below:

Expectation

The problem is I need to use Animation, so I decided to use View.animate.translationY(). Here is my code:

private void showBottomThreeLines(boolean show){
    if(show)
        mShiftContainer.animate().translationY(0);
    else
        mShiftContainer.animate().translationY(-(mFifthLineContainer.getHeight() * 3));
}

However, this is what I get after testing:

Reality

The current height is still the same as the previous height! The view's height is using MATCH_PARENT. I even tried to change it to 1000dp, but it still has the same height. How do I update view's height during translationY() animation?

Harry
  • 568
  • 1
  • 5
  • 20
  • 1
    translate doesn't set the height ..it move the view to x,y ... scale do the work for you...use mShiftContainer.animate().scaleY(-(mFifthLineContainer.getHeight() * 3)).setDuration(2000); – Angad Tiwari Jun 05 '15 at 07:20
  • Yeah, it doesn't. That's why I think I need something else... I tried the `mShiftContainer.animate().scaleY(-(mFifthLineContainer.getHeight() * 3)).setDuration(2000);`, but the layout go up that it makes my screen blank white. I think the parameter for `scaleY()` is wrong. – Harry Jun 05 '15 at 07:26
  • try different property...such as mShiftContainer.animate().scaleYBy() or mShiftContainer.animate().y() – Angad Tiwari Jun 05 '15 at 08:50
  • I don't think `scaleY()` is a good solution, as it enlarges my font size, padding, margin etc. It would just break my layout. Also I've tried `y()`, but it only updates my Y position without increasing its height. – Harry Jun 05 '15 at 08:57
  • 1
    try this http://stackoverflow.com/questions/9695981/animation-in-changing-layoutparams-in-linearlayout – Angad Tiwari Jun 05 '15 at 09:11
  • the answer with 14 vote...it work perfect for me – Angad Tiwari Jun 05 '15 at 09:13
  • he just extend the Animation and override transformation() method..to set layoutparams with height... – Angad Tiwari Jun 05 '15 at 09:14

2 Answers2

2

After doing some research, I find out that defining view height after its translation will not increase its height at all. It appears that the sum of the entire view's height CANNOT go exceed its parent layout's height. Which means, if you set parent layout's height as MATCH_PARENT and your screen size is 960 dp, your child view's maximum height will be 960 dp, even if you define its height, e.g. android:layout_height="1200dp".

Therefore, I decided to dynamically re-size parent layout's height, and make the footer layout's height MATCH_PARENT. By default, my parent layout's height is MATCH_PARENT, but I call below method on onCreateView():

private void adjustParentHeight(){
    WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
    DisplayMetrics metrics = new DisplayMetrics();
    wm.getDefaultDisplay().getMetrics(metrics);
    ViewGroup.LayoutParams params = mView.getLayoutParams();
    mFifthLineContainer.measure(0, 0);
    params.height = metrics.heightPixels + (mFifthLineContainer.getMeasuredHeight() * 3);
    mView.setLayoutParams(params);
}

This will make my footer layout become off-screen. Then I tried to use View.animate().translationY(), but then I got another problem! There is a bug in Android animation that causes flicker when you call View.setY() on onAnimationEnd(). It seems the cause is onAnimationEnd() is being called before the animation truly ends. Below are references that I use to solve this problem:

Android Animation Flicker

Android Flicker when using Animation and onAnimationEnd Listener

Therefore, I changed my showBottomThreeLines() method:

private void showBottomThreeLines(boolean show){
    if(show){
        TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, -(mFifthLineContainer.getHeight() * 3), 0);
        translateAnimation.setDuration(300);
        translateAnimation.setFillAfter(true);
        translateAnimation.setFillEnabled(true);
        translateAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                mShiftContainer.setY(mShiftContainer.getY() + mFifthLineContainer.getHeight() * 3);
            }

            @Override
            public void onAnimationEnd(Animation animation) {

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        mShiftContainer.startAnimation(translateAnimation);
    } else{
        TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, mFifthLineContainer.getHeight() * 3, 0);
        translateAnimation.setDuration(300);
        translateAnimation.setFillAfter(true);
        translateAnimation.setFillEnabled(true);
        translateAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                mShiftContainer.setY(mFifthLineContainer.getY());
            }

            @Override
            public void onAnimationEnd(Animation animation) {

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        mShiftContainer.startAnimation(translateAnimation);
    }
}
Community
  • 1
  • 1
Harry
  • 568
  • 1
  • 5
  • 20
0

Use this:

private ActionMode mActionMode;

...


private void expandView(View summary, int height, final boolean isSearch) {
        if (isSearch) summary.setVisibility(View.VISIBLE);

        final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.EXACTLY);
        summary.measure(widthSpec, height);

        Animator animator = slideAnimator(summary.getHeight(), height, summary);
        animator.start();
    }

    private void collapseView(final View summary, int height, final boolean isSearch) {
        int finalHeight = summary.getHeight();

        ValueAnimator mAnimator = slideAnimator(finalHeight, height, summary);
        final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.EXACTLY);
        summary.measure(widthSpec, height);

        Animator animator = slideAnimator(summary.getHeight(), height, summary);
        animator.start();
        mAnimator.start();
    }

    /**
     * Slide animation
     *
     * @param start   start animation from position
     * @param end     end animation to position
     * @param summary view to animate
     * @return valueAnimator
     */
    private ValueAnimator slideAnimator(int start, int end, final View summary) {

        ValueAnimator animator = ValueAnimator.ofInt(start, end);

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                //Update Height
                int value = (Integer) valueAnimator.getAnimatedValue();

                ViewGroup.LayoutParams layoutParams = summary.getLayoutParams();
                layoutParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, value, getResources().getDisplayMetrics());//value;
                summary.setLayoutParams(layoutParams);
            }
        });
        return animator;
    }

    private ActionMode.Callback mActionModeCallBack = new ActionMode.Callback() {
        //Contextual action menu. Shows different options in action bar when a list item is long clicked!
        @Override
        public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
            // Inflate a menu resource providing context menu items
            MenuInflater inflater = actionMode.getMenuInflater();
            inflater.inflate(R.menu.contextual_menu_options, menu);
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
            return false;
        }

        @Override
        public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
            mActionMode.finish();
            return true;
        }

        @Override
        public void onDestroyActionMode(ActionMode actionMode) {
            mActionMode = null;
        }
    };

Hope this will help you!

ArbenMaloku
  • 548
  • 4
  • 15
  • Thanks for your answer! I've tried your code, but still no luck. The height got changed, but the layout Y position doesn't. Is there any part of your code that has to be modified to achieve my goal? – Harry Jun 05 '15 at 07:33
  • @Harry Can you post your xml file – ArbenMaloku Jun 05 '15 at 07:47