android关于Scroller与GestureDetector实现滚动的效果

本文介绍了如何使用Scroller和GestureDetector在Android中实现滚动效果。Scroller是一个辅助类,用于实现View的平滑滚动,GestureDetector则用于处理用户的触摸手势。通过结合这两个类,可以创建出响应用户手势的滚动视图。文中详细讲解了Scroller的相关方法,如startScroll、computeScrollOffset等,并给出了自定义手势监听类CustomGestureListener的实现,用于处理滑动手势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    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>


布局代码如下:activity_main.xml

<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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值