If you don't talk much, first go to the renderings
Implementation ideas
- Show PopupWindow on screen
- Traverse the parent layout to get the child layout View
- 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