news 2026/10/30 1:01:20

每次滑动整个item的RecyclerView

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
每次滑动整个item的RecyclerView

每次滑动整个item的RecyclerView(实现viewpager效果),支持水平和垂直滑动

import android.content.Context; import android.support.annotation.Nullable; import android.support.v4.view.VelocityTrackerCompat; import android.support.v7.widget.LinearLayoutManager; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import java.lang.annotation.ElementType; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * Created by lijing on 2017/8/19. */ public class ScrollOneItemRecyclerView extends RecyclerView { private int height, width; private int lastPosition; private int oldScrollState; private VelocityTracker mVelocityTracker; private int downX, downY; private boolean isFirstDown; private boolean canFocus; private boolean canTouchChangePage = true;//是否可以手动换页 public ScrollOneItemRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); this.height = h; this.width = w; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: isFirstDown = true; canFocus = true; downX = (int) ev.getX(); downY = (int) ev.getY(); break; case MotionEvent.ACTION_MOVE: if (isFirstDown) { isFirstDown = false; int x = (int) ev.getX(); int y = (int) ev.getY(); int disX = Math.abs(x - downX); int disY = Math.abs(y - downY); LayoutManager layoutManager = getLayoutManager(); if (layoutManager != null) { final boolean canScrollVertically = layoutManager.canScrollVertically(); if (disX <= 1 && disY <= 1) { canFocus = false; } else if (disX >= disY) { canFocus = !canScrollVertically; } else { canFocus = canScrollVertically; } } } break; } return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent e) { if (!canTouchChangePage) { return false; } else { return super.onInterceptTouchEvent(e); } } @Override public boolean onTouchEvent(MotionEvent e) { if (!canTouchChangePage) return true;//不能手动换页,,就是,recyclerview不能滑动,只能不执行super的onTouchEvent if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } boolean eventAddedToVelocityTracker = false; LayoutManager layoutManager = getLayoutManager(); if (layoutManager == null) return false; final boolean canScrollHorizontally = layoutManager.canScrollHorizontally(); final boolean canScrollVertically = layoutManager.canScrollVertically(); final MotionEvent vtev = MotionEvent.obtain(e); switch (e.getAction()) { case MotionEvent.ACTION_MOVE: return super.onTouchEvent(e) && canFocus; case MotionEvent.ACTION_UP: { mVelocityTracker.addMovement(vtev); eventAddedToVelocityTracker = true; mVelocityTracker.computeCurrentVelocity(1000, 8000); final float xvel = canScrollHorizontally ? -VelocityTrackerCompat.getXVelocity(mVelocityTracker, e.getPointerId(0)) : 0; final float yvel = canScrollVertically ? -VelocityTrackerCompat.getYVelocity(mVelocityTracker, e.getPointerId(0)) : 0; if (((int) xvel == 0) && ((int) yvel == 0)) { if (layoutManager instanceof LinearLayoutManager) { int firstPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); View child = layoutManager.findViewByPosition(firstPosition); int x = (int) e.getX(); int y = (int) e.getY(); int disX = Math.abs(x - downX); int disY = Math.abs(y - downY); if (canScrollHorizontally) { if (disX > 100) { int right = child.getRight(); if (right > width / 2) { fling(-5000, 0); } else { fling(5000, 0); } } } else if (canScrollVertically) { if (disY > 100) { int bottom = child.getBottom(); if (bottom > height / 2) { fling(0, -5000); } else { fling(0, 5000); } } } } } } } if (!eventAddedToVelocityTracker) { mVelocityTracker.addMovement(vtev); } vtev.recycle(); return super.onTouchEvent(e); } /** * @param velocityX * @param velocityY recyclerview向上滑动为正 * @return */ @Override public boolean fling(int velocityX, int velocityY) { LayoutManager layoutManager = getLayoutManager(); if (layoutManager instanceof LinearLayoutManager) { int position = -1; if (layoutManager.canScrollVertically()) { if (velocityY > 0) { position = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); View child = layoutManager.findViewByPosition(position); int top = child.getTop(); int dis = height - (height - top); smoothScrollBy(0, dis, velocityX, Math.max(velocityY, 5000)); } else { position = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); View child = layoutManager.findViewByPosition(position); int bottom = child.getBottom(); int dis = bottom - height; smoothScrollBy(0, dis, velocityX, Math.min(velocityY, -5000)); } } if (layoutManager.canScrollHorizontally()) { if (velocityX > 0) { position = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); View child = layoutManager.findViewByPosition(position); int left = child.getLeft(); int dis = width - (width - left); smoothScrollBy(dis, 0, Math.max(velocityX, 5000), velocityY); } else { position = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); View child = layoutManager.findViewByPosition(position); int right = child.getRight(); int dis = right - width; smoothScrollBy(dis, 0, Math.max(velocityX, -5000), velocityY); } } if (onPagerChangedListener != null) { onPagerChangedListener.onPagerChanged(lastPosition, position); } lastPosition = position; } return true; } public void smoothScrollBy(int dx, int dy, int vx, int vy) { try { Class c = null; try { c = Class.forName("android.support.v7.widget.RecyclerView");//获得Class对象 } catch (ClassNotFoundException e) { e.printStackTrace(); return; } /** * 对应代码 * if (mLayout == null) { * Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " + * "Call setLayoutManager with a non-null argument."); * return; * } */ Field mLayoutField = c.getDeclaredField("mLayout");//根据属性名称,获得类的属性成员Field mLayoutField.setAccessible(true);//设置为可访问状态 LayoutManager mLayout = null; try { mLayout = (LayoutManager) mLayoutField.get(this);//获得该属性对应的对象 if (mLayout == null) { return; } } catch (IllegalAccessException e) { e.printStackTrace(); return; } /** * 对应代码 * if (mLayoutFrozen) { * return; * } */ Field mLayoutFrozen = c.getDeclaredField("mLayoutFrozen"); mLayoutFrozen.setAccessible(true); try { if ((Boolean) mLayoutFrozen.get(this)) { return; } } catch (IllegalAccessException e) { e.printStackTrace(); return; } /** * 对应代码 * if (!mLayout.canScrollHorizontally()) { * dx = 0; * } */ if (!mLayout.canScrollHorizontally()) { dx = 0; } /** * 对应代码 * if (!mLayout.canScrollVertically()) { * dy = 0; * } */ if (!mLayout.canScrollVertically()) { dy = 0; } /** * 对应代码 * if (dx != 0 || dy != 0) { * mViewFlinger.smoothScrollBy(dx, dy); * } * 此处调用mViewFlinger.smoothScrollBy(dx, dy, duration);这是我们的目的。 */ Field mViewFlingerField = c.getDeclaredField("mViewFlinger"); mViewFlingerField.setAccessible(true); try { Class ViewFlingerClass = null; try { //由于内部类是私有的,所以不能直接得到内部类名, //通过mViewFlingerField.getType().getName() //可以得到私有内部类的完整类名 ViewFlingerClass = Class.forName(mViewFlingerField.getType().getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); return; } //根据方法名,获得我们的目标方法对象。第一个参数是方法名,后面的是该方法的入参类型。 // 注意Integer.class与int.class的不同。 Method smoothScrollBy = ViewFlingerClass.getDeclaredMethod("smoothScrollBy", int.class, int.class, int.class, int.class); smoothScrollBy.setAccessible(true);//设置为可操作状态 if (dx != 0 || dy != 0) { Log.d("MySmoothScrollBy", "dx=" + dx + " dy=" + dy); try { //唤醒(调用)方法, // mViewFlingerField.get(this)指明是哪个对象调用smoothScrollBy。 // dx, dy, duration 是smoothScrollBy所需参数 smoothScrollBy.invoke(mViewFlingerField.get(this), dx, dy, vx, vy); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } catch (NoSuchMethodException e) { e.printStackTrace(); return; } } catch (NoSuchFieldException e) { return; } } public void setCanTouchChangePage(boolean canTouchChangePage) { this.canTouchChangePage = canTouchChangePage; } private OnPagerChangedListener onPagerChangedListener; public void setOnPagerChangedListener(OnPagerChangedListener onPagerChangedListener) { this.onPagerChangedListener = onPagerChangedListener; } public interface OnPagerChangedListener { void onPagerChanged(int lastPosition, int position); } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/30 1:00:55

CNN-LSTM混合模型实现小时级天气预测实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/30 0:58:28

智慧城市低空应用AI安全框架解析

1. 智慧城市低空应用的安全挑战与机遇中国移动最新发布的《智慧城市低空应用人工智能安全白皮书》揭示了当前低空经济发展中的关键安全问题。随着无人机、空中机器人等低空智能设备在智慧城市中的广泛应用&#xff0c;其安全风险也日益凸显。这份白皮书系统性地梳理了低空应用面…

作者头像 李华
网站建设 2026/10/30 0:45:53

Hyperframes机器人坐标框架管理:ROS TF树集成与移动抓取实战

1. 先搞清楚hyperframes到底是啥我在帮实验室搭移动机械臂的时候第一次撞上“hyperframes”这个词&#xff0c;当时以为是某种新出的帧同步算法&#xff0c;翻了一圈资料才发现&#xff0c;在机器人圈子里它主要指的是ROS生态里一个专门管理坐标框架的工具包——Hyperframes&am…

作者头像 李华
网站建设 2026/10/30 0:45:41

Speech Beta:音频语义对齐的语音配乐技术突破

1. Speech Beta 不是“语音音乐”的简单拼接&#xff0c;而是音频语义对齐的工程突破最近刷到不少朋友转发 Suno 官方那条简短公告&#xff1a;“Speech Beta is live — generate speech with matching background music.” 表面看就是个带BGM的语音生成工具&#xff0c;但作为…

作者头像 李华
网站建设 2026/10/30 0:27:57

对称网络与奇偶模法:射频差分线设计与S参数降维实战

简介&#xff1a;这份PPT讲座文档面向微波工程、电磁场与信号处理方向的学习者与工程师&#xff0c;系统讲解对称网络与奇偶模法的核心理论及工程应用。内容从双端口、多端口及多对称性网络切入&#xff0c;重点剖析S矩阵与Y矩阵两种表示方法&#xff0c;并深入阐述偶模激励与奇…

作者头像 李华
网站建设 2026/10/30 0:24:31

Mem++:非破坏性组织级长期记忆基础设施

1. 这不是“记忆插件”&#xff0c;而是一套让大模型真正“记住事”的组织级基础设施最近在几个技术团队的内部分享会上&#xff0c;我反复被问到一个问题&#xff1a;“你们那个能长期记住项目细节、客户偏好、历史决策逻辑的LLM系统&#xff0c;底层到底是怎么存数据的&#…

作者头像 李华