The controls in the PopupWindow implemented by Android pop up from the top one by one

If you don't talk much, first go to the renderings

Implementation ideas

  1. Show PopupWindow on screen
  2. Traverse the parent layout to get the child layout View
  3. Set the entry and exit animation for each View, and use the Handler to delay

1. Display PopupWindow

private void showWindow() {
        View layout = getLayoutInflater().inflate(R.layout.window_popup, null);
        final RelativeLayout relativeLayout = layout.findViewById(R.id.relative_popup);
        relativeLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Add exit animation
                closeAnimation(relativeLayout);
            }
        });
        popupWindow = new PopupWindow(layout, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        popupWindow.setFocusable(true);
        popupWindow.setBackgroundDrawable(new BitmapDrawable());
        //Add entry animation
        showAnimation(relativeLayout);
        popupWindow.setOutsideTouchable(false);
        popupWindow.setFocusable(false);
        popupWindow.showAtLocation(getWindow().getDecorView(), Gravity.BOTTOM, 0, 0);
    }

2. Entry animation

Because you want to achieve a rebound like effect after pop-up from the top, the effect written directly with objectanimator. Offlow() method is a bit ugly, so you directly found a better rebound effect through the implementation of TypeEvaluator interface on the Internet!

private void showAnimation(ViewGroup layout) {
        for (int i = 0; i < layout.getChildCount(); i++) {
            final View child = layout.getChildAt(i);
            child.setVisibility(View.INVISIBLE);
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    child.setVisibility(View.VISIBLE);
                    ValueAnimator fadeAnim = ObjectAnimator.ofFloat(child, "translationY", 800, 0);
                    fadeAnim.setDuration(800);
                    KickBackAnimator kickAnimator = new KickBackAnimator();
                    kickAnimator.setDuration(800);
                    fadeAnim.setEvaluator(kickAnimator);
                    fadeAnim.start();
                }
            }, i * 50);
        }
    }

Class to achieve rebound effect

import android.animation.TypeEvaluator;

public class KickBackAnimator implements TypeEvaluator<Float> {

    private final float s = 1.70158f;
    float mDuration = 0f;

    public void setDuration(float duration) {
        mDuration = duration;
    }

    public Float evaluate(float fraction, Float startValue, Float endValue) {
        float t = mDuration * fraction;
        float b = startValue.floatValue();
        float c = endValue.floatValue() - startValue.floatValue();
        float d = mDuration;
        float result = calculate(t, c, b, d);
        return result;
    }

    public Float calculate(float t, float c, float b, float d) {
        return b * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + c;
    }
}

Exit animation

Because our implementation is to traverse the child layout in the parent layout to achieve the entry and exit animation effect, so when you exit, you need to reverse the order of views in the collection, or the first View to exit is the first View to enter, so the effect will be ugly Of course, you can also reverse the set data when entering the field. See the layout method for details.
We use the reverse (list <? > list) method in the Collections class to reverse the data in the collection

private void closeAnimation(ViewGroup layout) {
        ArrayList<View> viewArrayList = new ArrayList<>();
        for (int i = 0; i < layout.getChildCount(); i++) {
            viewArrayList.add(layout.getChildAt(i));
        }
        Collections.reverse(viewArrayList);
        for (int i = 0; i < viewArrayList.size(); i++) {
            final View child = viewArrayList.get(i);
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    ValueAnimator fadeAnim = ObjectAnimator.ofFloat(child, "translationY", 0, -900);
                    fadeAnim.setDuration(800);
                    fadeAnim.start();
                    fadeAnim.addListener(new Animator.AnimatorListener() {
                        @Override
                        public void onAnimationStart(Animator animation) {

                        }

                        @Override
                        public void onAnimationEnd(Animator animation) {
                            child.setVisibility(View.INVISIBLE);
                            //Judge if it is the last View to exit, and exit the PopupWindow window
                            if (child.getId() == R.id.source_linear) {
                                popupWindow.dismiss();
                            }
                        }

                        @Override
                        public void onAnimationCancel(Animator animation) {

                        }

                        @Override
                        public void onAnimationRepeat(Animator animation) {
                            
                        }
                    });
                }
            }, i * 50);
        }
    }

OK, the specific implementation is these three steps!
The source code has been uploaded to Github. Anyone who doesn't understand can download it. GitHub source address

Tags: github Android

Posted on Sun, 03 Nov 2019 18:13:19 -0500 by rajatr