SYH 1 year ago
parent 15906f54f7
commit f227258aab

@ -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();// 更新高度
}
}
}

Loading…
Cancel
Save