scrollTo()与scrollBy()是View提供于实现滑动的方法,其中scrollBy()内部调用了scrolTo()。scrollTo()是移动到具体座标,scrollBy()是在当前情况下根据传入的偏移量移动。
/**
* 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);
}
/**
* 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();
}
}
}
首先我们要清楚,这两个方法滑动的是View的内容。为了更好地理解,请看下面例子。
在布局中设置一个TextView,给它设置文字,宽高(文字不要充满宽高),再设置一个按钮,当点击按钮时,TextView调用 scrollBy()。代码如下:
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="15dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_scroll"
android:layout_gravity="center"
android:text="我是TextView"
android:textColor="#000000"
android:textSize="28sp"
android:background="#B4AFAF"
android:layout_width="200dp"
android:layout_height="200dp" />
<Button
android:id="@+id/bt_scroll"
android:layout_gravity="center"
android:text="scrollBy"
android:textSize="20sp"
android:textAllCaps="false"
android:layout_width="200dp"
android:layout_height="80dp" />
</LinearLayout>
MainActivity代码:
public class MainActivity extends AppCompatActivity {
TextView tv;
Button bt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = findViewById(R.id.tv_scroll);
bt = findViewById(R.id.bt_scroll);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tv.scrollBy(0,-10);
}
});
}
}
效果如下:
可以看到,TextView调用scrollBy()方法,本身位置并没有移动,移动的是文字内容,即View的内容,我理解为View的画布,由于文字是绘制在画布上的,移动画布,文字也跟着移动了。
上面代码中我们调用scrollBy(0,-10),文字往下移动,这似乎与我们预想的不同。我们都知道android座标系中均为左负右正,上负下正,正常情况下,y方向输入-10,应该往上移动,但结果却相反。这就是scrollTo(0 / scrollBy() 比较难理解的地方。
如何理解呢,经过上面的例子我们知道scrollBy / scrollTo()移动的是View的内容,那么scrollTo()所传入的座标以及scrollBy()传入的偏移量,所作用的应该也是View的内容(画布),下面用两张图来帮助理解。在一开始,view的内容还没移动时,画布的(0,0)座标是与View边框的左上角对齐。(绿色方框表示View的大小,其余表示画布)
当调用scrolTo(-15,-10)时,会将画布的(-15,-10)座标与View边框的左上角对齐。(移动是画布,TextView不动)
此时文字内容移动到右下角。此时我们应该可以理解,为什么上面例子中调用scrollBy(),y方向偏移量输入负值,文字内容却往下移动,因为这个偏移量作用的是与View边框左上角对齐的座标。y方向对齐的座标减少,需将画布下移,所以文字内容下移。同样的,scrollTo()参数传入座标指的是与View边框左上角对齐的画布座标。
最后总结一下:
1.scrollTo() / scrollBy() 移动的是View的内容(画布)。
2.scrollTo()的参数座标指的是与View边框左上角对齐的画布座标,scrollBy()参数的偏移量作用于与View边框左上角的画布座标。
3.ViewGroup调用时这两个方法移动的是所有子View
4.getScrollX()和getScrollY()得到的是当前与View边框左上角对齐的画布座标值。(因为一开始为(0,0),移动后的值减(0,0)即为移动后的座标值)