From f227258aab4a130a39d82f5401f6ab2ed2bfac91 Mon Sep 17 00:00:00 2001 From: SYH <1017401752@qq.com> Date: Tue, 17 Dec 2024 13:49:10 +0800 Subject: [PATCH] 2 --- .../monkeybook/widget/RecyclerViewBar.java | 164 +++++++++++------- 1 file changed, 98 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/com/monke/monkeybook/widget/RecyclerViewBar.java b/app/src/main/java/com/monke/monkeybook/widget/RecyclerViewBar.java index 0aa746d..74532fd 100644 --- a/app/src/main/java/com/monke/monkeybook/widget/RecyclerViewBar.java +++ b/app/src/main/java/com/monke/monkeybook/widget/RecyclerViewBar.java @@ -1,5 +1,6 @@ +//定义类所在的包路径,表示该文件属于com.monke.monkeybook.widget包 package com.monke.monkeybook.widget; - +// 导入必要的类 import android.animation.Animator; import android.animation.ObjectAnimator; import android.annotation.TargetApi; @@ -24,215 +25,246 @@ import com.monke.monkeybook.R; import com.monke.monkeybook.utils.DensityUtil; public class RecyclerViewBar extends LinearLayout { + // 定义滑动动画的时间常量 public static long SLIDE_ANIM_TIME = 800; - + // 定义滑块的 ImageView private ImageView ivSlider; + // 定义滑块的高度,默认为 35dp private int sliderHeight = DensityUtil.dp2px(getContext(), 35f); - + // 定义 RecyclerView private RecyclerView recyclerView; - + // 定义滑块显示和隐藏的动画对象 private Animator slideIn; private Animator slideOut; + // 构造方法,初始化 public RecyclerViewBar(Context context) { this(context, null); } + // 带有属性集的构造方法 public RecyclerViewBar(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } + // 带有样式属性的构造方法 public RecyclerViewBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - init(attrs); + init(attrs);// 调用初始化方法 } + // 针对 Lollipop 及以上版本的构造方法 @TargetApi(Build.VERSION_CODES.LOLLIPOP) public RecyclerViewBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - init(attrs); + init(attrs);// 调用初始化方法 } + // 初始化方法 private void init(AttributeSet attrs) { - setOrientation(VERTICAL); + setOrientation(VERTICAL);// 设置垂直布局 + // 获取自定义属性 TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.RecyclerViewBar); + // 设置滑块高度 sliderHeight = a.getDimensionPixelSize(R.styleable.RecyclerViewBar_slider_height, sliderHeight); + // 设置滑块的左右内边距 int paddingLeft = a.getDimensionPixelSize(R.styleable.RecyclerViewBar_slider_paddingLeft, 0); int paddingRight = a.getDimensionPixelSize(R.styleable.RecyclerViewBar_slider_paddingRight, 0); + // 创建滑块 ImageView ivSlider = new ImageView(getContext()); - ivSlider.setPadding(paddingLeft, 0, paddingRight, 0); - ivSlider.setAlpha(0f); - ivSlider.setClickable(true); - addView(ivSlider); + ivSlider.setPadding(paddingLeft, 0, paddingRight, 0);// 设置滑块内边距 + ivSlider.setAlpha(0f);// 初始透明度为 0 + ivSlider.setClickable(true);// 设置为可点击 + addView(ivSlider);// 将 ImageView 添加到布局中 + // 设置滑块的布局参数 LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, sliderHeight); - ivSlider.setLayoutParams(layoutParams); - ivSlider.setImageResource(R.drawable.icon_slider); - ivSlider.setScaleType(ImageView.ScaleType.FIT_XY); + ivSlider.setLayoutParams(layoutParams);// 应用布局参数 + ivSlider.setImageResource(R.drawable.icon_slider);// 设置滑块图标 + ivSlider.setScaleType(ImageView.ScaleType.FIT_XY);// 设置图像缩放模式 - initIvSlider(); + initIvSlider();// 初始化滑块的触摸事件 + // 添加全局布局监听 RecyclerViewBar.this.getViewTreeObserver().addOnGlobalLayoutListener(layoutInitListener); } + // 用于记录触摸的 final Y 坐标 private float finalY = -10000; + // 初始化滑块的触摸事件监听 private void initIvSlider() { + // 设置触摸事件监听器 ivSlider.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { - int action = event.getAction(); + int action = event.getAction();// 获取触摸事件类型 switch (action) { case MotionEvent.ACTION_DOWN: - finalY = event.getY(); - return true; + finalY = event.getY();// 记录初始 Y 坐标 + return true;// 消耗事件 case MotionEvent.ACTION_MOVE: - if (finalY >= 0) { - float tempY = event.getY(); - float durY = tempY - finalY; - updateSlider(durY); + if (finalY >= 0) {// 检查是否为合法的 Y 坐标 + float tempY = event.getY();// 获取当前 Y 坐标 + float durY = tempY - finalY;// 计算移动的距离 + updateSlider(durY);// 更新滑块位置 - showSlide(); + showSlide(); // 显示滑块 } else { - finalY = event.getY(); + finalY = event.getY();// 更新 finalY } - return true; + return true;// 消耗事件 case MotionEvent.ACTION_UP: - if (finalY >= 0) { - finalY = -10000; - timeCountDown.cancel(); - timeCountDown.start(); - return true; + if (finalY >= 0) {// 检查是否为合法的 Y 坐标 + finalY = -10000;// 重置 finalY + timeCountDown.cancel();// 取消计时器 + timeCountDown.start();// 启动计时器 + return true;// 消耗事件 } break; default: if (finalY >= 0) { - finalY = -10000; - return true; + finalY = -10000;// 重置 finalY + return true;// 消耗事件 } break; } - return false; + return false;// 未消费事件 } }); } + // 更新滑块位置 private void updateSlider(float durY) { - LayoutParams l = (LayoutParams) ivSlider.getLayoutParams(); - float finalMarginTop = l.topMargin + durY; + LayoutParams l = (LayoutParams) ivSlider.getLayoutParams();// 获取滑块的布局参数 + float finalMarginTop = l.topMargin + durY;// 计算新的顶部边距 + // 限制滑块的位置 if (finalMarginTop < 0) { finalMarginTop = 0; } else if (finalMarginTop > getHeight() - sliderHeight) { finalMarginTop = getHeight() - sliderHeight; } + // 如果 RecyclerView 不为空 if (recyclerView != null) { + // 计算 RecyclerView 的滚动位置 int position = Math.round(finalMarginTop / (getHeight() - sliderHeight) * (recyclerView.getAdapter().getItemCount() - 1)); - ((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(position, 0); + ((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(position, 0);// 滚动到指定位置 } - l.topMargin = Math.round(finalMarginTop); - ivSlider.setLayoutParams(l); + l.topMargin = Math.round(finalMarginTop);// 更新滑块的顶部边距 + ivSlider.setLayoutParams(l);// 应用新的布局参数 } + // 设置 RecyclerView public void setRecyclerView(RecyclerView recyclerView) { - this.recyclerView = recyclerView; + this.recyclerView = recyclerView;// 保存 RecyclerView 的引用 if (this.recyclerView != null) { + // 添加滚动监听 this.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + // 如果滚动状态不为停止,则显示滑块 super.onScrollStateChanged(recyclerView, newState); if (newState != 0) { showSlide(); } else { - timeCountDown.cancel(); - timeCountDown.start(); + timeCountDown.cancel();// 停止计时器 + timeCountDown.start();// 启动计时器 } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); + // 将滑块滚动到当前可见项目的位置 scrollToPositionWithOffset(((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition()); } }); } } + // 根据位置滚动并更新滑块位置 public void scrollToPositionWithOffset(int position) { + // 如果 RecyclerView 存在且位置合法 if (recyclerView != null && position < recyclerView.getAdapter().getItemCount()) { float temp = position * 1.0f / recyclerView.getAdapter().getItemCount(); - LayoutParams l = (LayoutParams) ivSlider.getLayoutParams(); - l.topMargin = Math.round(((getHeight() - sliderHeight) * temp)); - ivSlider.setLayoutParams(l); + LayoutParams l = (LayoutParams) ivSlider.getLayoutParams();// 获取滑块的布局参数 + l.topMargin = Math.round(((getHeight() - sliderHeight) * temp));// 计算新的顶部边距 + ivSlider.setLayoutParams(l);// 应用新的布局参数 } } + // 显示滑块 private void showSlide() { - if (ivSlider.getAlpha() < 1) { + if (ivSlider.getAlpha() < 1) {// 如果透明度小于1 if (slideOut != null && slideOut.isRunning()) { - slideOut.cancel(); + slideOut.cancel();// 如果滑出动画正在执行,取消它 } if (slideIn == null) { - slideIn = ObjectAnimator.ofFloat(ivSlider, "alpha", ivSlider.getAlpha(), 1f); - slideIn.setDuration((long) (SLIDE_ANIM_TIME * (1f - ivSlider.getAlpha()))); + slideIn = ObjectAnimator.ofFloat(ivSlider, "alpha", ivSlider.getAlpha(), 1f);// 创建滑入动画 + slideIn.setDuration((long) (SLIDE_ANIM_TIME * (1f - ivSlider.getAlpha())));// 设置动画持续时间 } if (!slideIn.isRunning()) { - slideIn.start(); + slideIn.start();// 启动滑入动画 } } } - + // 隐藏滑块 private void hideSlide() { - if (ivSlider.getAlpha() > 0) { + if (ivSlider.getAlpha() > 0) {// 如果透明度大于0 if (slideIn != null && slideIn.isRunning()) { - slideIn.cancel(); + slideIn.cancel();// 如果滑入动画正在执行,取消它 } if (slideOut == null) { - slideOut = ObjectAnimator.ofFloat(ivSlider, "alpha", ivSlider.getAlpha(), 0f); - slideOut.setDuration((long) (SLIDE_ANIM_TIME * ivSlider.getAlpha())); + slideOut = ObjectAnimator.ofFloat(ivSlider, "alpha", ivSlider.getAlpha(), 0f);// 创建滑出动画 + slideOut.setDuration((long) (SLIDE_ANIM_TIME * ivSlider.getAlpha()));// 设置动画持续时间 } if (!slideOut.isRunning()) { - slideOut.start(); + slideOut.start();// 启动滑出动画 } } } + // 创建计时器,用于滑块的自动隐藏 private TimeCountDown timeCountDown = new TimeCountDown(); + // 定义倒计时类 class TimeCountDown extends CountDownTimer { - + // 构造方法,设置计时器 public TimeCountDown() { - this(1000, 1000); + this(1000, 1000);// 1000 毫秒后完成,间隔 1000 毫秒 } public TimeCountDown(long millisInFuture, long countDownInterval) { - super(millisInFuture, countDownInterval); + super(millisInFuture, countDownInterval);// 调用父类构造方法 } @Override public void onTick(long millisUntilFinished) { - + // 每次计时器滴答时调用(可选实现,暂时为空) } @Override public void onFinish() { - hideSlide(); + hideSlide();// 计时结束时隐藏滑块 } } + // 用于存储视图的高度 private int height = 0; + // 全局布局监听器 private ViewTreeObserver.OnGlobalLayoutListener layoutInitListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { - if(getHeight()>0){ + if(getHeight()>0){// 确保当前高度大于0 if (height == 0) { - height = getHeight(); + height = getHeight();// 保存初始高度 } else { - int diff = height - getHeight(); + int diff = height - getHeight();// 计算高度差 if (diff != 0) { - LayoutParams l = (LayoutParams) ivSlider.getLayoutParams(); + LayoutParams l = (LayoutParams) ivSlider.getLayoutParams();// 获取滑块的布局参数 l.topMargin = (int) ((l.topMargin*1.0f/(height-sliderHeight))*(getHeight()-sliderHeight)); - ivSlider.setLayoutParams(l); - height = getHeight(); + ivSlider.setLayoutParams(l);// 更新滑块的顶部边距 + height = getHeight();// 更新高度 } } }