一、android处理事件有两种形式.
1、基于监听的事件处理,就是通过setXxxListenter()进行处理的。
2、基于回调的事件处理,就是View类内部的onTouchEvent(),一般是在自定义控件时重写的。
关于这些方法是在什么时候被触发的,下面是对部分源码的分析:
1、首先:触摸事件会触发Activity的dispatchTouchEvent,
1 public boolean dispatchTouchEvent(MotionEvent ev) {
2 // onUserInteraction默认不执行任何动作。
3 // 它是提供给使用者的接口。
4 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
5 onUserInteraction();
6 }
7 // 这里会调用到ViewGroup的dispatchTouchEvent(),
8 // 即会调用Activity包含的根视图的dispatchTouchEvent()。
9 if (getWindow().superDispatchTouchEvent(ev)) {
10 return true;
11 }
12 // 如果superDispatchTouchEvent()返回false,
13 // 即Activity的根视图以及根视图的子视图都没有拦截该事件的话,则调用Activity的onTouchEvent()
14 return onTouchEvent(ev);
15 }
Activity的dispatchTouchEvent
DecorView是PhoneWindow的内部类,并且是Window界面的顶级View。
1 private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
2 ...
3
4 public boolean superDispatchTouchEvent(MotionEvent event) {
5 return super.dispatchTouchEvent(event);
6 }
7
8 ...
9 }
DecorView
从上面的DecorView源码部分可以看到:通过DecorView,Activity的触摸事件将转发给GroupView的dispatchTouchEvent()进行处理。
在Activity的dispatchTouchEvent()中,如果GroupView的dispatchTouchEvent()返回true则会拦截消耗事件,否则将执行Activity的onTouchEvent
1 public boolean onTouchEvent(MotionEvent event) {
2 if (mWindow.shouldCloseOnTouch(this, event)) {
3 finish();
4 return true;
5 }
6
7 return false;
8 }
9
10 //上面会调用Window的shouldCloseOnTouch()
11 public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
12 if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
13 && isOutOfBounds(context, event) && peekDecorView() != null) {
14 return true;
15 }
16 return false;
17 }
onTouchEvent
这个方法是对ctivity自身触摸事件的默认处理,可以用于关闭Dialog主题的Activity。
2、接着:由GroupView的dispatchTouchEvent()继续进行事件的分发
1 public boolean dispatchTouchEvent(MotionEvent ev) {
2 // mInputEventConsistencyVerifier是调试用的,不会理会
3 if (mInputEventConsistencyVerifier != null) {
4 mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
5 }
6
7 // 第1步:是否要分发该触摸事件
8 //
9 // onFilterTouchEventForSecurity()表示是否要分发该触摸事件。
10 // 如果该View不是位于顶部,并且有设置属性使该View不在顶部时不响应触摸事件,则不分发该触摸事件,即返回false。
11 // 否则,则对触摸事件进行分发,即返回true。
12 boolean handled = false;
13 if (onFilterTouchEventForSecurity(ev)) {
14 final int action = ev.getAction();
15 final int actionMasked = action & MotionEvent.ACTION_MASK;
16
17 // 第2步:检测是否需要清空目标和状态
18 //
19 // 如果是ACTION_DOWN(即按下事件),则清空之前的触摸事件处理目标和状态。
20 // 这里的情况状态包括:
21 // (01) 清空mFirstTouchTarget链表,并设置mFirstTouchTarget为null。
22 // mFirstTouchTarget是"接受触摸事件的View"所组成的单链表
23 // (02) 清空mGroupFlags的FLAG_DISALLOW_INTERCEPT标记
24 // 如果设置了FLAG_DISALLOW_INTERCEPT,则不允许ViewGroup对触摸事件进行拦截。
25 // (03) 清空mPrivateFlags的PFLAG_CANCEL_NEXT_UP_EVEN标记
26 if (actionMasked == MotionEvent.ACTION_DOWN) {
27 cancelAndClearTouchTargets(ev);
28 resetTouchState();
29 }
30
31 // 第3步:检查当前ViewGroup是否想要拦截触摸事件
32 //
33 // 是的话,设置intercepted为true;否则intercepted为false。
34 // 如果是"按下事件(ACTION_DOWN)" 或者 mFirstTouchTarget不为null;就执行if代码块里面的内容。
35 // 否则的话,设置intercepted为true。
36 final boolean intercepted;
37 if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
38 // 检查禁止拦截标记:FLAG_DISALLOW_INTERCEPT
39 // 如果调用了requestDisallowInterceptTouchEvent()标记的话,则FLAG_DISALLOW_INTERCEPT会为true。
40 // 例如,ViewPager在处理触摸事件的时候,就会调用requestDisallowInterceptTouchEvent()
41 // ,禁止它的父类对触摸事件进行拦截
42 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
43 if (!disallowIntercept) {
44 // 如果禁止拦截标记为false的话,则调用onInterceptTouchEvent();并返回拦截状态。
45 intercepted = onInterceptTouchEvent(ev);
46 ev.setAction(action); // restore action in case it was changed
47 } else {
48 intercepted = false;
49 }
50 } else {
51 intercepted = true;
52 }
53
54 // 第4步:检查当前的触摸事件是否被取消
55 //
56 // (01) 对于ACTION_DOWN而言,mPrivateFlags的PFLAG_CANCEL_NEXT_UP_EVENT位肯定是0;因此,canceled=false。
57 // (02) 当前的View或ViewGroup要被从父View中detach时,PFLAG_CANCEL_NEXT_UP_EVENT就会被设为true;
58 // 此时,它就不再接受触摸事情。
59 final boolean canceled = resetCancelNextUpFlag(this)
60 || actionMasked == MotionEvent.ACTION_CANCEL;
61
62 // 第5步:将触摸事件分发给"当前ViewGroup的子View和子ViewGroup"
63 //
64 // 如果触摸"没有被取消",同时也"没有被拦截"的话,则将触摸事件分发给它的子View和子ViewGroup。
65 // 如果当前ViewGroup的孩子有接受触摸事件的话,则将该孩子添加到mFirstTouchTarget链表中。
66 final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
67 TouchTarget newTouchTarget = null;
68 boolean alreadyDispatchedToNewTouchTarget = false;
69 if (!canceled && !intercepted) {
70 if (actionMasked == MotionEvent.ACTION_DOWN
71 || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
72 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
73 // 这是获取触摸事件的序号 以及 触摸事件的id信息。
74 // (01) 对于ACTION_DOWN,actionIndex肯定是0
75 // (02) 而getPointerId()是获取的该触摸事件的id,并将该id信息保存到idBitsToAssign中。
76 // 这个触摸事件的id是为多指触摸而添加的;对于单指触摸,getActionIndex()返回的肯定是0;
77 // 而对于多指触摸,第一个手指的id是0,第二个手指的id是1,第三个手指的id是2,...依次类推。
78 final int actionIndex = ev.getActionIndex();
79 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
80 : TouchTarget.ALL_POINTER_IDS;
81
82 // 清空这个手指之前的TouchTarget链表。
83 // 一个TouchTarget,相当于一个可以被触摸的对象;它中记录了接受触摸事件的View
84 removePointersFromTouchTargets(idBitsToAssign);
85
86 // 获取该ViewGroup包含的View和ViewGroup的数目,
87 // 然后递归遍历ViewGroup的孩子,对触摸事件进行分发。
88 // 递归遍历ViewGroup的孩子:是指对于当前ViewGroup的所有孩子,都会逐个遍历,并分发触摸事件;
89 // 对于逐个遍历到的每一个孩子,若该孩子是ViewGroup类型的话,则会递归到调用该孩子的孩子,...
90 final int childrenCount = mChildrenCount;
91 if (newTouchTarget == null && childrenCount != 0) {
92 final float x = ev.getX(actionIndex);
93 final float y = ev.getY(actionIndex);
94 final View[] children = mChildren;
95
96 final boolean customOrder = isChildrenDrawingOrderEnabled();
97 for (int i = childrenCount - 1; i >= 0; i--) {
98 final int childIndex = customOrder ?
99 getChildDrawingOrder(childrenCount, i) : i;
100 final View child = children[childIndex];
101 // 如果child可以接受触摸事件,
102 // 并且触摸坐标(x,y)在child的可视范围之内的话;
103 // 则继续往下执行。否则,调用continue。
104 // child可接受触摸事件:是指child的是可见的(VISIBLE);或者虽然不可见,但是位于动画状态。
105 if (!canViewReceivePointerEvents(child)
106 || !isTransformedTouchPointInView(x, y, child, null)) {
107 continue;
108 }
109
110 // getTouchTarget()的作用是查找child是否存在于mFirstTouchTarget的单链表中。
111 // 是的话,返回对应的TouchTarget对象;否则,返回null。
112 newTouchTarget = getTouchTarget(child);
113 if (newTouchTarget != null) {
114 newTouchTarget.pointerIdBits |= idBitsToAssign;
115 break;
116 }
117
118 // 重置child的mPrivateFlags变量中的PFLAG_CANCEL_NEXT_UP_EVENT位。
119 resetCancelNextUpFlag(child);
120
121 // 调用dispatchTransformedTouchEvent()将触摸事件分发给child。
122 if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
123 // 如果child能够接受该触摸事件,即child消费或者拦截了该触摸事件的话;
124 // 则调用addTouchTarget()将child添加到mFirstTouchTarget链表的表头,并返回表头对应的TouchTarget
125 // 同时还设置alreadyDispatchedToNewTouchTarget为true。
126 mLastTouchDownTime = ev.getDownTime();
127 mLastTouchDownIndex = childIndex;
128 mLastTouchDownX = ev.getX();
129 mLastTouchDownY = ev.getY();
130 newTouchTarget = addTouchTarget(child, idBitsToAssign);
131 alreadyDispatchedToNewTouchTarget = true;
132 break;
133 }
134 }
135 }
136
137 // 如果newTouchTarget为null,并且mFirstTouchTarget不为null;
138 // 则设置newTouchTarget为mFirstTouchTarget链表中第一个不为空的节点。
139 if (newTouchTarget == null && mFirstTouchTarget != null) {
140 // Did not find a child to receive the event.
141 // Assign the pointer to the least recently added target.
142 newTouchTarget = mFirstTouchTarget;
143 while (newTouchTarget.next != null) {
144 newTouchTarget = newTouchTarget.next;
145 }
146 newTouchTarget.pointerIdBits |= idBitsToAssign;
147 }
148 }
149 }
150
151 // 第6步:进一步的对触摸事件进行分发
152 //
153 // (01) 如果mFirstTouchTarget为null,意味着还没有任何View来接受该触摸事件;
154 // 此时,将当前ViewGroup看作一个View;
155 // 将会调用"当前的ViewGroup的父类View的dispatchTouchEvent()"对触摸事件进行分发处理。
156 // 即,会将触摸事件交给当前ViewGroup的onTouch(), onTouchEvent()进行处理。
157 // (02) 如果mFirstTouchTarget不为null,意味着有ViewGroup的子View或子ViewGroup中,
158 // 有可以接受触摸事件的。那么,就将触摸事件分发给这些可以接受触摸事件的子View或子ViewGroup。
159 if (mFirstTouchTarget == null) {
160 // 注意:这里的第3个参数是null
161 handled = dispatchTransformedTouchEvent(ev, canceled, null,
162 TouchTarget.ALL_POINTER_IDS);
163 } else {
164 // Dispatch to touch targets, excluding the new touch target if we already
165 // dispatched to it. Cancel touch targets if necessary.
166 TouchTarget predecessor = null;
167 TouchTarget target = mFirstTouchTarget;
168 while (target != null) {
169 final TouchTarget next = target.next;
170 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
171 handled = true;
172 } else {
173 final boolean cancelChild = resetCancelNextUpFlag(target.child)
174 || intercepted;
175 if (dispatchTransformedTouchEvent(ev, cancelChild,
176 target.child, target.pointerIdBits)) {
177 handled = true;
178 }
179 if (cancelChild) {
180 if (predecessor == null) {
181 mFirstTouchTarget = next;
182 } else {
183 predecessor.next = next;
184 }
185 target.recycle();
186 target = next;
187 continue;
188 }
189 }
190 predecessor = target;
191 target = next;
192 }
193 }
194
195 // 第7步:再次检查取消标记,并进行相应的处理
196 //
197 // Update list of touch targets for pointer up or cancel, if needed.
198 if (canceled
199 || actionMasked == MotionEvent.ACTION_UP
200 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
201 resetTouchState();
202 } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
203 final int actionIndex = ev.getActionIndex();
204 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
205 removePointersFromTouchTargets(idBitsToRemove);
206 }
207 }
208
209 // mInputEventConsistencyVerifier是调试用的,不会理会
210 if (!handled && mInputEventConsistencyVerifier != null) {
211 mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
212 }
213 return handled;
214 }
GroupView的dispatchTouchEvent
在分发事件时,除了判断是否被拦截或取消后,内部又判断了是否是Down事件,也就是只有在Down事件没有被拦截或取消,才会向其分发事件。
触摸事件会触发view中的dispatchTouchEvent(),如果没有子类中没有重写,则会向上寻找一个执行。下面是View中的部分源码,就是具体执行事件的部分
1 ListenerInfo li = mListenerInfo;
2 if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED&& li.mOnTouchListener.onTouch(this, event)) {
3 result = true;
4 }
5
6 if (!result && onTouchEvent(event)) {
7 result = true;
8 }
顶级View的dispatchTouchEvent
上面是23版本的片段,这部分代码写的比较巧妙,第一个if中:
1、li != null,这是ListenerInfo对象,保存各种监听器实例的对象,只要有一个监听器被设置,则该对象不为空。
1 static class ListenerInfo {
2 protected OnFocusChangeListener mOnFocusChangeListener;
3
4 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
5
6 protected OnScrollChangeListener mOnScrollChangeListener;
7
8 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;
9
10 public OnClickListener mOnClickListener;
11
12 protected OnLongClickListener mOnLongClickListener;
13
14 protected OnContextClickListener mOnContextClickListener;
15
16 protected OnCreateContextMenuListener mOnCreateContextMenuListener;
17
18 private OnKeyListener mOnKeyListener;
19
20 private OnTouchListener mOnTouchListener;
21
22 private OnHoverListener mOnHoverListener;
23
24 private OnGenericMotionListener mOnGenericMotionListener;
25
26 private OnDragListener mOnDragListener;
27
28 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
29
30 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
31 }
32
33 ListenerInfo mListenerInfo;
34
35 public void setOnTouchListener(OnTouchListener l) {
36 //在设置监听器实例时,这里会调用getListenerInfo()判断是否有ListenerInfo实例存在
37 getListenerInfo().mOnTouchListener = l;
38 }
39
40 ListenerInfo getListenerInfo() {
41 if (mListenerInfo != null) {
42 return mListenerInfo;
43 }
44 mListenerInfo = new ListenerInfo();
45 return mListenerInfo;
46 }
mListenerInfo部分
2、li.mOnTouchListener != null,这是判断是否有TouchListener,这是通过setOnTouchListener()设置的。
3、(mViewFlags & ENABLED_MASK) == ENABLED,这是判断View的mViewFlags是否是ENABLED。注意:这和View是否可点击不同,可点击是CLICKABLE=true
1 //检测是否是ENABLED,获取和设置都与mViewFlags有关
2 public boolean isEnabled() {
3 return (mViewFlags & ENABLED_MASK) == ENABLED;
4 }
5
6 public void setEnabled(boolean enabled) {
7 if (enabled == isEnabled()) return;
8
9 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK);
10
11
12 //下面是与点击有关的获取和设置
13 public boolean isClickable() {
14 return (mViewFlags & CLICKABLE) == CLICKABLE;
15 }
16
17 public void setClickable(boolean clickable) {
18 setFlags(clickable ? CLICKABLE : 0, CLICKABLE);
19 }
20
21 public boolean isLongClickable() {
22 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE;
23 }
24
25 public void setLongClickable(boolean longClickable) {
26 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE);
27 }
28
29 public boolean isContextClickable() {
30 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
31 }
32
33 public void setContextClickable(boolean contextClickable) {
34 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE);
35 }
36
37 //注意
38 public void setOnClickListener(@Nullable OnClickListener l) {
39 if (!isClickable()) {
40 setClickable(true);
41 }
42 getListenerInfo().mOnClickListener = l;
43 }
Enable和Clickable的区别
!!!注意:在setOnClickListener中会修改Clickable属性,即原本不能点击的View,如果添加点击的监听器,则可以点击。
4、li.mOnTouchListener.onTouch(this, event),就是判断添加的监听事件额返回值。
!!!只有当上面四个都是true时,设置result=true。而这个值又影响到下一个判断的执行,因为用到&&(这个操作符比较特殊,如果前一个操作数为true,则继续向后判断;如果前一个为false,则不执行后续判断直接返回false),所以前面是false这直接退出执行,否则会触发View的onTouchEvent(event)。该方法比较重要的两步见下面说明。需要注意的是:这个方法的返回值为true,则事件被消耗,否则将继续!!向后(其他的点击事件)也包括向!!父布局传递。
1 public boolean onTouchEvent(MotionEvent event) {
2 final int viewFlags = mViewFlags;
3
4 // 如果View被禁用的话,则返回它是否可以点击。
5 if ((viewFlags & ENABLED_MASK) == DISABLED) {
6 if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
7 setPressed(false);
8 }
9 return (((viewFlags & CLICKABLE) == CLICKABLE ||
10 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
11 }
12
13 // 如果该View的mTouchDelegate不为null的话,将触摸消息分发给mTouchDelegate。
14 // mTouchDelegate的默认值是null。
15 if (mTouchDelegate != null) {
16 if (mTouchDelegate.onTouchEvent(event)) {
17 return true;
18 }
19 }
20
21 // 如果View可以被点击的话,则执行if里面的内容。
22 // 这其中涉及到的主要是获取焦点,设置按下状态,触发onClick(), onLongClick()事件等等。
23 if (((viewFlags & CLICKABLE) == CLICKABLE ||
24 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
25 。。。
26 }
27 return true;
28 }
29
30 return false;
31 }
View的onTouchEvent
这个方法的返回值总结:
a、该View不可用,即(viewFlags & ENABLED_MASK) == DISABLED,则返回是否可点击或长击。如果可用则向下判断
b、mTouchDelegate如果不为null,则由其进行处理并返回结果,否则继续向下判断
c、到这这一步,只要View可以点击或长击则返回true,否则返回false。
下图是View事件分发的全过程图示,重点是事件首先是由顶级布局获取的,而不是其中的子View.
1 package com.dqxst.first.view;
2
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.util.Log;
6 import android.view.MotionEvent;
7 import android.view.View;
8 import android.view.View.OnClickListener;
9 import android.view.View.OnTouchListener;
10 import android.widget.Button;
11 import android.widget.ImageView;
12 import android.widget.LinearLayout;
13
14 import com.dqxst.first.R;
15 import com.dqxst.first.myui.MyBtn;
16
17 public class EventActivity extends Activity{
18 private final static String TAG="EventActivity";
19 private LinearLayout parent;
20 private Button btn;
21 private MyBtn myBtn;
22 private ImageView image;
23
24 @Override
25 protected void onCreate(Bundle savedInstanceState) {
26 super.onCreate(savedInstanceState);
27 setContentView(R.layout.activity_event);
28 findView();
29 event();
30 Log.i(TAG, "enabled="+image.isEnabled());
31 Log.i(TAG, "LongClickable="+image.isLongClickable());
32 }
33
34 private void event() {
35 parent.setOnClickListener(new OnClickListener() {
36 @Override
37 public void onClick(View v) {
38 Log.i(TAG, "父布局的OnClickListener被触发。。。");
39 }
40 });
41 btn.setOnClickListener(new OnClickListener() {
42 @Override
43 public void onClick(View v) {
44 Log.i(TAG, "点击btn,OnClickListener。。。");
45 }
46 });
47 btn.setOnTouchListener(new OnTouchListener() {
48 @Override
49 public boolean onTouch(View v, MotionEvent event) {
50 Log.i(TAG, "点击btn,OnTouchListener。。。,事件action="+event.getAction());
51 return false;
52 }
53 });
54
55 myBtn.setOnClickListener(new OnClickListener() {
56 @Override
57 public void onClick(View v) {
58 Log.i(TAG, "点击myBtn,OnClickListener。。。");
59 }
60 });
61 myBtn.setOnTouchListener(new OnTouchListener() {
62 @Override
63 public boolean onTouch(View v, MotionEvent event) {
64 Log.i(TAG, "点击myBtn,OnTouchListener。。。,事件action="+event.getAction());
65 return false;
66 }
67 });
68 image.setOnClickListener(new OnClickListener() {
69 @Override
70 public void onClick(View v) {
71 Log.i(TAG, "点击image,OnClickListener。。。");
72 }
73 });
74 image.setOnTouchListener(new OnTouchListener() {
75 @Override
76 public boolean onTouch(View v, MotionEvent event) {
77 Log.i(TAG, "点击image,OnTouchListener。。。,事件action="+event.getAction());
78 return false;
79 }
80 });
81 }
82
83 //上面已经有setOnClickListener,所以该方法不执行
84 public void btn_click(View view){
85 Log.i(TAG, "点击btn,通过xml绑定的onclick事件处理");
86 }
87
88 private void findView() {
89 parent=(LinearLayout) findViewById(R.id.parent);
90 btn=(Button) findViewById(R.id.btn);
91 myBtn=(MyBtn) findViewById(R.id.mybtn);
92 image=(ImageView) findViewById(R.id.event_image);
93 }
94 }
二、MotionEvent触摸事件,这是上面事件分发之后最终在OnTouchListener()执行的事件对象。通过这个对象可以获取当前的触摸事件。
getAction()可以获取事件标识,可以和MotionEvent中定义的事件标识进行匹配。
event.getAction()&MotionEvent.ACTION_MASK来获取事件。
在MotionEvent对象中最重要的属性就是触发事件的X,Y坐标。通过getX()/getY()获取。多点触控通过getX(int pointerIndex) ,来获得对应手指事件的发生位置. 获得Y轴用getY(int pointerIndex)
三、手势事件:其实就是android提供的封装了对MotionEvent事件的处理,把一些连续的操作响应为手势(当然也可以手动处理,但是比较麻烦)。主要用到的是GestureDetector类,使用过程分三步:
创建手势监听器对象,这是通过集成/实现该类中的接口/实现类来完成的,比如OnGestureListener接口/SimpleOnGestureListener类。
GestureDetector对象,需要通过构造器传入上面的手势监听器对象。
GestureDetector.onTouch()进行事件的处理。
需要注意的是,手势事件可以针对整个activity或者其中一个View。
1、如果针对Activity,那就不需要为其中的View添加事件监听,直接重写onTouchEvent()将事件转发即可。
需要返回值必须为true才能正确响应。
1 package com.dqxst.first.view;
2
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.util.Log;
6 import android.view.GestureDetector;
7 import android.view.GestureDetector.OnGestureListener;
8 import android.view.MotionEvent;
9 import android.view.View;
10 import android.view.View.OnClickListener;
11 import android.view.View.OnTouchListener;
12 import android.widget.Button;
13 import android.widget.ImageView;
14 import android.widget.LinearLayout;
15
16 import com.dqxst.first.R;
17 import com.dqxst.first.myui.MyBtn;
18 import com.dqxst.first.util.CommonUtils;
19
20 public class EventActivity extends Activity implements OnTouchListener{
21 private final static String TAG="EventActivity";
22 private LinearLayout parent;
23 private View view;
24 private Button btn;
25 private MyBtn myBtn;
26 private ImageView image;
27
28 private MyGestureListener mgListener;
29 private GestureDetector mDetector;
30
31 @Override
32 protected void onCreate(Bundle savedInstanceState) {
33 super.onCreate(savedInstanceState);
34 setContentView(R.layout.activity_event);
35
36 //实例化GestureListener与GestureDetector对象
37 mgListener = new MyGestureListener();
38 mDetector = new GestureDetector(this, mgListener);
39
40 findView();
41
42 // image.setOnTouchListener(this);
43 }
44
45 private void findView() {
46 parent=(LinearLayout) findViewById(R.id.parent);
47 view=findViewById(R.id.event_test);
48 btn=(Button) findViewById(R.id.btn);
49 myBtn=(MyBtn) findViewById(R.id.mybtn);
50 image=(ImageView) findViewById(R.id.event_image);
51 }
52
53 //如果是针对某一View,则使用下面的监听器,然后给相应的View进行set即可
54 @Override
55 public boolean onTouchEvent(MotionEvent event) {
56 return mDetector.onTouchEvent(event);
57 }
58
59 @Override
60 // public boolean onTouch(View v, MotionEvent event) {
61 // mDetector.onTouchEvent(event);
62 // return true;
63 // }
64
65 //自定义一个GestureListener,这个是View类下的,别写错哦!!!
66 private class MyGestureListener implements OnGestureListener {
67
68 @Override
69 public boolean onDown(MotionEvent motionEvent) {
70 Log.d(TAG, "onDown:按下");
71 CommonUtils.toastShow(getApplicationContext(), "onDown:按下");
72 return false;
73 }
74
75 @Override
76 public void onShowPress(MotionEvent motionEvent) {
77 Log.d(TAG, "onShowPress:手指按下一段时间,不过还没到长按");
78 CommonUtils.toastShow(getApplicationContext(), "onShowPress:手指按下一段时间,不过还没到长按");
79 }
80
81 @Override
82 public boolean onSingleTapUp(MotionEvent motionEvent) {
83 Log.d(TAG, "onSingleTapUp:手指离开屏幕的一瞬间");
84 CommonUtils.toastShow(getApplicationContext(), "onSingleTapUp:手指离开屏幕的一瞬间");
85 return false;
86 }
87
88 @Override
89 public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
90 Log.d(TAG, "onScroll:在触摸屏上滑动");
91 CommonUtils.toastShow(getApplicationContext(), "onScroll:在触摸屏上滑动");
92 return false;
93 }
94
95 @Override
96 public void onLongPress(MotionEvent motionEvent) {
97 Log.d(TAG, "onLongPress:长按并且没有松开");
98 CommonUtils.toastShow(getApplicationContext(), "onLongPress:长按并且没有松开");
99 }
100
101 @Override
102 public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
103 Log.d(TAG, "onFling:迅速滑动,并松开");
104 CommonUtils.toastShow(getApplicationContext(), "onFling:迅速滑动,并松开");
105 return false;
106 }
107 }
108
109 }
手势操作实例
上面是基本使用。除此之外还可以使用GestureOverlayView编辑手势,使用GestureLibraries(手势库)来添加(刚才编辑的手势)或者获取手势。
package com.dqxst.first.view;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.dqxst.first.R;
import com.dqxst.first.myui.MyBtn;
import com.dqxst.first.util.CommonUtils;
public class EventActivity extends Activity implements OnTouchListener{
private final static String TAG="EventActivity";
private LinearLayout parent;
private View view;
private Button btn;
private MyBtn myBtn;
private ImageView image;
private MyGestureListener mgListener;
private GestureDetector mDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event);
//实例化GestureListener与GestureDetector对象
mgListener = new MyGestureListener();
mDetector = new GestureDetector(this, mgListener);
findView();
// event();
Log.i(TAG, "enabled="+view.isEnabled());
Log.i(TAG, "click="+view.isClickable());
Log.i(TAG, "Longclick="+view.isLongClickable());
image.setOnTouchListener(this);
}
private void event() {
parent.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "父布局的OnClickListener被触发。。。");
}
});
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "点击btn,OnClickListener。。。");
}
});
btn.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i(TAG, "点击btn,OnTouchListener。。。,事件action="+event.getAction());
return false;
}
});
myBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "点击myBtn,OnClickListener。。。");
}
});
myBtn.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i(TAG, "点击myBtn,OnTouchListener。。。,事件action="+event.getAction());
return false;
}
});
image.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "点击image,OnClickListener。。。");
}
});
image.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i(TAG, "点击image,OnTouchListener。。。,事件action="+event.getAction());
return false;
}
});
}
//上面已经有setOnClickListener,所以该方法不执行
public void btn_click(View view){
Log.i(TAG, "点击btn,通过xml绑定的onclick事件处理");
}
private void findView() {
parent=(LinearLayout) findViewById(R.id.parent);
view=findViewById(R.id.event_test);
btn=(Button) findViewById(R.id.btn);
myBtn=(MyBtn) findViewById(R.id.mybtn);
image=(ImageView) findViewById(R.id.event_image);
}
// @Override
// public boolean onTouchEvent(MotionEvent event) {
// return mDetector.onTouchEvent(event);
// }
@Override
public boolean onTouch(View v, MotionEvent event) {
mDetector.onTouchEvent(event);
return true;
}
//自定义一个GestureListener,这个是View类下的,别写错哦!!!
private class MyGestureListener implements OnGestureListener {
@Override
public boolean onDown(MotionEvent motionEvent) {
Log.d(TAG, "onDown:按下");
CommonUtils.toastShow(getApplicationContext(), "onDown:按下");
return false;
}
@Override
public void onShowPress(MotionEvent motionEvent) {
Log.d(TAG, "onShowPress:手指按下一段时间,不过还没到长按");
CommonUtils.toastShow(getApplicationContext(), "onShowPress:手指按下一段时间,不过还没到长按");
}
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
Log.d(TAG, "onSingleTapUp:手指离开屏幕的一瞬间");
CommonUtils.toastShow(getApplicationContext(), "onSingleTapUp:手指离开屏幕的一瞬间");
return false;
}
@Override
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
Log.d(TAG, "onScroll:在触摸屏上滑动");
CommonUtils.toastShow(getApplicationContext(), "onScroll:在触摸屏上滑动");
return false;
}
@Override
public void onLongPress(MotionEvent motionEvent) {
Log.d(TAG, "onLongPress:长按并且没有松开");
CommonUtils.toastShow(getApplicationContext(), "onLongPress:长按并且没有松开");
}
@Override
public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
Log.d(TAG, "onFling:迅速滑动,并松开");
CommonUtils.toastShow(getApplicationContext(), "onFling:迅速滑动,并松开");
return false;
}
}
}