From 460df3fc92ef3cda42601368561367346d41dc80 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Mon, 15 Dec 2025 17:11:34 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E9=87=8D=E5=A4=8D=E7=9A=84?= =?UTF-8?q?=E4=B8=8D=E8=83=BD=E7=94=A8=E7=9A=84=E5=86=97=E4=BD=99Horizonta?= =?UTF-8?q?lListView=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../studio/libappbase/HorizontalListView.java | 240 ------------------ 1 file changed, 240 deletions(-) delete mode 100644 libappbase/src/main/java/cc/winboll/studio/libappbase/HorizontalListView.java diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/HorizontalListView.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/HorizontalListView.java deleted file mode 100644 index 1a48fb6..0000000 --- a/libappbase/src/main/java/cc/winboll/studio/libappbase/HorizontalListView.java +++ /dev/null @@ -1,240 +0,0 @@ -package cc.winboll.studio.libappbase; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.widget.ListView; -import android.widget.Scroller; - -/** - * @Author ZhanGSKen&豆包大模型 - * @Date 2025/11/11 20:26 - * @Describe 水平滚动 ListView 控件 - * 继承自 ListView,重写布局和测量逻辑,实现子项水平排列和滚动,替代默认垂直布局 - */ -public class HorizontalListView extends ListView { - /** 日志标签,用于当前控件的日志输出标识 */ - public static final String TAG = "HorizontalListView"; - - /** 子项垂直偏移量(用于调整子项在垂直方向的位置,默认 0) */ - private int mVerticalOffset = 0; - /** 平滑滚动控制器(用于实现水平方向的平滑滚动动画) */ - private Scroller mScroller; - /** 所有子项总宽度(包含内边距),用于计算滚动范围 */ - private int mTotalWidth; - - /** - * 构造方法:仅上下文 - * @param context 上下文(Activity/Fragment) - */ - public HorizontalListView(Context context) { - super(context); - init(); - } - - /** - * 构造方法:上下文 + 自定义属性 - * @param context 上下文 - * @param attrs 自定义属性集合(如布局文件中设置的属性) - */ - public HorizontalListView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - /** - * 构造方法:上下文 + 自定义属性 + 样式属性 - * @param context 上下文 - * @param attrs 自定义属性集合 - * @param defStyle 样式属性(如系统默认样式) - */ - public HorizontalListView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(); - } - - /** - * 初始化控件配置 - * 初始化滚动控制器,设置滚动条显示状态 - */ - private void init() { - // 初始化平滑滚动器(上下文为当前控件所在上下文) - mScroller = new Scroller(getContext()); - // 启用水平滚动条(默认显示) - setHorizontalScrollBarEnabled(true); - // 禁用垂直滚动条(水平列表无需垂直滚动) - setVerticalScrollBarEnabled(false); - } - - /** - * 设置子项垂直偏移量 - * 用于整体调整所有子项在垂直方向的位置(如居中、偏移) - * @param verticalOffset 垂直偏移像素值(正数向下偏移,负数向上偏移) - */ - public void setVerticalOffset(int verticalOffset) { - this.mVerticalOffset = verticalOffset; - } - - /** - * 重写布局方法:实现子项水平排列 - * 遍历所有子项,按水平方向依次布局(左对齐,叠加排列) - * @param changed 布局是否发生变化(true:首次布局或尺寸变化;false:重绘) - * @param l 控件左边界坐标 - * @param t 控件上边界坐标 - * @param r 控件右边界坐标 - * @param b 控件下边界坐标 - */ - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); // 执行父类布局逻辑(确保基础配置生效) - - int childCount = getChildCount(); // 获取当前可见子项数量 - int left = getPaddingLeft(); // 子项起始左坐标(包含控件左内边距) - // 控件可用高度(总高度 - 上下内边距) - int viewHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); - mTotalWidth = left; // 初始化总宽度为左内边距 - - // 遍历子项,水平排列 - for (int i = 0; i < childCount; i++) { - View child = getChildAt(i); // 获取当前子项 - int childWidth = child.getMeasuredWidth(); // 子项测量宽度 - int childHeight = child.getMeasuredHeight(); // 子项测量高度 - - // 布局子项:水平方向从 left 开始,垂直方向偏移 mVerticalOffset - child.layout( - left, // 子项左边界 - mVerticalOffset, // 子项上边界(带垂直偏移) - left + childWidth, // 子项右边界(左 + 宽度) - mVerticalOffset + childHeight // 子项下边界(偏移 + 高度) - ); - - left += childWidth; // 更新下一个子项的起始左坐标 - } - - // 计算总宽度(所有子项宽度 + 左右内边距) - mTotalWidth = left + getPaddingRight(); - } - - /** - * 重写测量方法:设置控件测量规则 - * 水平方向:允许无限宽度(适应所有子项总宽度);垂直方向:自适应内容高度 - * @param widthMeasureSpec 父控件传递的宽度测量规格 - * @param heightMeasureSpec 父控件传递的高度测量规格 - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // 重写宽度测量规则:最大值(Integer.MAX_VALUE >> 2 避免溢出),自适应内容 - int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); - // 重写高度测量规则:同上,自适应子项高度 - int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); - - // 执行父类测量逻辑(使用重写后的测量规格) - super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); - } - - /** - * 重写滚动计算方法:实现平滑滚动 - * 配合 Scroller 实现水平方向的平滑滚动动画(需在滚动时调用 invalidate() 触发) - */ - @Override - public void computeScroll() { - // 判断滚动是否正在进行(Scroller 计算当前滚动位置) - if (mScroller.computeScrollOffset()) { - // 滚动到当前计算的位置(x 轴水平滚动,y 轴固定 0) - scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); - // 触发重绘,持续更新滚动状态 - postInvalidate(); - } - } - - /** - * 平滑滚动到指定坐标 - * 基于 Scroller 实现水平方向的平滑滚动(300ms 动画时长) - * @param x 目标 x 轴坐标(水平滚动位置) - * @param y 目标 y 轴坐标(固定 0,无需垂直滚动) - */ - public void smoothScrollTo(int x, int y) { - // 计算滚动距离(目标坐标 - 当前滚动坐标) - int dx = x - getScrollX(); - int dy = y - getScrollY(); - - // 启动平滑滚动:起始坐标(当前滚动位置)、滚动距离、动画时长(300ms) - mScroller.startScroll(getScrollX(), getScrollY(), dx, dy, 300); - // 触发重绘,启动滚动动画 - invalidate(); - } - - /** - * 计算水平滚动总范围(用于滚动条显示比例) - * @return 滚动总宽度(所有子项总宽度 + 内边距) - */ - @Override - public int computeHorizontalScrollRange() { - return mTotalWidth; - } - - /** - * 计算当前水平滚动偏移量(用于滚动条位置) - * @return 当前 x 轴滚动坐标 - */ - @Override - public int computeHorizontalScrollOffset() { - return getScrollX(); - } - - /** - * 计算水平滚动可视范围(用于滚动条大小) - * @return 控件可见宽度(当前显示区域宽度) - */ - @Override - public int computeHorizontalScrollExtent() { - return getWidth(); - } - - /** - * 滚动到指定位置的子项(水平方向) - * 定位目标子项,计算滚动坐标,执行平滑滚动 - * @param position 子项索引(从 0 开始,仅当前可见子项有效) - */ - public void scrollToItem(int position) { - // 校验索引有效性(避免数组越界) - if (position < 0 || position >= getChildCount()) { - LogUtils.d(TAG, "无效的子项索引: " + position); - return; - } - - View targetView = getChildAt(position); // 获取目标子项 - int targetLeft = targetView.getLeft(); // 目标子项左边界坐标 - // 计算目标滚动坐标(子项左边界 - 控件左内边距,确保子项左对齐显示) - int scrollX = targetLeft - getPaddingLeft(); - - // 修正滚动范围(避免超出总宽度或小于 0) - int maxScrollX = mTotalWidth - getWidth(); // 最大滚动坐标(总宽度 - 控件宽度) - scrollX = Math.max(0, Math.min(scrollX, maxScrollX)); - - // 强制重新布局和绘制(确保子项位置正确) - requestLayout(); - invalidateViews(); - // 平滑滚动到目标坐标 - smoothScrollTo(scrollX, 0); - - // 打印滚动日志(调试用) - LogUtils.d(TAG, String.format( - "滚动到子项索引: %d, 目标滚动X: %d, 总滚动范围: %d", - position, scrollX, computeHorizontalScrollRange() - )); - } - - /** - * 重置滚动到起始位置(最左侧) - * 强制重新布局后,平滑滚动到 x=0 坐标 - */ - public void resetScrollToStart() { - // 强制重新布局和绘制(确保滚动位置准确) - requestLayout(); - invalidateViews(); - // 平滑滚动到最左侧(x=0,y=0) - smoothScrollTo(0, 0); - } -} -