图片介绍(状态切换过程其实是动画的)
- 列表还未滚动时的全部显示

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();
}
});
}