在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时关于焦点颜色的设置问题
# 我们可以
# 的是
# 可以通过
# 是在
# 想让
# 方法来
# 都是
# 当我们
# 在上面
# 偏移量
# 也会
# 出了
# 上一
# 瞬间
# 它可以
# 可以看出
# 触控
# 可以实现
# 种方法
# 两张
相关文章:
小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?
C++ static_cast和dynamic_cast区别_C++静态转换与动态类型安全转换
三星网站视频制作教程下载,三星w23网页如何全屏?
北京企业网站设计制作公司,北京铁路集团官方网站?
黑客如何利用漏洞与弱口令入侵网站服务器?
英语简历制作免费网站推荐,如何将简历翻译成英文?
javascript中对象的定义、使用以及对象和原型链操作小结
logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?
招贴海报怎么做,什么是海报招贴?
网站制作网站,深圳做网站哪家比较好?
在线ppt制作网站有哪些软件,如何把网页的内容做成ppt?
如何配置IIS站点权限与局域网访问?
学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?
公众号网站制作网页,微信公众号怎么制作?
建站之星安装失败:服务器环境不兼容?
如何在Windows虚拟主机上快速搭建网站?
如何解决VPS建站LNMP环境配置常见问题?
广州网站设计制作一条龙,广州巨网网络科技有限公司是干什么的?
Android自定义listview布局实现上拉加载下拉刷新功能
专业制作网站的公司哪家好,建立一个公司网站的费用.有哪些部分,分别要多少钱?
如何规划企业建站流程的关键步骤?
如何解决ASP生成WAP建站中文乱码问题?
如何在Golang中使用replace替换模块_指定本地或远程路径
如何在搬瓦工VPS快速搭建网站?
C#如何使用XPathNavigator高效查询XML
建站与域名管理如何高效结合?
如何通过云梦建站系统实现SEO快速优化?
如何处理“XML格式不正确”错误 常见XML well-formed问题解决方法
盘锦网站制作公司,盘锦大洼有多少5G网站?
宝塔面板创建网站无法访问?如何快速排查修复?
如何高效配置香港服务器实现快速建站?
上海制作企业网站有哪些,上海有哪些网站可以让企业免费发布招聘信息?
整人网站在线制作软件,整蛊网站退不出去必须要打我是白痴才能出去?
零服务器AI建站解决方案:快速部署与云端平台低成本实践
如何生成腾讯云建站专用兑换码?
宠物网站制作html代码,有没有专门介绍宠物如何养的网站啊?
香港服务器网站搭建教程-电商部署、配置优化与安全稳定指南
建站DNS解析失败?如何正确配置域名服务器?
标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?
购物网站制作公司有哪些,哪个购物网站比较好?
建站之星上传入口如何快速找到?
建站VPS配置与SEO优化指南:关键词排名提升策略
如何快速选择适合个人网站的云服务器配置?
如何用低价快速搭建高质量网站?
实现点击下箭头变上箭头来回切换的两种方法【推荐】
矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
建站为何优先选择香港服务器?
重庆市网站制作公司,重庆招聘网站哪个好?
开封网站制作公司,网络用语开封是什么意思?
*请认真填写需求信息,我们会在24小时内与您取得联系。