关于Android中View的分发机制的学习总结(View篇)
来源:互联网 发布:php租房管理源码 编辑:程序博客网 时间:2024/05/22 17:49
这是我自己参考了网上许多关于View 的分发机制的文章之后的总结,可能有错误,也有解释的不对的地方,请指正。我尽量做到不打错别字,不造成阅读障碍。
说明:源码已变,但是结构思想未变,仍具有参考价值,你也可以找低的API版本。
先从设置点击事件开始
要借助一个小例子了
现在只有一个Activity,并且Activity中只有一个按钮。你应该已经知道,如果想要给这个按钮注册一个点击事件,只需要调用:
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Log.d("TAG", "onClick execute");
- }
- });
- button.setOnTouchListener(new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- Log.d("TAG", "onTouch execute, action " + event.getAction());
- return false;
- }
- });
可以看到,onTouch是优先于onClick执行的,并且onTouch执行了两次,一次是ACTION_DOWN,一次是ACTION_UP(你还可能会有多次ACTION_MOVE的执行,如果你手抖了一下)。因此事件传递的顺序是先经过onTouch,再传递到onClick。
接下来,你会发现onTouch是有返回值的,你在onTouch方法里返回true试试!结果:
厉害了!onClick不执行了,就是说OnClickListener的回调没有执行,肯定是被某个判断给抹杀了呗,而且就在onTouch返回值的判断上,没错,机智!
ViewGroup中说过,简单总结一下,你点击了button会执行button外LinearLayout(或RelativeLayout之类的)继承的ViewGroup的dispatchTouchEvent方法,然后在其中经过一系列操作会执行button的dispatchTouchEvent方法,可惜button没有这个方法,但是button继承TextView,TextView 也没有这个方法,而TextView 继承View,View有这个方法啊!可找到了!赶紧执行,上代码:
- public boolean dispatchTouchEvent(MotionEvent event) {
- if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
- mOnTouchListener.onTouch(this, event)) {
- return true;
- }
- return onTouchEvent(event);
- }
- public void setOnTouchListener(OnTouchListener l) {
- mOnTouchListener = l;
- }
- button.setOnTouchListener(new OnTouchListener() {...});
- 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;
- }
- private void postCheckForLongClick(int delayOffset) {
- mHasPerformedLongPress = false;
- // 实例化CheckForLongPress对象
- if (mPendingCheckForLongPress == null) {
- mPendingCheckForLongPress = new CheckForLongPress();
- }
- mPendingCheckForLongPress.rememberWindowAttachCount();
- // 调用PostDelayed函数发送长按事件的异步延迟消息
- postDelayed(mPendingCheckForLongPress,
- ViewConfiguration.getLongPressTimeout() - delayOffset);
- }
- public void run() {
- // 进入该函数,说明检测到了长按操作
- if (isPressed() && (mParent != null)
- && mOriginalWindowAttachCount == mWindowAttachCount) {
- if (performLongClick()) {
- mHasPerformedLongPress = true;
- }
- }
- }
- public boolean performLongClick() {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
- boolean handled = false;
- if (mOnLongClickListener != null) {
- // 回调用户实现的长按操作监听函数(OnLongClickListener)
- handled = mOnLongClickListener.onLongClick(View.this);
- }
- if (!handled) {
- // 如果OnLongClickListener的onLongClick返回false
- // 则需要继续处理该长按事件,这里是显示上下文菜单
- handled = showContextMenu();
- }
- if (handled) {
- // 长按操作事件被处理了,此时应该给用户触觉上的反馈
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- }
- return handled;
- }
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}
- if (((viewFlags & CLICKABLE) == CLICKABLE ||
- (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {...}
- 关于Android中View的分发机制的学习总结(View篇)
- 关于Android 中View的分发机制的学习与总结(ViewGroup篇)
- 【Android学习笔记】Android中View的事件分发机制
- android中view的事件分发机制
- Android中View的事件分发机制
- Android中View的事件分发机制
- Android中View的事件分发机制
- Android中View的事件分发机制
- Android中View的事件分发机制
- Android中View的事件分发机制
- Android中View的事件分发机制
- Android中View的Touch分发机制
- 【Android学习】View点击事件的分发机制(一)
- 【Android学习】View点击时间的分发机制(三)
- Android View的事件分发机制(一):View
- Android中View的事件分发机制(没有子控件的View)
- View的事件分发机制(View篇)
- View的事件分发机制总结
- 要不要用monxin商城收银系统
- Java实训和Java培训的区别
- markdownpad2-注册码-2017-02-23
- 存储过程实例
- 摇钱树 dp+贪心
- 关于Android中View的分发机制的学习总结(View篇)
- logitech webcam linux 驱动安装(适用于TX1和PC)
- 获取json中的key值
- Java中的内部类
- rsync+inotify实现文件服务器实时双向同步
- Linq to DataSet的Distinct用法
- [BoolanC++微专业] Week5笔记
- 1097. Deduplication on a Linked List
- PAT 乙级 1022. D进制的A+B (20) Java版