Scroller类是实现View能够滚动的一个帮助类。效果如下所示:
要实现以上的效果还要一个类就是GestureDetector类,这个类是实现手势类。
现在我们来探讨一下这两个类。
首先说说Scroller类,定义对象private Scroller mScroller = new Scroller(context);
相关方法:mScroller.getCurrX() 该方法为获取当前水平滚动的位置
mScroller.getCurrY() 该方法为获取当前竖直滚动的位置
mScroller.getFinalX() 该方法为获取最终停止的水平位置
mScroller.getFinalY() 该方法为获取最终停止的竖直位置
mScroller.setFinalX(int newX) 该方法设置最终停留水平位置,没有动画效果,直接到最终位置
mScroller.setFinalY(int newY) 该方法设置最终停留竖直位置,没有动画效果,直接到最终位置
mScroller.startScroll(int startX, int startY, int dx, int dy) 该方法为开始滚动,startX,startY为开始滚动的位置,dx,dy为滚动的偏移量,默认完成时间为250ms
mScroller.startScroll(int startX, int startY, int dx, int dy, int duration) 该方法同上一方法,但多一个参数duration, 设置完成时间
mScroller.computeScrollOffset() 方法返回值为boolean类型,为true表示滚动尚未完成,false表示滚动已经完成
我们定义方法
public void viewScrollTo(int x, int y) { //滚动到位置(x,y)
mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), x - mScroller.getFinalX(), y-mScroller.getFinalY());
invalidate(); //刷新View,确保调用方法public void computeScroll()
}
public void viewScrollBy(int dx, int dy) {
mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);
invalidate();
}
public void computeScroll(){
if(mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); //完成真实的滚动
postInvalidate(); //更新界面,实现滚动效果
}
super.computeScroll();
}
GestureDetector监听类
相关方法如下:
boolean onDoubleTap(MotionEvent e) //双击的第二下Touch down时触发
boolean onDoubleTapEvent(MotionEvent e) //双击的第二下Touch down和up都会触发,可用e.getAction()区分。
boolean onDown(MotionEvent e) //Touch down时触发
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) //Touch了滑动一点距离后,up时触发。
void onLongPress(MotionEvent e) //Touch了不移动一直Touch down时触发
boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) //Touch了滑动时触发。
void onShowPress(MotionEvent e) //Touch了还没有滑动时触发(与onDown,onLongPress比较 onDown只要Touch down一定立刻触发。而Touchdown后过一会没有滑动先触发onShowPress再是onLongPress。所以Touchdown后一直不滑动,onDown->onShowPress->onLongPress这个顺序触发。
boolean onSingleTapConfirmed(MotionEvent e)
boolean onSingleTapUp(MotionEvent e) //上面这两个函数都是在touch down后又没有滑动(onScroll),又没有长按(onLongPress),然后Touchup时触发。
自定义手势监听类
class CustomGestureListener implements GestureDetector.OnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return true;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
int dis = (int)((distanceY-0.5)/2);
Log.i(TAG, dis + ".");
viewScrollBy(0, dis);
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
return false;
}
}
自定义linearlayout代码如下:
<span style="font-size:14px;">public class CustomLinearView extends LinearLayout {
private static final String TAG = "CustomView";
private Scroller mScroller;
private GestureDetector mGestureDetector;
public CustomLinearView(Context context) {
this(context, null);
}
public CustomLinearView(Context context, AttributeSet attrs) {
super(context, attrs);
setClickable(true);
setLongClickable(true);
mScroller = new Scroller(context);
mGestureDetector = new GestureDetector(context, new CustomGestureListener());
}
//调用此方法滚动到目标位置
public void viewScrollTo(int fx, int fy) {
int dx = fx - mScroller.getFinalX();
int dy = fy - mScroller.getFinalY();
viewScrollBy(dx, dy);
}
//调用此方法设置滚动的相对偏移
public void viewScrollBy(int dx, int dy) {
//设置mScroller的滚动偏移量
mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);
invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
}
@Override
public void computeScroll() {
Log.i("computeScroll()", "ok");
//先判断mScroller滚动是否完成
if (mScroller.computeScrollOffset()) {
//这里调用View的scrollTo()完成实际的滚动
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
//必须调用该方法,否则不一定能看到滚动效果
postInvalidate();
}
super.computeScroll();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP :
Log.i(TAG, "get Sy" + getScrollY());
viewScrollTo(0, 0);
break;
default:
return mGestureDetector.onTouchEvent(event);
}
return super.onTouchEvent(event);
}
class CustomGestureListener implements GestureDetector.OnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return true;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
int dis = (int)((distanceY-0.5)/2);
Log.i(TAG, dis + ".");
viewScrollBy(0, dis);
return false;
}</span>
<span style="font-size:14px;">
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
return false;
}
}
}</span>
<span style="font-size:14px;"><RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffff0000"></TextView>
<com.scroller.CustomLinearView
android:id="@+id/custom_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#0fff"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#aaa"
android:gravity="center_horizontal"
android:text="下拉"
android:textSize="32sp" />
</com.scroller.CustomLinearView>
</RelativeLayout ></span>
activity代码如下:
<span style="font-size:14px;">public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}</span>
能运行得到上图的效果。(部分参考网络资源)
+_+ @ a little a day