滑动效果是如何产生的?

滑动一个View从本质上来说就是移动一个View,改变其当前的坐标。所以,想要滑动一个View,就必须监听该View的触摸事件,并且根据事件的坐标,不断的改变View的坐标从而实现View的滑动。

Android中的坐标体系

Android中的坐标体系分为两种:

Android坐标系

视图坐标系

Android坐标系

Android坐标系

从图中我们可以看的出来**在Android坐标系中以屏幕的左上方作为坐标系的原点,从原点向右为X轴的正方向,向下为Y轴的正方向**。在触控事件中使用**getRawX()、getRawY()**来获得Android坐标系的坐标

视图坐标系

视图坐标系

视图坐标系主要描述的是该View和该View在父视图中的位置关系,和Android坐标系一样,也是以原点右方为X正方向,以原点下方为Y轴正方向,不过这里不是以屏幕的左上角为原点,而是**以父视图的左上角为原点**。在触控事件中使用**getX()、getY()**来获得视图坐标系的坐标

触控事件

在上一篇文章中我们使用到了MotionEvent,这个就是触控事件的封装,首先看一下MotionEvent中封装的事件常量

public static final int ACTION_DOWN = 0; //单点触摸按下动作

public static final int ACTION_UP = 1; //单点触摸离开动作

public static final int ACTION_MOVE = 2; //单点触摸移动动作

public static final int ACTION_CANCEL = 3; //触摸动作取消

public staiic final int ACTION_OUTSIDE = 4; //触摸动作超出边界

public static final int ACTION_POINTER_DOWN = 5; //多点触摸按下动作

public static final int ACTION_POINTER_UP = 6; 多点离开动作

通常情况下我们会在onTouchEvent(MotionEvent event)方法中通过event.getAction()来获取触控事件的类型。知道Android中的坐标系和触控事件之后我们就可以来实现View的滑动了

滑动实现

实现滑动有好多种方法,但是其思想都是一样的。当触摸到View时,记录当前触摸点的坐标,然后当手指移动时,获取到相对于前一个点的偏移量,这样我们就可以通过这个偏移量来进行修改View的坐标,这样不断的重复,就能实现View的滑动

举个例子

我们自定义一个View,让他来跟随我们手指的移动来移动,如图:

layout方法

我们知道在View进行绘制的时候会通过onLayout()方法来设置View的显示位置,这里我们通过修改View的left, top, right, bottom四个值来控制View的坐标

public boolean onTouchEvent(MotionEvent event) {

int x = (int) event.getX();

int y = (int) event.getY();

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

//记录触摸点的坐标

lastX = x;

lastY = y;

break;

case MotionEvent.ACTION_MOVE:

//计算偏移量

int offsetX = x - lastX;

int offsetY = y - lastY;

//在当前位置基础加上偏移量

layout(

getLeft() + offsetX,

getTop() + offsetY,

getRight() + offsetX,

getBottom() + offsetY

);

break;

}

return true;

}

offsetLeftAndRight()和offsetTopAndBottom

这个方法就是相当于系统提供的一个对左右、上下移动的API的封装,计算好偏移量后,调用方法即可:

offsetLeftAndRight(offsetX);

offsetTopAndBottom(offsetY);

LayoutParams

LayoutParams保存了View的布局参数,所以我们可以改变LayoutParams来动态的改变布局的位置来达到滑动的效果。在程序中使用getLayoutParams()来获取当前View的LayoutParams,这里就和上面一样,获取到偏移量后通过setLayoutParams来设置该View的LayoutParams:

RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) getLayoutParams();

params.leftMargin = getLeft() + offsetX;

params.topMargin = getTop() + offsetY;

setLayoutParams(params);

需要注意一点,通过getLayoutParams()获取LayoutParams的时候,要根据View的父布局的类型来设置,当然前提还要有一个父布局。还有就是我们可以使用ViewGroup.MarginLayoutParams,这样就不用考虑父布局是什么了

scrollTo、scrollBy

在View中,系统还提供了scrollTo、scrollBy两种方式来改变一个View的位置。

其中scrollTo表示移动到一个具体的坐标点,scrollBy表示移动的偏移量,其实在scrollBy内部也是调用的scrollTo。

和前面的方式一样,获取到偏移量后调用scrollBy来移动view,可是当我们运行程序,拖动View,发现View并没有移动!这是因为scrollTo、scrollBy方法移动的是View的内容,如果在ViewGroup中使用scrollTo、scrollBy的滑,那么移动的就是View了,但是如果在View中使用,那么移动的将是View里面的内容,比如TextView,那么移动的就是文本了。

所以通过上面的分析,我们把代码改为如下:

((View)getParent()).scrollBy(offsetX, offsetY);

再次运行程序,我们会发现动是动了,但是在乱动。因为这里我们其实是在相反的方向移动(这里由于篇幅限制,感兴趣的同学自行查找一下资料),我们把偏移量改为负的之后就会发现滑动正常了。

Scroller

首先来想一个场景:我们需要让一个Button向右面移动100个像素,如果我们用scrollTo/scrollBy的话,那么该View就会很突兀的移动到该点,没有过程,而Scroller则是可以实现平滑的过渡效果的

下面我们把上面跟随手指滑动的例子改一下,我们在松开手指后,View自动回到原点(屏幕左上角)。使用Scroller需要三个步骤

初始化

通过构造方法即可 Scroller mScroller = new Scroller(context);

重写computeScroll()方法,实现滑动

startScroll()开启滑动

代码如下:

case MotionEvent.ACTION_UP:

View viewGroup = (View) getParent();

mScroller.startScroll(

viewGroup.getScrollX(),

viewGroup.getScrollY(),

-viewGroup.getScrollX(),

-viewGroup.getScrollY()

);

invalidate();

break;

----------------------------------------------------------------

@Overrid

public void computeScroll() {

super.computeScroll();

if (mScroller.computeScrollOffset()) {

((View) getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());

invalidate();

}

}

当我们手指抬起来的时候开启Scroller滑动,获取到当前view的移动距离,然后我们把需要移动的偏移量设置为相反数就ok,最后调用invalidate来通知重绘,从而调用computeScroll()方法。运行程序如下:

现在就把这几种View的滑动都说完了,自己动手写一下,感触良多。

最后

爱生活,爱小丽,爱Android

android群英传 自定义滑动view,Android群英传学习之路-View的滑动相关推荐

  1. android项目中自定义顶部标题栏,Android项目中自定义顶部标题栏

    Android项目中自定义顶部标题栏 下面给大家详细介绍android中自定义顶部标题栏的思路及实现方式 先来图: 思路及实现步骤 1.定义标题栏布局 2.自定义TitleActivity控制标题栏按 ...

  2. android r.id 自定义,什么是“ android.R.id.text1”?

    什么是" android.R.id.text1"? 我是Android开发的新手. 在记事本示例中,我看到了以下代码片段: SimpleCursorAdapter adapter ...

  3. android 如何去掉自定义标签页,Android中为TextView增加自定义的HTML标签

    Android中的TextView,本身就支持部分的Html格式标签.这其中包括常用的字体大小颜色设置,文本链接等.使用起来也比较方便,只需要使用Html类转换一下即可.比如: textView.se ...

  4. android 虚拟按键自定义,如何适配Android底部虚拟按键

    前言 本文章只做一个记录,一个备忘,也为了更好的帮助他人,文章参考地址:Android适配底部虚拟按键的方法 问题说明 项目进行中需要透明渐变的状态栏,全屏显示,当然透明渐变好弄,方法有很多,但是如果 ...

  5. Android加载自定义字体出错,Android设置自定义字体的解决方案

    找了很多解决方案,但是都会报错,只好边借鉴着前辈们的思路,边自己尝试改代码了QWQ 前面准备:要先把使用的字体文件放入到工具中 新建一个名叫assets的文件夹,然后把字体文件复制到里面,如图 成功放 ...

  6. android tv 桌面,自定义RecyclerView打造Android TV桌面

    前言 Android TV Launcher页在RecyclerView出来之前大家用GridView去实现.TV开发有五向键的监听,遥控器hover监听,点击事件等.用GridView去处理焦点是有 ...

  7. android文本复制自定义剪切板,android 剪切板-文本复制、粘贴

    1. 粘贴-文本保存到剪切板中 ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Cont ...

  8. android键盘映射(转)-- good 1,android UI

    1.我们只有在button2使用了layout_weight属性,并赋值为1:但是button1和button2并没有使用这个属性,根据API可以知道,他们的layout_weight属性等于0. 2 ...

  9. Flutter Android app 修改启动背景颜色和logo——筑梦之路

    打开android\app\src\main\res\drawable\launch_background.xml, <?xml version="1.0" encoding ...

最新文章

  1. 开发日记-20190507 关键词 java通过id直接操作视图
  2. 动态规划 dp04 凸n边形的三角形划分 c代码
  3. Smarty目录结构和子目录路径问题
  4. SpringMVC自动配置
  5. 谷歌大脑推出视觉领域任务自适应基准:VTAB
  6. c++ 终止 超时_c++超时问题
  7. 机器学习基础(二)——词集模型(SOW)和词袋模型(BOW)
  8. 完整安装sqlserver always on集群
  9. 百度服务器临时文件多久一删,百度站长提醒:11月9日前尽快删除超出站点配额的历史sitemap文件...
  10. python核心编程---读书笔记:第18章 多线程编程
  11. ceph存储 PG的状态机和peering过程
  12. PhalApi框架新手脱坑笔记(一)
  13. Git 使用 stash暂存代码
  14. 02.配置免费图床Gitee/Github
  15. 【从零搭建后端基础设施系列(九)】-- VM容器化
  16. 在开课吧的Python学习
  17. 研发人员绩效考核工作失败的几方面表现
  18. data spring 指定时区_SpringBoot 相关时区(TimeZone)设置
  19. fluent旋转机械滑移网格法设置
  20. 局域网语音对讲系统_智慧医疗信息化系统建设(七):医院专业智能化

热门文章

  1. (UML两个汇总)九种图。
  2. 虚拟机四种网络连接模式比较
  3. 编写优美的GTest测试案例
  4. 自定义GridView 介绍
  5. Android应用开发-图片加载库Glide
  6. tcp建立连接为什么需要三次握手
  7. MySQL 之 索引
  8. 帮助文件html打不开,chm帮助文件打不开全是代码?这几种解决方法了解一下
  9. 博客地址 RSS地址
  10. mysql 8.0 yum_CentOS8 安装 MySQL8.0(yum)