View基础(二)之滑动
在Android
设备上,滑动几乎是应用的标配,不管是下拉刷新还是SlidingMenu
,它们的基础都是滑动。从另外一方面来说,Android
手机由于屏幕比较小,为了给用户呈现跟多的内容,就需要使用滑动来隐藏和显示一些内容。基于上述两点,可以知道滑动在Android
开发中具有很重要的作用。
View
的滑动有三种实现方式:
- 通过
View
本身提供的scrollTo
/scrollBy
方法。 - 通过动画给
View
施加平移效果来实现滑动。 - 通过改变
View
的LayoutParams
使得View
重新布局从而实现滑动。
下面来一一进行分析。
使用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;
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
则实现了基于所传递参数的绝对滑动。scrollTo
和scrollBy
都是改变通过View
内部的两个属性mScrollX
和mScrollY
来实现滑动的,这两个属性可以通过getScrollX
和getScrollY
方法得到,下面先简要概括一下:在滑动过程中,mScrollX
的值总是等于View
的左边缘和View
内容左边缘在水平方向的距离,而mScrollY
的值总是等于View
上边缘和View
内容上边缘在垂直方向的距离。
View
边缘是指View
的位置,由四个顶点组成,而View
内容边缘是指View
中的内容的边缘,scrollTo
和scrollBy
只能改变View
内容的位置而不能改变View
在布局中的位置。mScrollX
和mScrollY
的单位为像素,并且当View
左边缘在View
内容左边缘的右边时,mScrollX
为正值,反之为负值。换句话说,如果从左向右滑动,那么mScrollX
为负值,反之为正值;如果从上往下滑动,那么mScrollY
为负值,反之则为正值。
为了更好的理解这个问题,下面举个例子,如下图所示(蓝色表示View
的内容)。假设图中水平和竖直方向的滑动距离都为100像素,针对图中各种滑动情况,都给出了对应的mScrollX
和mScrollY
的值。
![](https://img.haomeiwen.com/i10149931/ba72502f346bf62f.png)
使用动画
通过动画我们能够让一个View
进行平移,而平移就是一种滑动。使用动画来移动View
,主要是操作View
的translationX
和translationY
属性,既可以采用传统的View
动画,也可以采用属性动画。
采用View
动画的代码如下所示。此动画可以在100ms内将一个View
从原始位置向右下角移动100个像素。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<translate
android:duration="100"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/linear_interpolator"
android:toXDelta="100"
android:toYDelta="100"/>
</set>
如果采用属性动画的话,就更简单了,以下代码可以将一个View
在100ms内从原始位置向右平移100像素。
ObjectAnimator.ofFloat(targetView,"translationX",0,100)
.setDuration(100).start();
上面简单介绍了通过动画来移动View
的方法,关于动画可以跳转至我的另一篇文章:Android动画(一)之View动画。使用动画来做View
的滑动需要注意一点,View
动画是对View
的影像做操作,它并不能改变View
的位置参数,包括宽/高,并且如果希望动画后的状态得以保留还必须将fillAfter
属性设置为true
,否则动画完成后其动画结果会消失,但是使用属性动画则不会存在这个问题。
上面提到了View
动画并不能真正改变View
的位置,这会带来一个很严重的问题。比如我们通过View
动画将一个Button
向右移动100px,并且这个View
设置有点击事件,那么当点击原始位置时,它的onclick
事件会被触发,单击新位置却不会触发,因为它的位置信息并不会随着动画而改变。如果想要解决这个问题可以改为使用属性动画(Android 3.0
之后的版本),或者在新位置创建一个的和原view
一样的view
,并且默认隐藏,当view
滑动之后再将其显示出来并隐藏原来的那个view
。
改变布局参数
改变布局参数,即改变LayoutParams
。例如我们想要将一个Button
向右平移100px,我们只需要将这个Button
的LayoutParams
里的marginLeft
参数的值增加100px即可。下面是示例代码:
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) button.getLayoutParams();
params.leftMargin += 100;
button.requestLayout();
//或者 button.setLayoutParams(params);
三种滑动方式的对比
先看scrollTo
/scrollBy
,它是View
提供的原生方法,专门用于View的滑动,但是它只能滑动View的内容,并不能滑动View本身。
再看动画,View
动画无法改变View
本身的属性,所以如果动画元素不需要响应用户的交互,那么使用动画是比较合适的。且动画还有一个很明显的优点:一些复杂的效果必须要通过动画才能实现。
最后来看改变布局方式,它除了使用起来麻烦点外,也明显的区别,它的主要适用对象是一些具有交互性的View
。
针对以上分析再做一下总结:
scrollTo
/scrollBy
:操作简单,适合对View
内容的滑动。- 动画:操作简单,主要适用于没有交互的
View
和实现复杂的动画效果。- 改变布局参数:操作稍微复杂,适用于有交互的
View
。