Android中实现滑动的七种方式总结
发布时间 - 2026-01-10 22:57:46 点击率:次在Android中想要实现实现滑动有很多方法,这篇博客将提供一些实现滑动的思路,希望可以帮助到有需要的人。

一、Android坐标体系
在讲解滑动之前,我们有必要简单提一下Android的坐标体系,因为滑动的实质就是坐标的不断改变,所以我们先来了解一下Android坐标系和视图坐标系两个概念。直接放上两张图片吧,一目了然。
Android坐标系
视图坐标系
从上面的两张图可以看出,Android坐标系的坐标原点位于屏幕的左上角,而视图坐标系的原点位于父视图的左上角,既然提供了两种不同的坐标系,那么我们如何来获取坐标呢,Android已经给我们提供了一些方法用于获取这些坐标,看下面的图便一目了然。
Android获取坐标的各种方法
二、layout方法
在View进行绘制时,是调用onLayout()方法来确定View的位置的,同样我们也可以调用layout()方法来传入我们滑动后的坐标便可以实现View的滑动,当然坐标的获取我们可以在触控事件中进行获取,下面我们做一个View随手指进行滑动的小例子来进行说明。
public class DragView extends View {
private int mLastX;
private int mLastY;
public DragView(Context context) {
this(context, null);
}
public DragView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DragView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
int lastX = 0, lastY = 0;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mLastX = x;
mLastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offsetX = x - mLastX;
int offsetY = y - mLastY;
layout(getLeft() + offsetX, getTop() + offsetY,
getRight() + offsetX, getBottom() + offsetY);
break;
}
return true;
}
}
上面我们在触控事件中获取到获取到手指按下时的坐标(lastX, lastY),然后在手指移动时不断计算X和Y方向上的偏移量,然后再调用layout()方法来改变View的位置从而实现滑动。当然上面我们是通过getX()和getY()来获取视图坐标来进行修改,我们也可以通过getRawX()和getRawY()来获取绝对坐标来实现上面的效果。代码如下:
private int mLastX;
private int mLastY;
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getRawX();
int y = (int) event.getRawY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mLastX = x;
mLastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offsetX = x - mLastX;
int offsetY = y - mLastY;
layout(getLeft() + offsetX, getTop() + offsetY,
getRight() + offsetX, getBottom() + offsetY);
//重新设置初始坐标
mLastX = x;
mLastY = y;
break;
}
return true;
}
上面一定要注意,我们在改变完View的位置后必须调用设置初始坐标,这样才能准确获取偏移量。
三、offsetLeftAndRight和offsetTopAndBottom
这一种方法和上一种方法大部分步骤都是相同的,只是在移动View上有所差别,代码如下:
offsetLeftAndRight(offsetX); offsetTopAndBottom(offsetY);
上面的这种方法只是多了一层封装,可以实现比上面实现同样的效果。
四、设置LayoutParams
LayoutParams可以通过改变的布局参数,我们可以通过下面的代码实现上面同样的效果。
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams(); layoutParams.leftMargin = getLeft() + offsetX; layoutParams.topMargin = getTop() + offsetY; setLayoutParams(layoutParams);
注意:我们的LayoutParams可以通过getLayoutParams()方法来获取,但是要注意,如果View的父布局是LinearLayout,那么我们的LayoutParams就是LinearLayout.LayoutParams,如果View的父布局是RelativeLayout,则我们的LayoutParams就是RelativeLayout.LayoutParams。当然我们还有一种简单的方法,不用再管父布局的布局方式。代码如下:
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams(); marginLayoutParams.leftMargin = getLeft() + offsetX; marginLayoutParams.topMargin = getTop() + offsetY; setLayoutParams(marginLayoutParams);
上面的这种方法不用管父布局的类型,使用起来更加方便。
五、scrollTo和scrollBy方法
关于这两个方法我们需要仔细说一下其中的一些注意事项
1 . scrollTo的参数是具体的一个坐标点(x, y), 而scrollBy的参数是在x, y方向上的坐标偏移
2 . scrollTo和scrollBy移动的是View的内容。这一点很重要!!!!
如果我们对ViewGroup使用scrollTo和scrollBy则移动的是内部的所有子View, 如果对TextView使用scrollTo和scrollBy则移动的是其中额文本。
3 . 视图移动还有一个不太好理解的地方在于坐标,我们下面结合图片来说明一下:
视图移动1
视图移动2
我们可以这样理解,我们的手机屏幕作为一个盖板,在手机屏幕下面是一个巨大的画布,我们的手机屏幕这个盖板是透明的,导致只有和手机屏幕重合的画布部分才会被我们看到,我们调用scrollTo和scrollBy也可以理解为是在移动手机上面的盖板。如图中所示,按钮在ViewGroup中的坐标是(20, 10),当我们调用scrollBy(20, 10)之后,就相当于移动了屏幕上的盖板,然后我们看到的按钮就到了ViewGroup的左上角。这样如果我们想让按钮在水平和竖直方向上各移动20和10个单位,我们就必须调用scrollBy(-20, -10)
经过了上面的知识准备,我们这里也使用scrollBy来实现前面实现的那个View随手指移动的小例子:
((View)getParent()).scrollBy(-offsetX, -offsetY);
六、使用Scroller
Scroller也是滑动中很重要的一个角色,进过前面的scrollTo和scrollBy大家也会发现,它们的移动时瞬间完成的,滑动显得十分突兀,Google为了改善用户体验,便给出了Scroller,它可以实现平滑的移动,从而使滑动过程更加真实,用户体验更好,下面我们先简单说说Scroller的实现原理。
Scroller也是滑动中很重要的一个角色,进过前面的scrollTo和scrollBy大家也会发现,它们的移动时瞬间完成的,滑动显得十分突兀,Google为了改善用户体验,便给出了Scroller,它可以实现平滑的移动,从而使滑动过程更加真实,用户体验更好,下面我们先简单说说Scroller的实现原理。
Scroller的实现方式类似于scrollTo和scrollBy,scrollTo和scrollBy的移动都是从一个坐标点瞬间移动到另一个左边点,而Scroller则是将移动的这段距离切分成好几段的微小的位移,然后每一段调用scrollTo来不断移动这些微小的位移,由于人眼的视觉暂留效果,就会给人平滑移动的视觉效果。
下面我们在上一步的基础上增加一个小功能,第一部分还是View随手指移动,但是当我们松开手指时,让View自己平滑移动到最初始的位置(屏幕左上角),下面我们就来一步步介绍Scroller的用法
1 . 声明Scroller变量,并在构造方法中进行初始化
2 . 在触控事件的ACTION_UP(手指抬起)事件中传入开始滑动的坐标和需要滑动的距离并触发Scroller的滑动事件
3 . 重写computeScroll(),实现真正的滑动
下面是完整的代码示例:
public class DragView extends View {
private int mLastX;
private int mLastY;
//声明Scroller变量
private Scroller mScroller;
public DragView(Context context) {
this(context, null);
}
public DragView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DragView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//在构造方法中初始化Scroller变量
mScroller = new Scroller(context);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getRawX();
int y = (int) event.getRawY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mLastX = x;
mLastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offsetX = x - mLastX;
int offsetY = y - mLastY;
//实现View跟随手指移动的效果
((View)getParent()).scrollBy(-offsetX, -offsetY);
//重新设置初始坐标
mLastX = x;
mLastY = y;
break;
case MotionEvent.ACTION_UP:
//当手指抬起时执行滑动过程
View view = (View) getParent();
mScroller.startScroll(view.getScrollX(), view.getScrollY(),
view.getScrollX(), view.getScrollY(), 5000);
//调用重绘来间接调用computeScroll()方法
invalidate();
break;
}
return true;
}
@Override
public void computeScroll() {
super.computeScroll();
//判断滑动过程是否完成
if (mScroller.computeScrollOffset()){
((View)getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
//通过重绘来不断调用computeScroll()方法
invalidate();
}
}
}
上面的代码View随手指移动的代码部分是与前面相同的,我们只说说Scroller的部分以及一些注意事项
1 . startScroll()方法各参数的意义,我们可以看看下面的源码:
/** * Start scrolling by providing a starting point, the distance to travel, * and the duration of the scroll. * * @param startX Starting horizontal scroll offset in pixels. Positive * numbers will scroll the content to the left. * @param startY Starting vertical scroll offset in pixels. Positive numbers * will scroll the content up. * @param dx Horizontal distance to travel. Positive numbers will scroll the * content to the left. * @param dy Vertical distance to travel. Positive numbers will scroll the * content up. * @param duration Duration of the scroll in milliseconds. */ public void startScroll(int startX, int startY, int dx, int dy, int duration)
可以看出startX和startY参数就是开始滚动的(x, y)坐标,那么我们就可以通过ViewGroup(子View的父视图)的getScrollX()和getScrollY()来获取,这里一定要注意,我们在滑动时的content就是子View,所以我们通过子View的父视图(ViewGroup)的getScrollX()和getScrollY()获取到的就是子View在X和Y方向上滑动的距离,即就是我们需要的当我们手指抬起时子View的(x, y)坐标。而如果我们对子View调用getScrollX()和getScrollY()方法,则获得的是子View内部的视图的滑动距离及坐标。
dx和dy分别是在X和Y方向上的偏移量,而且注释中说了,如果我们传入的dx和dy的值是正值,那么将会向上向左移动这个content(其实就是我们这里的View),即我们就可以让子View回到左上角,这里我们还是可以借助于上一小节中提到的视图移动的概念,我们想让子View向坐上方移动,其实就是想让覆盖在上面的盖板向右下角移动,我们可以将dx和dy理解为父视图(覆盖在上面的盖板)的偏移量。
假设我们刚开始是让子View随手指向右下方移动,那么相当于覆盖在上面的盖板是向左上方移动,所以我们通过getScrollX()和getScrollY()获得的值是负值,我们现在松开手指想让子View向左上方移动(即回到屏幕左上角),那么就相当于盖板向右下角移动,所以我们的dx和dy的值必须是-getScrollX()和-getScrollY(),此时的两个值都是正值。
2 . 由于我们的computeScroll()方法不会主动调用,但是我们又需要它不断调用从而不断进行微小移动从而实现平滑的滑动,所以我们可以通过下面的方法。
这三个按照以下顺序进行调用 invalidate()--->onDraw()--->computeScroll(),所以我们可以可以在ACTION_UP中调用完startScroll()方法后调用invalidate()方法,然后在computeScroll()方法中判断滑动是否结束,如果没结束,则通过getCurrX()和getCurrY()来获得当前需要移动的微小的位移的坐标点,然后传入scrollTo()方法中,这时候子View还只是移动了一小段距离,然后我们再次调用invalidate()方法,然后接着调用onDraw()方法,然后再次进入computeScroll()中再次让子View移动一小段距离,直到滑动结束,computeScrollOffset()返回false,则这个循环调用的过程结束,从而完成平滑移动的过程。
七、属性动画
属性动画一样可以实现View的滑动,但是由于属性动画涉及到的知识点也是众多,这里不再展开来写,只是提供一个思路,后续后专门写一篇博客来说。
八、ViewDragHelper
ViewDragHelper可以帮助我们实现各种滑动需求,但是它的使用也相对较复杂,所以准备专门写一篇博客来介绍他,这里只是给出一个概念
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# android实现滑动
# android实现页面滑动
# Android ListView的OnItemClickListener详解
# Android 中ListView setOnItemClickListener点击无效原因分析
# android post请求接口demo
# Android实现屏蔽微信拉黑和删除联系人功能示例
# Android中Fab(FloatingActionButton)实现上下滑动的渐变效果
# 超简单实现Android自定义Toast示例(附源码)
# Android 仿微信聊天时间格式化显示功能
# Android 处理OnItemClickListener时关于焦点颜色的设置问题
# 我们可以
# 的是
# 可以通过
# 是在
# 想让
# 方法来
# 都是
# 当我们
# 在上面
# 偏移量
# 也会
# 出了
# 上一
# 瞬间
# 它可以
# 可以看出
# 触控
# 可以实现
# 种方法
# 两张
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何在服务器上配置二级域名建站?
Win11任务栏卡死怎么办 Windows11任务栏无反应解决方法【教程】
MySQL查询结果复制到新表的方法(更新、插入)
网站制作怎么样才能赚钱,用自己的电脑做服务器架设网站有什么利弊,能赚钱吗?
详解Nginx + Tomcat 反向代理 负载均衡 集群 部署指南
Laravel如何实现全文搜索功能?(Scout和Algolia示例)
Laravel如何处理JSON字段的查询和更新_Laravel JSON列操作与查询技巧
Laravel中间件如何使用_Laravel自定义中间件实现权限控制
Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】
如何在浏览器中启用Flash_2025年继续使用Flash Player的方法【过时】
大型企业网站制作流程,做网站需要注册公司吗?
手机怎么制作网站教程步骤,手机怎么做自己的网页链接?
企业网站制作这些问题要关注
Claude怎样写结构化提示词_Claude结构化提示词写法【教程】
Windows家庭版如何开启组策略(gpedit.msc)?(安装方法)
微信推文制作网站有哪些,怎么做微信推文,急?
JavaScript模板引擎Template.js使用详解
湖南网站制作公司,湖南上善若水科技有限公司做什么的?
智能起名网站制作软件有哪些,制作logo的软件?
html5如何实现懒加载图片_ intersectionobserver api用法【教程】
百度浏览器网页无法复制文字怎么办 百度浏览器复制修复
Linux系统命令中screen命令详解
头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?
关于BootStrap modal 在IOS9中不能弹出的解决方法(IOS 9 bootstrap modal ios 9 noticework)
如何用已有域名快速搭建网站?
Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】
胶州企业网站制作公司,青岛石头网络科技有限公司怎么样?
Chrome浏览器标签页分组怎么用_谷歌浏览器整理标签页技巧【效率】
如何用好域名打造高点击率的自主建站?
通义万相免费版怎么用_通义万相免费版使用方法详细指南【教程】
如何在局域网内绑定自建网站域名?
JavaScript如何实现错误处理_try...catch如何捕获异常?
制作旅游网站html,怎样注册旅游网站?
如何用花生壳三步快速搭建专属网站?
Laravel如何实现用户密码重置功能?(完整流程代码)
Laravel如何设置定时任务(Cron Job)_Laravel调度器与任务计划配置
JavaScript实现Fly Bird小游戏
Laravel如何使用Service Container和依赖注入?(代码示例)
Android滚轮选择时间控件使用详解
Laravel如何使用Telescope进行调试?(安装和使用教程)
百度浏览器如何管理插件 百度浏览器插件管理方法
Laravel如何部署到服务器_线上部署Laravel项目的完整流程与步骤
Laravel如何实现文件上传和存储?(本地与S3配置)
Laravel怎么连接多个数据库_Laravel多数据库连接配置
高防服务器租用如何选择配置与防御等级?
猎豹浏览器开发者工具怎么打开 猎豹浏览器F12调试工具使用【前端必备】
Laravel怎么清理缓存_Laravel optimize clear命令详解
音乐网站服务器如何优化API响应速度?
Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解
Laravel如何实现图片防盗链功能_Laravel中间件验证Referer来源请求【方案】

