android点击事件(View)
来源:互联网 发布:sql查询所有表 编辑:程序博客网 时间:2024/06/06 09:16
本文主要讲述一个view的点击事件相关知识,事件分发方面的可以去 android事件分发
阅读本文最好对事件有一定了解,可以通过阅读郭神的http://blog.csdn.net/guolin_blog/article/details/9097463
概述
1、onTouch如果返回true,那么 onTouchEvent执行不到,而onClick在onTouchEvent内,所以 onClick也无法执行,这样就屏蔽了 onClick
2、onClick和onTouch是观察者模式,但是onTouchEvent是方法重写,要自定义view3、从源码中可以看出,onTouchEvent和onTouch这两个方法都是在View的dispatchTouchEvent中调用的,onTouch优先于onTouchEvent执行。如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行。
4、另外需要注意的是,onTouch能够得到执行需要两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。因此如果你有一个控件是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。
5、我们都知道如果给一个控件注册了touch事件,每次点击它的时候都会触发一系列的ACTION_DOWN,ACTION_MOVE,ACTION_UP等一组事件。按理说每次事件都会触发dispatchTouchEvent。可是如果一组事件中的某个事件的dispatchTouchEvent返回了false,那表示这组事件已经处理完毕,后面的事件不会触发dispatchTouchEvent。
例如ACTION_DOWN的dispatchTouchEvent返回了false,后面一系列其它的action就不会再得到执行了。简单的说,就是当dispatchTouchEvent在进行事件分发的时候,只有前一个action的dispatchTouchEvent返回true(这里是指 dispatchTouchEvent返回true而不是onTouch 返回true) ,才会触发后一个action。(这里的action和事件是一个意思)
6 如果一个view是clickable或者longclickable,那么他永远会消费action_up事件,在onTouchEvent里面消费掉,不会传递给他的parent
源码流程
dispatchTouchEvent流程
public boolean dispatchTouchEvent(MotionEvent event) { if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) { return true; } return onTouchEvent(event);}
onClick哪里调用
public boolean onTouchEvent(MotionEvent event) { final int viewFlags = mViewFlags; if ((viewFlags & ENABLED_MASK) == DISABLED) { // A disabled view that is clickable still consumes the touch // events, it just doesn't respond to them. return (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); } if (mTouchDelegate != null) { if (mTouchDelegate.onTouchEvent(event)) { return true; } } if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { switch (event.getAction()) { case MotionEvent.ACTION_UP: boolean prepressed = (mPrivateFlags & PREPRESSED) != 0; if ((mPrivateFlags & PRESSED) != 0 || prepressed) { // take focus if we don't have it already and we should in // touch mode. boolean focusTaken = false; if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { focusTaken = requestFocus(); } if (!mHasPerformedLongPress) { // This is a tap, so remove the longpress check removeLongPressCallback(); // Only perform take click actions if we were in the pressed state if (!focusTaken) { // Use a Runnable and post this rather than calling // performClick directly. This lets other visual state // of the view update before click actions start. if (mPerformClick == null) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { performClick(); } } } if (mUnsetPressedState == null) { mUnsetPressedState = new UnsetPressedState(); } if (prepressed) { mPrivateFlags |= PRESSED; refreshDrawableState(); postDelayed(mUnsetPressedState, ViewConfiguration.getPressedStateDuration()); } else if (!post(mUnsetPressedState)) { // If the post failed, unpress right now mUnsetPressedState.run(); } removeTapCallback(); } break; case MotionEvent.ACTION_DOWN: if (mPendingCheckForTap == null) { mPendingCheckForTap = new CheckForTap(); } mPrivateFlags |= PREPRESSED; mHasPerformedLongPress = false; postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); break; case MotionEvent.ACTION_CANCEL: mPrivateFlags &= ~PRESSED; refreshDrawableState(); removeTapCallback(); break; case MotionEvent.ACTION_MOVE: final int x = (int) event.getX(); final int y = (int) event.getY(); // Be lenient about moving outside of buttons int slop = mTouchSlop; if ((x < 0 - slop) || (x >= getWidth() + slop) || (y < 0 - slop) || (y >= getHeight() + slop)) { // Outside button removeTapCallback(); if ((mPrivateFlags & PRESSED) != 0) { // Remove any future long press/tap checks removeLongPressCallback(); // Need to switch from pressed to not pressed mPrivateFlags &= ~PRESSED; refreshDrawableState(); } } break; } return true; } return false;}
public boolean performClick() { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); if (mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); mOnClickListener.onClick(this); return true; } return false;}
如何禁止GridView的滚动呢?
这是一种方法,通过继承GridView,并且重写dispatchTouchEvent实现
还有一种方法,dispatchTouchEvent会传递给onTouch,我们可以在onTouch里拦截,在这里判断Action是不是MOVE,如果是就直接返回true,那么就无法往下传递,也不会滚动
为什么button2次ontouch才有一次onclick
EditText诡异事件
touch mode
对于一个拥有触摸屏功能的设备而言, 一旦用户用手点击屏幕, 设备立刻进入touch mode . 这时候被点击的控件只有isFocusableInTouchMode()方法返回true的时候才会 focusable , 比如EditText控件. 其他可以触摸的控件, 比如按钮, 当被点击的时候不会获取焦点; 它们只是简单地执行onClick事件而已.
任何时候只要用户点击key或滚动trackball, 设备就会退出touch mode ,并且找一个view将焦点置于其上. 此时用户可以不使用触摸手势了.
touch mode 在整个系统运行期间都是有效的(在任何activities中). 如果想要查询当前处于何种状态, 你可以调用View#isInTouchMode()来看看当前是否处于touch mode .
001 public boolean onTouchEvent(MotionEvent event) {002 final float x = event.getX();003 final float y = event.getY();004 final int viewFlags = mViewFlags;005 006 if ((viewFlags & ENABLED_MASK) == DISABLED) {007 if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {008 setPressed(false);009 }010 // A disabled view that is clickable still consumes the touch011 // events, it just doesn't respond to them.012 return (((viewFlags & CLICKABLE) == CLICKABLE ||013 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));014 }015 016 if (mTouchDelegate != null) {017 if (mTouchDelegate.onTouchEvent(event)) {018 return true;019 }020 }021 022 if (((viewFlags & CLICKABLE) == CLICKABLE ||023 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {024 switch (event.getAction()) {025 case MotionEvent.ACTION_UP:026 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;027 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {028 // take focus if we don't have it already and we should in029 // touch mode.030 boolean focusTaken = false;031 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {032 focusTaken = requestFocus();033 }034 035 if (prepressed) {036 // The button is being released before we actually037 // showed it as pressed. Make it show the pressed038 // state now (before scheduling the click) to ensure039 // the user sees it.040 setPressed(true, x, y);041 }042 043 if (!mHasPerformedLongPress) {044 // This is a tap, so remove the longpress check045 removeLongPressCallback();046 047 // Only perform take click actions if we were in the pressed state048 if (!focusTaken) {049 // Use a Runnable and post this rather than calling050 // performClick directly. This lets other visual state051 // of the view update before click actions start.052 if (mPerformClick == null) {053 mPerformClick = new PerformClick();054 }055 if (!post(mPerformClick)) {056 performClick();057 }058 }059 }060 061 if (mUnsetPressedState == null) {062 mUnsetPressedState = new UnsetPressedState();063 }064 065 if (prepressed) {066 postDelayed(mUnsetPressedState,067 ViewConfiguration.getPressedStateDuration());068 } else if (!post(mUnsetPressedState)) {069 // If the post failed, unpress right now070 mUnsetPressedState.run();071 }072 073 removeTapCallback();074 }075 break;076 077 case MotionEvent.ACTION_DOWN:078 mHasPerformedLongPress = false;079 080 if (performButtonActionOnTouchDown(event)) {081 break;082 }083 084 // Walk up the hierarchy to determine if we're inside a scrolling container.085 boolean isInScrollingContainer = isInScrollingContainer();086 087 // For views inside a scrolling container, delay the pressed feedback for088 // a short period in case this is a scroll.089 if (isInScrollingContainer) {090 mPrivateFlags |= PFLAG_PREPRESSED;091 if (mPendingCheckForTap == null) {092 mPendingCheckForTap = new CheckForTap();093 }094 mPendingCheckForTap.x = event.getX();095 mPendingCheckForTap.y = event.getY();096 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());097 } else {098 // Not inside a scrolling container, so show the feedback right away099 setPressed(true, x, y);100 checkForLongClick(0);101 }102 break;103 104 case MotionEvent.ACTION_CANCEL:105 setPressed(false);106 removeTapCallback();107 removeLongPressCallback();108 break;109 110 case MotionEvent.ACTION_MOVE:111 drawableHotspotChanged(x, y);112 113 // Be lenient about moving outside of buttons114 if (!pointInView(x, y, mTouchSlop)) {115 // Outside button116 removeTapCallback();117 if ((mPrivateFlags & PFLAG_PRESSED) != 0) {118 // Remove any future long press/tap checks119 removeLongPressCallback();120 121 setPressed(false);122 }123 }124 break;125 }126 127 return true;128 }129 130 return false;131 }
上述代码是View内的,可以看到31行有个isFocusableInTouchMode,对于EditText的第一次点击,而且当前焦点不是此EditText,那就会requestFocus,去获取焦点,focusTaken会变true,48行的if快就不执行,所以不调用performClick,也就不会调用OnClick。当第二次点击EditText时,31行isFocused会为true,就不在获取焦点,focusTaken为false,就可以进入48行的if块,能执行performClick,执行OnClick。
EditText如何弹出软键盘的呢?
参考文献
http://blog.csdn.net/guolin_blog/article/details/9097463
http://jakend.iteye.com/blog/764521
http://blog.csdn.net/guolin_blog/article/details/9097463
http://blog.csdn.net/guolin_blog/article/details/9153747
- android点击事件(View)
- Android view点击事件
- Android:View点击事件
- Android学习(9) -- 点击事件中的View
- 【Android学习】View点击事件的分发机制(一)
- 【Android学习】View点击事件分发机制(二)
- android view点击事件无效 OnClickListener
- Android View 点击事件的分发机制
- android...View的点击事件传递详解,
- Android中View点击事件传递(一)
- Android中View点击事件传递(二)
- Android代码练习:View的点击事件
- Android自定义View与添加点击事件
- Android自定义view的点击事件
- Android中父View和子view的点击事件
- Android中父View和子view的点击事件
- Android之View和View点击事件坐标系
- Android中父View和子view的点击事件
- android悬浮窗口的实现
- 电力大数据
- android studio启动问题
- 算法学习 - 图的拓扑排序
- listview加载刷新加载更多的逻辑
- android点击事件(View)
- 如何记录Listview中item的点击状态
- ceph存储 快速传输大数据(tar+lz4+pv)
- Linux C编程一站式学习第一章
- hdu1867
- Objective-C 类的初始化
- c/c++中的数组指针,指针数组,常量指针和指针常量
- 构建高可扩Web架构和分布式系统实战(下)
- Android NDK 下 FFMPEG 的编译选项详解