一个根据列表滚动来执行显示隐藏动画或隐藏部分文字的自定义view

218 阅读3分钟

图片介绍(状态切换过程其实是动画的)

  1. 列表还未滚动时的全部显示

2. 列表滚动一点后的部分显示

3. 列表滚动到底部彻底向右执行隐藏动画

控件布局

<com.k.toef.view.foldview.FoldView
        android:id="@+id/foldView"
        android:visibility="gone"
        android:layout_marginBottom="@dimen/x70"
        android:layout_marginRight="@dimen/x16"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

自定义view源码

import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.k.android.view.basewidget.BaseWidget;
import com.k.toef.R;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class FoldView extends BaseWidget {
    private TextView mTextFold;
    /**
     * 动画执行时间
     */
    private int actionTime = 300;
    private boolean isActionIng=false;
    //记录控件现有状态,避免连点动画顺序执行错误 0,默认状态(展开状态); 1,圆球状态; 2,圆球向右隐藏 ;
    private int state = 0;
    //当动画执行完成时通知上层,因为快速滑动的状态下滚动到顶部有可能textView无法进行展开,所以需要监听此事件.再次进行一次位置和状态的匹配.匹配不上的话,上一个动画完成后则上层再次主动调用一下textView的展开方法
    private OnAnimEndListener mEndListener;
    public FoldView(@NotNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void initView() {
        mTextFold = findViewById(R.id.textFold);

    }

    @Override
    public void initInnerEvent() {

    }

    public void setState(int state) {
        this.state = state;
    }

    /**
     * 外界可配置子动画执行时长
     * @param actionTime
     */
    public void setActionTime(int actionTime) {
        this.actionTime = actionTime;
    }

    @Override
    public int getLayoutId() {
        return R.layout.view_fold;
    }

    int tempWidth = 0;
    /**
     * 执行textView向右收起动画
     */
    public void rightFold1(){
        if(isActionIng || state!=0){
            return;
        }
        if(tempWidth==0){
            tempWidth = mTextFold.getMeasuredWidth();
        }
        ValueAnimator valueAnimator = new ValueAnimator();
        valueAnimator.setIntValues(mTextFold.getMeasuredWidth(),0);
        valueAnimator.addListener(new FoldViewAnimatorListener(this,null,1));//动画执行完后显示成 圆球状态
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                ViewGroup.LayoutParams params = mTextFold.getLayoutParams();
                int width = (int)animation.getAnimatedValue();
                params.width = width;
                mTextFold.setLayoutParams(params);
                Log.e("--->",((float)width)/tempWidth+"");
//                invalidate();
                mTextFold.setAlpha(((float)width)/tempWidth);
                if(width==0){
                    mTextFold.setVisibility(View.GONE);
                }else{
                    mTextFold.setVisibility(View.VISIBLE);
                }
            }
        });
        valueAnimator.setDuration(actionTime);
        valueAnimator.start();
    }

    /**
     * 执行向右第二次收起动画
     */
    public void rightFold2(){
        if(isActionIng || state!=1){
            return;
        }
        final float tempX = getX();
        ValueAnimator valueAnimator = new ValueAnimator();
        valueAnimator.setFloatValues(0,getResources().getDimensionPixelSize(R.dimen.x64));
        valueAnimator.addListener(new FoldViewAnimatorListener(this,null,2));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float translateX = (float)animation.getAnimatedValue();
                setX(tempX + translateX);
            }
        });
        valueAnimator.setDuration(actionTime);
        valueAnimator.start();
    }

    /**
     * 执行整体view向左划出动画
     */
    public void leftOpen1(){
        if(isActionIng || state!=2){
            return;
        }
        final float tempX = getX();
        ValueAnimator valueAnimator = new ValueAnimator();
        valueAnimator.setFloatValues(0,getResources().getDimensionPixelSize(R.dimen.x64));
        valueAnimator.addListener(new FoldViewAnimatorListener(this,mEndListener,1));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float translateX = (float)animation.getAnimatedValue();
                setX(tempX - translateX);
            }
        });
        valueAnimator.setDuration(actionTime);
        valueAnimator.start();
    }
    /**
     * 执行textView向左变大动画
     */
    public void leftOpen2(){
        if(isActionIng || state!=1){
            return;
        }
        if(tempWidth==0){
            tempWidth = mTextFold.getMeasuredWidth();
        }
        ValueAnimator valueAnimator = new ValueAnimator();
        valueAnimator.setIntValues(0,tempWidth);
        valueAnimator.addListener(new FoldViewAnimatorListener(this,null,0));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                ViewGroup.LayoutParams params = mTextFold.getLayoutParams();
                int width = (int)animation.getAnimatedValue();
                params.width = width;
                mTextFold.setLayoutParams(params);
                Log.e("--->",((float)width)/tempWidth+"");
//                invalidate();
                mTextFold.setAlpha(((float)width)/tempWidth);
                if(width==0){
                    mTextFold.setVisibility(View.GONE);
                }else{
                    mTextFold.setVisibility(View.VISIBLE);
                }
            }
        });
        valueAnimator.setDuration(actionTime);
        valueAnimator.start();
    }

    public void setActionIng(boolean actionIng) {
        isActionIng = actionIng;
    }

    public void setOnAnimEndListener(OnAnimEndListener listener){
        this.mEndListener = listener;
    }

    public int getState() {
        return state;
    }


}

控件的使用

1. 初始化
FoldView mFoldView = findViewById(R.id.foldView);

2.设置此view点击事件 
protected boolean isRoolUp = false;//是否折叠状态--(本例是根据是否是折叠状态处理了一些逻辑,要是您不需要可以不用添加此变量)
mFoldView.setOnClickListener(this);
点击后调用  switchRollUp(true);

private void switchRollUp(boolean roolup) {
        this.isRoolUp = !roolup;
        ViewGroup.LayoutParams params = spokenQuestionContentRl.getLayoutParams();
        if (roolup) {
            params.height = getResources().getDimensionPixelOffset(R.dimen.x120);
        } else {
            params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
        }
        spokenQuestionContentRl.setLayoutParams(params);
    }

3.设置foldView内部动画执行完时的监听
mFoldView.setOnAnimEndListener(new OnAnimEndListener() {
            @Override
            public void onAnimEnd() {
                animatorCheck();
            }
        });

private void animatorCheck() {
        if (isRoolUp){//不是是折叠状态
            if(tempHeight==0){
                tempHeight = spokenQuestionContentRl.getMeasuredHeight();
                tempHeight=tempHeight-cdlMain.getMeasuredHeight()+spokenTopll.getMeasuredHeight();
            }
            if(tempVerticalOffset<=10){//默认状态
                if(mFoldView.getState()!=0){
                    mFoldView.leftOpen2();
                }
            }else if(tempVerticalOffset>10 && tempVerticalOffset<tempHeight){//圆球状态
                if(mFoldView.getState()==0){
                    mFoldView.rightFold1();
                }else {
                    mFoldView.leftOpen1();
                }
            }else if(tempVerticalOffset>tempHeight){//圆球收起
                if(mFoldView.getState()==1){
                    mFoldView.rightFold2();
                }
            }
        }
    }
    //点击  点击收起按钮
    public void scrollToTop() {
        CoordinatorLayout.Behavior behavior =((CoordinatorLayout.LayoutParams) mAppBar.getLayoutParams()).getBehavior();
        if (behavior instanceof AppBarLayout.Behavior) {
            AppBarLayout.Behavior appBarLayoutBehavior = (AppBarLayout.Behavior) behavior;
            int topAndBottomOffset = appBarLayoutBehavior.getTopAndBottomOffset();
            if (topAndBottomOffset != 0) {
                appBarLayoutBehavior.setTopAndBottomOffset(0);
            }
        }
    }
    
4. 被检测的view处理-本例检测AppBar的滑动状态,故需要监听appBar
int tempHeight;
int tempVerticalOffset = 0;
private void initListener() {
    mAppBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
            tempVerticalOffset = -verticalOffset;
            animatorCheck();
        }
    });
    mFoldView.setOnClickListener(this);
    mFoldView.setOnAnimEndListener(new OnAnimEndListener() {
        @Override
        public void onAnimEnd() {
            animatorCheck();
        }
    });
}