1.先上效果(PS:只实现了左右,原理类似,其他类型改改逻辑就可以)
2.实现逻辑
简单说,收缩动画:就是通过监听ValueAnimator动画中的值变化,改变组件的宽度,等宽度为零时,设置组件不可见。展开动画:先设置组件可见,根据动画值变化,改变组件宽度。(可能自己比较菜,不知道现成的方式,欢迎大佬指点。)
- 逻辑代码都比较简单,就不多解释了,直接上干活。PS:其他类型动画,可参考这种方式实现。
package com.mojo.tools.utils.animation; import android.animation.ValueAnimator; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.ViewGroup; import com.mojo.tools.utils.DensityUtil; /** * 实现动画收缩展开组件 * 同时联动其他子View更新布局 */ public class VisibleAnimation { /** * 需要动画的View */ private final View view; /** * 原始宽度 */ private Params defaultParams; /** * 原始宽度 */ private ValueAnimator animator; /** * View可见性,是否显示 */ private boolean visible; /** * 动画时长 */ private int duration = 5000; /** * 适用固定宽度组件, * 组件宽度为自适应 * * @param view 动画显示的View */ public VisibleAnimation(View view) { this.view = view; this.visible = view.getVisibility() == View.VISIBLE; ViewGroup.LayoutParams params = view.getLayoutParams(); if (params instanceof ViewGroup.MarginLayoutParams) { defaultParams = new Params((ViewGroup.MarginLayoutParams) params); this.initAnim(); } else { view.post(() -> { this.defaultParams = new Params(view); this.initAnim(); }); } } /** * @param view 组件 * @param marginParams 组件属性 */ public VisibleAnimation(View view, ViewGroup.MarginLayoutParams marginParams) { this.view = view; this.defaultParams = new Params(marginParams); this.initAnim(); } /** * 初始化动画 */ private void initAnim() { int max = this.defaultParams.getViewWidth(); animator = ValueAnimator.ofInt(max, 0); animator.setDuration(duration); animator.setRepeatCount(0); animator.addUpdateListener(animation -> { int value = (int) animation.getAnimatedValue(); value = visible ? max - value : value; this.setRefreshParams(value); }); } /** * @param width 组件显示所占宽度(包括边距) */ private void setRefreshParams(int width) { ViewGroup.LayoutParams params = view.getLayoutParams(); if (width == 0 && !visible) { view.setVisibility(View.GONE); } if (params instanceof ViewGroup.MarginLayoutParams) { ViewGroup.MarginLayoutParams par = (ViewGroup.MarginLayoutParams) params; par.rightMargin = Math.max(defaultParams.enM != 0 ? 1 : 0, Math.min(width, defaultParams.enM)); par.width = Math.max(1, Math.min(width - defaultParams.enM, defaultParams.wid)); par.leftMargin = Math.max(0, Math.min(width - defaultParams.enM - defaultParams.wid, defaultParams.stM)); } else { params.width = Math.max(1, defaultParams.wid * width / 100); } view.setLayoutParams(params); } String TAG = "VisibleAnimation"; /** * @param visible 是否可见 * @param animated 是否使用动画显示 */ public void setVisible(boolean visible, boolean animated) { if (animated && visible != this.visible) { if (visible) { //解决ConstraintLayout下闪烁问题 new Handler().postDelayed(() -> view.setVisibility(View.VISIBLE), 1); } this.visible = visible; animator.start(); } else { view.setVisibility(visible ? View.VISIBLE : View.GONE); } } public int getDuration() { return duration; } public void setDuration(int duration) { this.duration = duration; } static class Params { //左边距 public int stM = 0; //上边距 public int tpM = 0; //右边距 public int enM = 0; //下边距 public int boM = 0; //宽度 public int wid; //高度 public int hei; public Params(int wid, int hei) { this.wid = wid; this.hei = hei; } public Params(View view) { this.wid = view.getWidth(); this.hei = view.getHeight(); } public Params(ViewGroup.MarginLayoutParams params) { this.wid = params.width; this.hei = params.height; this.stM = params.leftMargin; this.tpM = params.topMargin; this.enM = params.rightMargin; this.boM = params.bottomMargin; Log.e("TAG", "Params: " + wid + "--:stM" + stM + "--:enM" + enM); } /** * @return 组件显示宽度(包含左右边距) */ public int getViewWidth() { return this.wid + this.stM + this.enM; } } }