(大多重写自View,HorizontalScrollView也一样)
public final int getScrollX()
返回值表示当前滚动到内容的哪个位置
public void scrollTo(int x, int y)
滚动到内容的x或y位置,一步到位,没有滚动动画,滚动动画需要利用Scroller定义
public void scrollBy(int x, int y)
往内容的正或负方向滚动x或y距离
fling过程中屏蔽了scrollTo()和scrollBy()
如果scrollTo()或scrollBy()超出内容的边界,则止于边界(默认)。
public final void smoothScrollTo(int x, int y)
平滑滚动到内容的x或y位置
当直接调用smoothScrollTo()没有效果时,试试这种方法:
View#post(new Runnable() {
@Override
public void run() {
smoothScrollTo(x, y);
}
});
public void startScroll(int startX, int startY, int dx, int dy, int duration)
开始一个动画控制,由(startX , startY)在duration时间内前进(dx,dy)个单位,即到达偏移坐标为(startX+dx , startY+dy)处
public boolean computeScrollOffset()
滑动过程中,根据当前已经消逝的时间计算当前偏移的坐标点,保存在mCurrX和mCurrY值中
public final int getCurrX()
返回mCurrX
import android.content.Context;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
import android.widget.OverScroller;
public class MyScrollView extends HorizontalScrollView {
private static final String TAG = "MyScrollView";
private OverScroller mScroller; //OverScroller >= Scroller
public MyScrollView(Context context) {
super(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new OverScroller(context);
}
/**
* 只要内容正在滚动(手指滑动+fling),就会连续触发onScrollChanged()
* onScrollChanged()的触发频率与onTouchEvent()一致
* 当scroll速度慢或者scroll停止时,同一个位置会执行两次
* @param scrollX = getScrollX(),可取最值,各取两次
* @param scrollY
* @param oldScrollX = 上一次执行onScrollChanged()时的scrollX值
* @param oldScrollY
*/
@Override
protected void onScrollChanged(int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
Log.d(TAG, "onScrollChanged: scrollX = " + scrollX + ",oldScrollX=" + oldScrollX);
super.onScrollChanged(scrollX, scrollY, oldScrollX, oldScrollY);
}
/**
* 只要内容正在滚动(手指滑动+fling),就会连续触发onOverScrolled()
* onOverScrolled()的触发频率与onTouchEvent()一致,同一个位置不会执行两次
* @param scrollX 当前位置,可取最值,各取一次,getScrollX()=参数scrollX上一次的取值
* @param scrollY
* @param clampedX 当scroll到左/右边界时,值为true
* @param clampedY 当scroll到上/下边界时,值为true
*/
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
Log.d(TAG, "onOverScrolled: scrollX=" + scrollX + ",scrollY=" + scrollY);
Log.d(TAG, "onOverScrolled: clampedX=" + clampedX + ",clampedY=" + clampedY);
//去掉这一行,会导致异常,滑不动
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}
/**
* 只要内容正在滚动(手指滑动+fling),就会连续触发overScrollBy()
* 但scroll停止的那一刻不执行此方法,即delta*不取0值,scroll*不取最值
* overScrollBy()的触发频率与onTouchEvent()一致
*/
@Override
protected boolean overScrollBy(int deltaX,
int deltaY,//与内容滚动速度成正相关,scroll将停未停时,deltaY为1或-1,不取0值
int scrollX,
int scrollY,//=getScrollY(),不取最值
int scrollRangeX,
int scrollRangeY,//控件内容可scroll的总跨度
int maxOverScrollX,
int maxOverScrollY,//最大可OverScroll的值,默认为0
boolean isTouchEvent//手指滑动带动scroll时,true;手指抬起,惯性fling时,false。
) {
Log.d(TAG, "overScrollBy deltaX = " + deltaX);
Log.d(TAG, "overScrollBy deltaY = " + deltaY);
Log.d(TAG, "overScrollBy scrollX = " + scrollX);
Log.d(TAG, "overScrollBy scrollY = " + getScrollY());
Log.d(TAG, "overScrollBy scrollRangeX = " + scrollRangeX);
Log.d(TAG, "overScrollBy scrollRangeY = " + scrollRangeY);
Log.d(TAG, "overScrollBy maxOverScrollX = " + maxOverScrollX);
Log.d(TAG, "overScrollBy maxOverScrollY = " + maxOverScrollY);
Log.d(TAG, "overScrollBy isTouchEvent = " + isTouchEvent);
//直接return true或者false,都会导致异常,滑不动
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
/**
* fling过程中不执行onTouchEvent()
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG, "onTouchEvent: getScrollX=" + getScrollX());
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
Log.d(TAG, "onTouchEvent: up");
// 分页效果demo----------------------------------------------------
mScroller.startScroll(getScrollX(), 0, 2000 - getScrollX(), 0, 2000);
//执行ScrollView的invalidate(),触发computeScroll()
invalidate();
// ---------------------------------------------------------------
break;
}
return super.onTouchEvent(event);
}
/**
* 一次scroll手势中,当手指离开屏幕时执行一次fling()
* @param velocityX:手指离开时scroll的速度(fling的初速度);内容向正方向滚,速度值为正值;内容向负方向滚,速度值为负值
*/
@Override
public void fling(int velocityX) {
Log.d(TAG, "fling: velocityX = " + velocityX);
super.fling(velocityX);
}
/**
* 只要内容正在滚动(手指滑动+fling),就会连续触发computeScroll()
*/
@Override
public void computeScroll() {
/**
* isMainThread为true表示该方法在主线程中执行
*/
boolean isMainThread = Looper.myLooper() == Looper.getMainLooper();
Log.d(TAG, "computeScroll in main thread : " + isMainThread);
// 分页效果demo------------------------------------------------------------
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
//执行ScrollView的invalidate(),触发computeScroll()
invalidate();
}
// -----------------------------------------------------------------------
}
}
https://github.com/chulichao/PageScrollView/blob/master/app/src/main/java/com/clc/psv/PageScrollView.java