以前做项目只是简单应用一些点击事件以及滑动事件,有些细节方便不是很清楚,今天特意学习了一下,顺便分享,以便于以后的记忆
一、先说点击事件:
点击事件很简单,我们只要绑定点击事件的监听接口并实现点击事件的监听方法,在onClik方法中进行点击事件的处理即可。如点击事件监听接口OnClickListener、长按事件的监听接口OnLongClickListener等。下面是一个点击事件的简单实现过程:
<span style="font-size:14px;"><span style="font-family:SimSun;font-size:14px;">class CliclLister implements OnClickListener{ @Override public void onClick(View v) { switch(v.getId()){ case R.id.but: if(v.isPressed()){ btn.setText("单击成功"); }else{ btn.setText("单击"); } break; } } } </span></span>Button绑定监听事件后,点击Button可以出发该事件,if(v.idPressed)内部的代码可以执行,但else后面的代码是不会执行的,如果我们想捕获点击事件时按下与弹起的这些动作,在该方法内是无法完成的。那如果我们详见听点击事件的按下与弹起怎么做呢?其实很简单,一种方法是我们自定义View,在自定义的View里面重写onTouchEvent方法实现这些手势的监听,不过这种方法是很愚蠢的,我们就只是想监听一下用户的简单手势还需要重写View的方法。其实还有更加简单的方法了,呵呵。。
二、再说OnTouchListener
最简单的方法就是实现OnTouchListener接口,在该接口中实现OnTouch方法來监听用户的手势操作。这里注意一下,如果我们为某一控件设置了OnTouchListener监听,那么该View本身内部的onTouchEvent方法是否会执行就要看OnTouchListener接口中onTouch方法的返回值了,如果返回值是true,那么View本身内部的onTouchEvent方法不会被调用,如果返回的是false,那么onTouchEvent也会被正常调用。由此可见OnTouchListener监听事件的优先级要比onTouchEvent高。
下面简单看一下OnTouchListener的简单实现:
<span style="font-size:14px;"><span style="font-family:SimSun;font-size:14px;">public class MainActivity extends Activity { private Button but; private TextView text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); but = (Button) findViewById(R.id.but); text = (TextView) findViewById(R.id.text); but.setOnTouchListener(new MyTouchListener()); but.setOnClickListener(new MyClickListener()); } class MyTouchListener implements OnTouchListener{ @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case KeyEvent.ACTION_DOWN: but.setText("已经按下按钮"); break; case KeyEvent.ACTION_UP: but.setText("按钮以弹起"); break; default: break; } return true; } } class MyClickListener implements OnClickListener{ @Override public void onClick(View v) { if(v.getId() == R.id.but){ text.setText("您点击成功这个按钮了!!"); text.setTextColor(Color.RED); } } } }</span></span>代码很简单,Button绑定了两个监听,一个是OnTouchListener,一个是OnClickListener,我们点击这个按钮后发现,OnTouchListener的监听方法执行了,而OnClickListener得监听方法没有执行。
其实上面已经介绍过,我们OnTouchListener的onTouch方法返回值为true,这表示事件只由它内部处理,不会传递给View的onTouchEvent,而OnClickListener得执行过程是在onTouchEvent之后,如果在onTouchEvent方法中,发现当前View设置了OnClickListener,就去处理它的onClick事件,由此可得出事件处理的一个优先级:
OnTouchListener -> onTouchEvent -> OnClickListener
三、GestureDetector强势来袭
当用户触摸屏幕的时候,会产生许多手势,例如down,up,scroll,filing等等。通过重写他的onTouch(View v, MotionEvent event)方法,我们可以处理一些touch事件,但是这个方法太过简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦(因为我们要自己根据用户触摸的轨迹去判断是什么手势)。Android sdk给我们提供了GestureDetector(Gesture:手势Detector:识别)类,通过这个类我们可以识别很多的手势。GestureDetector虽然能够处理手势,但不同手势的处理是留给程序员自己处理。
GestureDetector类对外提供两个接口和一个内部类:
接口:OnGestureListener,OnDoubleTapListener
内部类:SimpleOnGestureListener
下面我们先看OnGestureListener接口:
(1)GestureDetector.OnGestureListener---接口
<span style="font-size:14px;">class MyGestureDetector implements OnGestureListener{ @Override public boolean onDown(MotionEvent e) { // 用户按下屏幕就会触发; return false; } @Override public void onShowPress(MotionEvent e) { // 如果是按下的时间超过瞬间,而且在按下的时候没有松开或者是拖动的,那么onShowPress就会执行,具体这个瞬间是多久 } @Override public boolean onSingleTapUp(MotionEvent e) { // 一次单独的轻击抬起操作,也就是轻击一下屏幕,立刻抬起来,才会有这个触发,当然,如果除了Down以外还有其它操作,那就不再算是Single操作了,所以也就不会触发这个事件 return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // 在屏幕上拖动事件。无论是用手拖动view,或者是以抛的动作滚动,都会多次触发,这个方法 return false; } @Override public void onLongPress(MotionEvent e) { // 长时间点击事件 } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // 滑屏,用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发 return false; } }</span>我们在创建一个GestureDetector需要三部:
1.创建OnGestureListener监听函数,可以使用构造实例,也可以使用构造类。
OnGestureListener listener = newOnGestureListener(){
}或
class MyGestureListener implements OnGestureListener{
}
2.创建GestureDetector 实例gestureDetector,构造函数有三个,我们可以根据需要选择
<span style="font-size:14px;"> GestureDetector gestureDetector=new GestureDetector(GestureDetector.OnGestureListener listener); GestureDetector gestureDetector=new GestureDetector(Context context,GestureDetector.OnGestureListener listener); GestureDetector gestureDetector=new GestureDetector(Context context,GestureDetector.SimpleOnGestureListener listener);</span>3.在OnTouchListener的onTouch方法中拦截事件
<span style="font-size:14px;">public boolean onTouch(View v, MotionEvent event) { return gestureDetector.onTouchEvent(event); }</span>
4.控件绑定监听
<span style="font-size:14px;">TextView tv = (TextView)findViewById(R.id.tv); tv.setOnTouchListener(this); </span>
下面看一个简单的实现
首先,在主布局页面添加一个textView,方便在其上的手势识别,将textView放的比较大,并且用户的手势监听会以textview显示出来,方便查看手势监听的过程,布局文件代码为:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="@color/green" android:gravity="center" android:textSize="16dp"/> <Button android:id="@+id/but" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="清除"/> </LinearLayout>下面是Java代码,代码中监听在TextView上的手势,并且将手势的监听过程打印在TextView上,具体代码如下:
public class ActivityOnGestureOne extends Activity implements OnTouchListener{ private TextView text; private Button but; GestureDetector myGestureDetector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ongesture_listener); init(); } private void init() { text = (TextView) findViewById(R.id.text); but = (Button) findViewById(R.id.but); myGestureDetector = new GestureDetector(new MyGestureListener()); //使用派生自OnGestureListener text.setOnTouchListener(this); text.setFocusable(true); text.setClickable(true); text.setLongClickable(true); but.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { text.setText(""); } }); } //将捕捉到的MotionEvent交给GestureDetector @Override public boolean onTouch(View v, MotionEvent event) { return myGestureDetector.onTouchEvent(event); } class MyGestureListener implements OnGestureListener{ // 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发 @Override public boolean onDown(MotionEvent e) { text.append(" onDown "); Log.i("MyGesture", "onDown"); return false; } /* * 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发 * 注意和onDown()的区别,强调的是没有松开或者拖动的状态 * * 而onDown也是由一个MotionEventACTION_DOWN触发的,但是他没有任何限制, * 也就是说当用户点击的时候,首先MotionEventACTION_DOWN,onDown就会执行, * 如果在按下的瞬间没有松开或者是拖动的时候onShowPress就会执行,如果是按下的时间超过瞬间 * (这块我也不太清楚瞬间的时间差是多少,一般情况下都会执行onShowPress)拖动了,就不执行onShowPress。 */ @Override public void onShowPress(MotionEvent e) { text.append(" onShowPress "); Log.i("MyGesture", "onShowPress"); } /*用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发 轻击一下屏幕,立刻抬起来,才会有这个触发 从名子也可以看出,一次单独的轻击抬起操作,当然,如果除了Down以外还有其它操作,那就不再算是Single操作了,所以这个事件 就不再响应 */ @Override public boolean onSingleTapUp(MotionEvent e) { text.append(" onSingleTapUp "); Log.i("MyGesture", "onSingleTapUp"); return true; } // 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发 @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { text.append(" onScroll "); Log.i("MyGesture", "onScroll"); return true; } // 用户长按触摸屏后会触发 @Override public void onLongPress(MotionEvent e) { text.append(" onLongPress "); Log.i("MyGesture", "onLongPress"); } // 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发 @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { text.append(" onFling "); Log.i("MyGesture", "onFling"); return true; } } }读者可以自己通过手势监听的打印自己分析一下监听过程,下面是我截取的一张点击TextView并且滑动的截图:
(2)GestureDetector.OnDoubleTapListener---接口