zoukankan      html  css  js  c++  java
  • [Android UI]View滑动方式总结

    一、前言

      在上一篇文章,介绍了View的坐标等基础知识,有了基础知识后,对下面内容的理解也将会容易很多。那么本文介绍的是View滑动的几种方式,这对于View来说,也是需要重要掌握的内容,因为用户无时无刻不在与View打交道,而主要途径有滑动,比如说:界面的切换等。

    二、滑动方式

      在Android中,要滑动一个View有多种方式,下面就来介绍几种常用的方式以及他们的区别。

    1、使用scrollTo或scrollBy

      在View的源码中,提供了专门滑动View的方法,分别是scrollTo和scrollBy。顾名思义,scrollTo是滑动到某一坐标,是绝对滑动;而scrollBy是滑动一段距离,是相对滑动。而需要特别注意的是,这里用的两个方法,都是只改变View的内容的位置,实际上View的坐标并没有改变。为了说明这个问题,我们来看一下源码:

        /**
          * The offset, in pixels, by which the content of this view is scrolled
          * horizontally.
          * {@hide}
          */
            @ViewDebug.ExportedProperty(category = "scrolling")
            protected int mScrollX;
            protected int mScrollY;
        /**
          * Set the scrolled position of your view. This will cause a call to
          * {@link #onScrollChanged(int, int, int, int)} and the view will be
          * invalidated.
          * @param x the x position to scroll to
          * @param y the y position to scroll to
          */
            public void scrollTo(int x, int y) {
                if (mScrollX != x || mScrollY != y) {
                    int oldX = mScrollX;
                    int oldY = mScrollY;
                    mScrollX = x;
                    mScrollY = y;
                    invalidateParentCaches();
                    onScrollChanged(mScrollX, mScrollY, oldX, oldY);
                    if (!awakenScrollBars()) {
                        postInvalidateOnAnimation();
                    }
                }
            }
        /**
          * Move the scrolled position of your view. This will cause a call to
          * {@link #onScrollChanged(int, int, int, int)} and the view will be
          * invalidated.
          * @param x the amount of pixels to scroll by horizontally
          * @param y the amount of pixels to scroll by vertically
          */
            public void scrollBy(int x, int y) {
                scrollTo(mScrollX + x, mScrollY + y);
            }
    

      实际上scrollBy调用了scrollTo方法,我们只看scrollTo方法,在方法内部,没有涉及到我们上一篇文章说到了View的几个基本参数,而是使用了mScrollX、mScrollY这两个参数,那这两个参数表示的是什么呢?从源码的注释我们可以看出,这两个坐标是表示View内容的偏移量,并且单位是px,即mScrollX是等于View的左边缘和View内容左边缘在水平方向的距离,并且当View内容左边缘在View左边缘的右侧的时候,mScrollX为负,反之为正;同理,mScrollY是等于View的上边缘和View内容上边缘在数值方向的距离,并且Viwe内容上边缘在View上边缘下侧的时候,mScrollY为负,反之为正。为了方便理解,下面用几幅图描述mScrollX、mScrollY和View内容的关系:

      小结一下:对于View内容来说,从左往右滑,mScrollX为负;从上往下滑,mScrollY为负。

      那么,View和View内容有什么关系呢?可以这样想,对于一个View来说,是一个容器,而View内容是容器里面的东西。对于一个ViewGroup来说,那么它的内容是它的所有子View,那么如果在ViewGroup调用了scrollTo或者scrollBy,它的所有子View会同时移动。对于一个具体的View来说,比如说一个TextView,它的内容就是它里面的文字;对于一个ImageView,它的内容就是它里面的图片,诸如此类。

      这里给出滑动一个View的使用方法:

        TextView textview = (TextView) findViewById(R.id.textview);
        textview.scrollBy(-20,0)      //将textview里面的文字向右滑动20px
    

      总之,使用scrollTo和scrollBy滑动一个View的时候,View的布局参数(比如Top、Left、X、Y等)不会改变,改变的是View的内容位置。

    2、使用属性动画

      使用Android 3.0推出的属性动画,可以很轻松实现一个View的滑动:

        ObjectAnimator.ofFloat(view,"translationX",0,100).setDuration(500).start();
    

      对ofFloat方法的几个参数解释:第一个参数是要滑动的view;第二个参数是对view的某个参数进行改动,这里选择translationX,那么动画效果将作用于view的translationX参数,上一篇文章说到translationX代表view的偏移量,所以属性动画改变的是translationX和translationY值,而不是初始的Top、Left等值;最后两个参数表示前一个参数的起始值和最终值,这里指定为0和100,意思就是说translationX从0变到100。由于涉及到了View的基本参数,所以属性动画这种滑动方式改变的是View本身的位置。

    3、改变布局参数

      顾名思义,这个方法是直接对View的位置参数进行改变,即改变LayoutParams,下面给出一个示例再进行分析:

        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) imageView.getLayoutParams();  //获取imageView的布局参数
        params.leftMargin += 100;     //修改leftMargin的值,相当于xml布局文件中的margin_left的值
        imageView.setLayoutParams(params);  //将新的params值设置进imageView
    

      这里说明一下,对布局参数的改变,实际上是改变了View的top、left、right、bottom这四个初始坐标;然而在上一篇文章有说到,View在绘制完成后这四个初始值是不会改变的,那么是否是矛盾了呢?其实不是的,实际上setLayoutParams()对布局参数的改变,会触发View的重新测绘、布局、绘制这三个流程,那么这四个值也就随之改变了,关于View的三大工作流程,这里不详谈了,以后可能写View机制的源码分析的文章。

    4、使用layout()

      View在绘制的时候会调用layout()来确定View本身的位置,那么我们可以直接调用这个方法来绘制View:

        viwe.layout(int left,int top,int right,int bottom);
    

      一行代码即可调整View的位置了,注意到,以上都是view相对于父容器的坐标,View的位置的确定依赖于这四个坐标,如果这四个坐标不按照view自身的缩放比例设置,会造成View制图的缩放。比如说,一个View的宽和高都是100,选择的位移坐标是(50,50,100,100),那么显然view的宽和高就变成了50,即缩小了。所以如果为了View的正常滑动,一般可以将以上代码修改成如下:

        view.layout(view.getLeft()+offsetX,view.getTop()+offsetY,view.getRight()+offsetX,view.getBottom()+offsetY);
    

    5、使用 offsetLeftAndRight 和 offsetTopAndBottom

      直接调用View的offsetLeftAndRight(int offsetX)或者offsetTopAndBottom(int offsetY)能对view的四个坐标直接进行偏移,以达到移动view的目的。

        imageView.offsetLeftAndRight(50);  //将imageView沿水平正方向偏移50px
        imageView.offsetTopAndBottom(50); //将iamgeView沿竖直正方向偏移50px
    

      原理和onlayout方法差不多,也是导致了view的重新布局、绘制,所以基本参数坐标发生了变化。

    三、总结

      以上介绍了5种常见的view滑动方式,其实还有一种:scroller,这个将会在下一篇文章的弹性滑动中讲述这个类的用法,这里先总结上面说到的5种滑动方式的应用场景:

      ①scrollTo/scrollBy:只适合对view的内容的滑动

      ②属性动画:操作简单,功能强大,能实现复杂的动画效果,不建议用于有交互的View

      ③布局参数、layout、offsetLeftAndRight:适用于交互性强的View,对View的绘制原理应该有一定理解,这样使用的时候才会得心应手。

  • 相关阅读:
    Java实现 LeetCode 69 x的平方根
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 66 加一
    Java实现 LeetCode 66 加一
    CxSkinButton按钮皮肤类
  • 原文地址:https://www.cnblogs.com/zhousysu/p/5616307.html
Copyright © 2011-2022 走看看