博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android View体系(二)实现View滑动的六种方法
阅读量:7088 次
发布时间:2019-06-28

本文共 7862 字,大约阅读时间需要 26 分钟。

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:
View Code

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;
View Code

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 Code

动画

可以采用View动画来移动,在res目录新建anim文件夹并创建translate.xml:
在Java代码中引用:mCustomView.setAnimation(AnimationUtils.loadAnimation(this, R.anim.translate));当然使用属性动画移动那就更简单了,我们让CustomView在1000毫秒内沿着X轴像右平移300像素:ObjectAnimator.ofFloat(mCustomView,"translationX",0,300).setDuration(1000).start();
View Code

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()方法,这样我们就通过不断的移动一个小的距离并连贯起来就实现了平滑移动的效果:@Overridepublic 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,0,delta,0,2000);      invalidate();}最后我们在ViewSlideActivity.java中调用CustomView的smoothScrollTo()方法://使用Scroll来进行平滑移动mCustomView.smoothScrollTo(-400,0);这里我们是设定CustomView沿着X轴向右平移400像素。
View Code

 

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(-400,0);    }}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,0,delta,0,2000);        invalidate();    }    @Override    public void computeScroll() {        super.computeScroll();        if(mScroller.computeScrollOffset()){            ((View) getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());            //通过不断的重绘不断的调用computeScroll方法            invalidate();        }    }}
View Code

 

转载地址:http://ngyql.baihongyu.com/

你可能感兴趣的文章
开机挂载文件系统
查看>>
万中选一,北京升哲科技荣获首个物联网行业 IDEA 金奖
查看>>
Spring常用属性的注入及属性编辑器
查看>>
C++11 function使用
查看>>
Matrix libraries for C and C++
查看>>
阿里云ECS、Redis再次降价 最高降幅35%
查看>>
JAVA 入坑教程 | 章节六 循环结构体
查看>>
物联网的应用会让黑客掌控一切吗?
查看>>
当当网Docker应用实践
查看>>
Docker数据安全隐患分析
查看>>
李包罗:撬动旧医疗体制的有力杠杆是什么?
查看>>
支付宝陷“隐私门”:加强监管避免隐私不当收集
查看>>
一个可能有用的封闭PGSQL操作的PYTHON函数
查看>>
落实网络安全法 多互联网公司推送个人信息保护条款
查看>>
这种口令解决方案可替代多因子验证
查看>>
区块链的业务价值是通过数据共享降低信任成本
查看>>
新华三G3系列服务器带来数据中心变革的新体验
查看>>
VMware收购Apteligent 借力移动应用管理强化云和终端用户计算
查看>>
下一代动态网络分析工具FakeNet-NG的Linux平台初体验
查看>>
戴尔安全简化融合网络的管理
查看>>