Android View体系(二)实现View滑动的六种方法
1.View的滑动简介
View的滑动是Android实现自定义控件的基础,同时在开发中我们也难免会遇到View的滑动的处理。其实不管是那种滑动的方式基本思想都是类似的:当触摸事件传到View时,系统记下触摸点的坐标,手指移动时系统记下移动后的触摸的坐标并算出偏移量,并通过偏移量来修改View的坐标。
实现View滑动有很多种方法,这篇文章主要讲解六种滑动的方法,分别是:layout()、offsetLeftAndRight()与offsetTopAndBottom()、LayoutParams、动画、scollTo与scollBy和Scroller;在下一篇文章我们会详细介绍属性动画。
2.实现View滑动的六种方法
layout()
view进行绘制的时候会调用onLayout()方法来设置显示的位置,因此我们同样也可以通过修改View的left、top、right、bottom这四种属性来控制View的坐标。
首先我们要自定义一个View,在onTouchEvent()方法中获取触摸点的坐标:
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; 接下来我们在ACTION_MOVE事件中计算偏移量,再调用layout()方法重新放置这个自定义View的位置就好了
case MotionEvent.ACTION_MOVE:
//计算移动的距离
int offsetX = x - lastX;
int offsetY = y - lastY;
//调用layout方法来重新放置它的位置
layout(getLeft()+offsetX, getTop()+offsetY,
getRight()+offsetX , getBottom()+offsetY);
break; 当我们每次移动时都会调用layout()方法来对自己重新布局,从而达到移动View的效果。 自定义View的全部代码(CustomView.java):
public class CustomView extends View {
private int lastX;
private int lastY; public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
} public CustomView(Context context) {
super(context);
} 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方法来重新放置它的位置
layout(getLeft()+offsetX, getTop()+offsetY,
getRight()+offsetX , getBottom()+offsetY);
break;
} return true;
}
} 布局中引用自定义View:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <com.example.liuwangshu.moonviewslide.CustomView
android:id="@+id/customview"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="50dp"
android:background="@android:color/holo_red_light" />
</LinearLayout>
offsetLeftAndRight()与offsetTopAndBottom()
这两种方法和layout()方法效果方法差不多,使用也差不多,我们将ACTION_MOVE中的代码替换成如下代码:
case MotionEvent.ACTION_MOVE:
//计算移动的距离
int offsetX = x - lastX;
int offsetY = y - lastY;
//对left和right进行偏移
offsetLeftAndRight(offsetX);
//对top和bottom进行偏移
offsetTopAndBottom(offsetY);
break;
LayoutParams(改变布局参数)
LayoutParams主要保存了一个View的布局参数,因此我们可以通过LayoutParams来改变View的布局的参数从而达到了改变View的位置的效果。同样的我们将ACTION_MOVE中的代码替换成如下代码:
LinearLayout.LayoutParams layoutParams= (LinearLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);
动画
可以采用View动画来移动,在res目录新建anim文件夹并创建translate.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="" android:toXDelta="" android:duration=""/>
</set> 在Java代码中引用:
mCustomView.setAnimation(AnimationUtils.loadAnimation(this, R.anim.translate)); 当然使用属性动画移动那就更简单了,我们让CustomView在1000毫秒内沿着X轴像右平移300像素:
ObjectAnimator.ofFloat(mCustomView,"translationX",,).setDuration().start();
scollTo与scollBy
scollTo(x,y)表示移动到一个具体的坐标点,而scollBy(dx,dy)则表示移动的增量为dx、dy。其中scollBy最终也是要调用scollTo的。scollTo、scollBy移动的是View的内容,如果在ViewGroup中使用则是移动他所有的子View。我们将ACTION_MOVE中的代码替换成如下代码:
((View)getParent()).scrollBy(-offsetX,-offsetY);
Scroller
我们用scollTo/scollBy方法来进行滑动时,这个过程是瞬间完成的,所以用户体验不大好。这里我们可以使用Scroller来实现有过度效果的滑动,这个过程不是瞬间完成的,而是在一定的时间间隔完成的。Scroller本身是不能实现View的滑动的,它需要配合View的computeScroll()方法才能弹性滑动的效果。
在这里我们实现CustomView平滑的向右移动。
首先我们要初始化Scroller:
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
} 接下来重写computeScroll()方法,系统会在绘制View的时候在draw()方法中调用该方法,这个方法中我们调用父类的scrollTo()方法并通过Scroller来不断获取当前的滚动值,每滑动一小段距离我们就调用invalidate()方法不断的进行重绘,重绘就会调用computeScroll()方法,这样我们就通过不断的移动一个小的距离并连贯起来就实现了平滑移动的效果:
@Override
public void computeScroll() {
super.computeScroll();
if(mScroller.computeScrollOffset()){
((View) getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
//通过不断的重绘不断的调用computeScroll方法
invalidate();
}
} 调用Scroller.startScroll()方法。我们在CustomView中写一个smoothScrollTo()方法,调用Scroller.startScroll()方法,在2000毫秒内沿X轴平移delta像素:
public void smoothScrollTo(int destX,int destY){
int scrollX=getScrollX();
int delta=destX-scrollX;
//1000秒内滑向destX
mScroller.startScroll(scrollX,,delta,,);
invalidate();
} 最后我们在ViewSlideActivity.java中调用CustomView的smoothScrollTo()方法:
//使用Scroll来进行平滑移动
mCustomView.smoothScrollTo(-,); 这里我们是设定CustomView沿着X轴向右平移400像素。
3.完整代码:
public class ViewSlideActivity extends AppCompatActivity {
private CustomView mCustomView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_slide);
mCustomView= (CustomView) this.findViewById(R.id.customview);
//使用属性动画使view滑动
// ObjectAnimator.ofFloat(mCustomView,"translationX",0,300).setDuration(1000).start();
//使用View动画使view滑动
// mCustomView.setAnimation(AnimationUtils.loadAnimation(this, R.anim.translate));
//使用Scroll来进行平滑移动
mCustomView.smoothScrollTo(-,);
}
}
public class CustomView extends View {
private int lastX;
private int lastY;
private Scroller mScroller;
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
}
public CustomView(Context context) {
super(context);
}
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方法来重新放置它的位置
// layout(getLeft()+offsetX, getTop()+offsetY,
// getRight()+offsetX , getBottom()+offsetY);
//对left和right进行偏移
// offsetLeftAndRight(offsetX);
//对top和bottom进行偏移
// offsetTopAndBottom(offsetY);
//使用LayoutParams
// LinearLayout.LayoutParams layoutParams= (LinearLayout.LayoutParams) getLayoutParams();
// layoutParams.leftMargin = getLeft() + offsetX;
// layoutParams.topMargin = getTop() + offsetY;
// setLayoutParams(layoutParams);
//使用MarginLayoutParams
// ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
// layoutParams.leftMargin = getLeft() + offsetX;
// layoutParams.topMargin = getTop() + offsetY;
// setLayoutParams(layoutParams);
//使用scrollBy
((View)getParent()).scrollBy(-offsetX,-offsetY);
break;
}
return true;
}
public void smoothScrollTo(int destX,int destY){
int scrollX=getScrollX();
int delta=destX-scrollX;
//1000秒内滑向destX
mScroller.startScroll(scrollX,,delta,,);
invalidate();
}
@Override
public void computeScroll() {
super.computeScroll();
if(mScroller.computeScrollOffset()){
((View) getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
//通过不断的重绘不断的调用computeScroll方法
invalidate();
}
}
}
Android View体系(二)实现View滑动的六种方法的更多相关文章
- android中实现view可以滑动的六种方法续篇(二)
承接上一篇,上一篇中讲解了实现滑动的第五种方法,如果你还没读过,可点击下面链接: http://www.cnblogs.com/fuly550871915/p/4985482.html 这篇文章现在来 ...
- android中实现view可以滑动的六种方法
在android开发中,经常会遇到一个view需要它能够支持滑动的需求.今天就来总结实现其滑动的六种方法.其实每一种方法的 思路都是一样的,即:监听手势触摸的坐标来实现view坐标的变化,从而实现vi ...
- android中实现view可以滑动的六种方法续篇(一)
承接上一篇,如果你没有读过前四章方法,可以点击下面的链接: http://www.cnblogs.com/fuly550871915/p/4985053.html 下面开始讲第五中方法. 五.利用Sc ...
- 《Android进阶之光》--View体系与自定义View
No1: View的滑动 1)layout()方法的 public class CustomView extends View{ private int lastX; private int last ...
- View体系第二篇:View滑动
View滑动的基本思想:当点击事件传到View时,系统记下触摸点的坐标,手指移动时系统记下触摸后的坐标并计算出偏移量,然后根据偏移量修正View坐标. 实现View滑动共有6种方法:layout()方 ...
- Android动画之二:View Animation
作为一个博客<Android其中的动画:Drawable Animation>.android动画主要分为三大部分.上一篇博客已经解说Drawable Animation的使用方法,即逐帧 ...
- Android View体系(四)从源码解析Scroller
在Android View体系(二)实现View滑动的六种方法这篇文章中我们讲到了用Scroller来实现View的滑动,所以这篇文章我们就不介绍Scroller是如何使用的了,本篇就从源码来分析下S ...
- Android View体系(八)从源代码解析View的layout和draw流程
相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源 ...
- Android View体系(十)自定义组合控件
相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源 ...
随机推荐
- Spring boot MultipartResolver
[参考文章]:Required MultipartFile parameter 'file' is not present [参考文章]:Springboot2.0中WebMvcConfigurerA ...
- es 基于match_phrase的模糊匹配原理及使用
[版权声明]:本文章由danvid发布于http://danvid.cnblogs.com/,如需转载或部分使用请注明出处 在业务中经常会遇到类似数据库的"like"的模糊匹配需求 ...
- pycharm中可以运行脚本但是不能debug脚本
以前用的时候好好地,但是最近上班突然脚本就不能debug了,debug直接报错,如下所示 上网查过该有的原因: 1.在pycharm中两个地方设置成utf-8,页面右下角和File>settin ...
- 《ASP.NET Core跨平台开发从入门到实战》Web API自定义格式化protobuf
<ASP.NET Core跨平台开发从入门到实战>样章节 Web API自定义格式化protobuf. 样章 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于 ...
- Java RMI HelloWorld
Java RMI HelloWorld RMI 远程方法调用. 顾名思义就是可以像调用本地程序方法一样调用远程(其他JVM)的程序方法. 分为3个部分: Stub:中介,代理. 封装了远程对象 ...
- js实现深拷贝的一些方法
在ECMAScript变量中包含两种不同类型的值:基本类型值和引用类型值. 基本类型值:Undefined.Null.Boolean.Number.String 引用类型值:Object.Array. ...
- salesforce零基础学习(九十)项目中的零碎知识点小总结(三)
本次的内容其实大部分人都遇到过,也知道解决方案.但是因为没有牢记于心,导致问题再次出现还是花费了一点时间去排查了原因.在此记录下来,好记性不如烂笔头,争取下次发现类似的现象可以直接就知道原因.废话少说 ...
- 独享锁 & 共享锁
独享锁(互斥锁):同时只能有一个线程获得锁.比如,ReentrantLock 是互斥锁,ReadWriteLock 中的写锁是互斥锁. 共享锁:可以有多个线程同时获得锁.比如,Semaphore.Co ...
- 猪圈密码 摩斯密码 QWE加密 栅栏加密 当铺密码
1.猪圈密码 猪圈密码:对应下图就是HORSE 2.摩斯密码 在线摩斯密码翻译器:http://www.mathsking.net/morse.htm 3.QWE加密 键盘按ABC的顺序排列得到对应的 ...
- SpringMVC+jquery.uploadify 上传文件
前言 以前用Asp.net MVC+uploadify上传文件,最近学习SpringMVC,所以就用SpringMVC+uploadify做个上传文件的demo. 刚开始用form表单的方式提交,在C ...