View的滑动

来源:互联网 发布:计算机二级考试vb题库 编辑:程序博客网 时间:2024/05/15 02:36

        滑动在Android开发中具有很重要的作用,不管一些滑动效果多么绚丽,归根结底,它们都是由不同的滑动外加一些特效所组成的。因此,掌握滑动的方法是实现绚丽的自定义控件的基础。通过三种方式可以实现View的滑动:

    • 第一种是通过View本身提供的scrollTo/scrollBy方法来实现滑动;
    • 第二种是通过动画给View施加平移效果来实现滑动;
    • 第三种是通过改变View的LayoutParams使得View重新布局从而实现滑动。

        从目前来看,常见的滑动方式就这么三种,下面一一进行分析。



1.使用 scrollTo/scrollBy


        为了实现View的滑动,View提供了专门的方法来实现这个功能,那就是scrollTo和scrollBy,我们先来看看这两个方法的实现,如下所示。


/**    * 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;//已经滑动到的X            int oldY = mScrollY;//已经滑动到的Y            mScrollX = x;            mScrollY = y;            onScrollChanged(mScrollX, mScrollY, oldX, oldY);//调用说明状态改变            if (!awakenScrollBars()) {                invalidate();//通知视图进行重绘            }        }    }  /**     * 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则实现了基于所传递参数的绝对滑动,这个不难理解。利用scrollTo和scrollBy来实现View的滑动,这不是一件困难的事,但是我们要明白滑动过程中View内部的两个属性mScrollX和mScrollY的改变规则,这两个属性可以通过getScrollX和getScrollY方法分别得到。这里先简要概况一下:在滑动过程中,mScrollX的值总是等于View左边缘和View内容左边缘在水平方向的距离,而mScrollY的值总是等于View上边缘和View内容上边缘在竖直方向的距离。View边缘是指View的位置,由四个顶点组成,而View内容边缘是指View中的内容的边缘,scrollTo和scrollBy只能改变View内容的位置而不能改变View在布局中的位置。mScrollX和mScrollY的单位为像素,并且当View左边缘在View内容左边缘的右边时,mScrollX为正值,反之为负值;当View上边缘在View内容上边缘的下边时,mScrollY为正值,反之为负值。换句话说,如果从左向右滑动,那么mScrollX为负值,反之为正值;如果从上往下滑动,那么mScrollY为负值,反之为正值。

       为了更好地理解这个问题,下面举个例子,如下图所示。在图中假设水平和竖直方向的滑动距离都为100像素,针对图中各种滑动情况,都给出了对应的mScrollX和mScrollY的值。根据上面的分析,可以知道,使用scrollTo和scrollBy来实现View的滑动,只能将View的内容进行移动,并不能将View本身进行移动,也就是说,不管怎么滑动,也不可能将当前View滑动到附近View所在的区域,这个需要仔细体会一下。






2.使用动画


          Android动画可以分为两类,最初的传统动画和Android3.0 之后出现的属性动画传统动画又包括 帧动画(Frame Animation)和补间动画(Tweened Animation)。这里可以使用补间动画实现100ms内将一个View从原始位置向右下角移动100个像素。

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"    android:fillAfter="true"    android:zAdjustment="normal" >        <translateandroid:duration="100"android:fromXDelta="0"        android:toXDelta="100"        android:fromYDelta="0"        android:toYDelta="100" />    </set>

如果采用属性动画的话,就更简单了,以下代码可以将一个View在100ms内从原始位置向右平移100像素。

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


        使用动画来做View的滑动需要注意一点,View动画是对View的影像做操作,它并不能真正改变View的位置参数,包括宽/高,并且如果希望动画后的状态得以保留还必须将fillAfter属性设置为true,否则动画完成后其动画结果会消失。比如我们要把View向右移动100像素,如果fillAfter为false,那么在动画完成的一刹那,View会瞬间恢复到动画前的状态;如果fillAfter为true,在动画完成后,View会停留在距原始位置100像素的右边。使用属性动画并不会存在上述问题,但是在Android 3.0以下无法使用属性动画,这个时候我们可以使用动画兼容库nineoldandroids来实现属性动画。
       上面提到补间动画并不能真正改变View的位置,这会带来一个很严重的问题。试想—下,比如我们通过补间动画将一个Button向右移动100px,并且这个View设置的有单击事件,然后你会惊奇地发现,单击新位置无法触发onClick事件,而单击原始位置仍然可以触发onClick事件,尽管Button己经不在原始位置了。这个问题带来的影响是致命的,但是它却又是可以理解的,因为不管Button怎么做变换,但是它的位置信息(四个顶点和宽/高)并不会随着动画而改变,因此在系统眼里,这个Button并没有发生任何改变,它的真身仍然在原始位置。在这种情况下,单击新位置当然不会触发onClick事件了,因为Button的真身并没有发生改变,在新位置上只是View的影像而已。基于这一点,我们不能简单地给一个View做平移动画并且还希望它在新位置继续触发一些单击事件。属性动画才是真正的实现了view的移动,补间动画对view的移动更像是在不同地方绘制了一个影子,实际的对象还是处于原来的地方。

3.改变布局的参数


        比如我们想把一个Button向右平移100px,我们只需要将这个Button的LayoutParams里的marginLeft参数的值增加100px即可,是不是很简单呢?还有一种情形,为了达到移动Button的目的,我们可以在Button的左边放置一个空的View,这个空View的默认宽度为0,当我们需要向右移动Button时,只需要重新设置空View的宽度即可,当空View的宽度增大时(假设Button的父容器是水平方向的LinearLayout),Button就自动被挤向右边,即实现了向右平移的效果。如何重新设置一个View的LayoutParams呢?很简单,如下所示。

MarginLayoutParams params = (MarginLayoutParams)mButtonl.getLayoutParams();params.width +=100;params.leftMargin += 100;mButtonl.requestLayout();//或者 mButtonl .setLayoutParams (params);



原创粉丝点击