openeim key事件本身就key down,up,long pressed这几种

来源:互联网 发布:thinking in java答案 编辑:程序博客网 时间:2024/05/27 03:25

原文:openeim key事件本身就key down,up,long pressed这几种 ...

/*
前面OpenEIM 与大家看了key事件的处理流程,相信大家对此已经有了新的认识,这篇文章我打算带领大家来看看稍微复杂些的touch事件的处理流程。说它复杂是因为key事件本身就key down,up,long pressed这几种,而touch事件支持多指触摸,给人的感觉好像同时在发生多个touch事件一样,所以要处理的手指是多个而不是固定的一个,逻辑上当然也就复杂些了。不过本质上还都是down、up、long pressed,touch的话还有move事件。接下来让我们直接进入本文的正题。
*/

/**
     * Pass the touch screen motion event down to the target view, or this openeim
     * view if it is the target.
     *
     * @param event The motion event to be dispatched.
     * @return True if the event was handled by the view, false otherwise.
     */
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);
        }

        if (onFilterTouchEventForSecurity(event)) { // 一般都成立
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) { // 先在ENABLED状态下尝试调用onTouch方法
                return true; // 如果被onTouch处理了,则直接返回true
            }
            // 从这里我们可以看出,当你既设置了OnTouchListener又设置了OnClickListener,那么当前者返回true的时候,
            // onTouchEvent没机会被调用,当然你的OnClickListener也就不会被触发
            if (onTouchEvent(event)) {
                return true;
            }
        }

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }
        return false; // 上面的都没处理,则返回false
    }

    /**
     * Implement this method to handle touch screen motion events.
     * <p>
     * If this method is used to detect click actions, it is recommended that
     * the actions be performed by implementing and calling
     * {@link #performClick()}. This will ensure consistent system behavior,
     * including:
     * <ul>
     * <li>obeying click sound preferences
     * <li>dispatching OnClickListener calls
     * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when
     * accessibility features are enabled
     * </ul>
     *
     * @param event The motion event.
     * @return True if the event was handled, false otherwise.
     */
    public boolean onTouchEvent(MotionEvent event) { // View对touch事件的默认处理逻辑
        final int viewFlags = mViewFlags;

        if ((viewFlags & ENABLED_MASK) == DISABLED) { // DISABLED的状态下
            if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
                setPressed(false); // 复原如果之前是PRESSED状态
            }
            // A disabled view that is clickable still consumes the touch
            // events, it just doesn't respond to them.
            return (((viewFlags & CLICKABLE) == CLICKABLE || // CLICKABLE或LONG_CLICKABLE的view标记为对事件处理了,
                    (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); // 只不过是以do nothing的方式处理了。
        }

        if (mTouchDelegate != null) {
            if (mTouchDelegate.onTouchEvent(event)) { // 如果有TouchDelegate的话,优先交给它处理
                return true; // 处理了返回true,否则接着往下走
            }
        }

        if (((viewFlags & CLICKABLE) == CLICKABLE || // View能对touch事件响应的前提要么是CLICKABLE要么是LONG_CLICKABLE
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_UP: // UP事件
                    // 如果外围有可以滚动的parent的话,当按下时会设置这个标志位
                    boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
                    if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { // 按下了或者预按下了
                        // take focus if we don't have it already and we should in
                        // touch mode.
                        boolean focusTaken = false;
                        // 这行代码就是我们上篇博客中说的,设置了FocusableInTouchMode后,View在点击的时候就会
                        // 尝试requestFocus(),并将focusToken设置为true
                        if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
                            focusTaken = requestFocus(); // 能进来这个if,一般都会返回true
                        }

                        if (prepressed) {
                            // The button is being released before we actually
                            // showed it as pressed.  Make it show the pressed
                            // state now (before scheduling the click) to ensure
                            // the user sees it.
                            setPressed(true); // 设置为按下状态,会刷新View的状态
                       }

                        if (!mHasPerformedLongPress) { // 如果没有长按发生的话
                            // This is a tap, so remove the longpress check
                            removeLongPressCallback(); // 移除长按callback

                            // Only perform take click actions if we were in the pressed state
                            if (!focusTaken) { // 看到没,focusTaken是false才会进去下面的if语句
                                // 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)) { // 如果post失败了,则直接调用performClick()方法
                                    performClick(); // 这2行代码会触发onClickListener
                                }
                            }
                        }

                        if (mUnsetPressedState == null) {
                            mUnsetPressedState = new UnsetPressedState(); // unset按下状态的
                        }

                        if (prepressed) {
                            postDelayed(mUnsetPressedState,
                                    ViewConfiguration.getPressedStateDuration());
                        } else if (!post(mUnsetPressedState)) {
                            // If the post failed, unpress right now
                            mUnsetPressedState.run();
                        }
                        removeTapCallback();
                    }
                    break;

                case MotionEvent.ACTION_DOWN:
                    mHasPerformedLongPress = false;

                    if (performButtonActionOnTouchDown(event)) {
                        break;
                    }

                    // Walk up the hierarchy to determine if we're inside a scrolling container.
                    boolean isInScrollingContainer = isInScrollingContainer();

                    // For views inside a scrolling container, delay the pressed feedback for
                    // a short period in case this is a scroll.
                    if (isInScrollingContainer) { // 如果是在可以滚动的container里面的话
                        mPrivateFlags |= PFLAG_PREPRESSED; // 设置pre按下标志位
                        if (mPendingCheckForTap == null) {
                            mPendingCheckForTap = new CheckForTap();
                        } // 延迟pressed feedback
                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                    } else {
                        // Not inside a scrolling container, so show the feedback right away
                        setPressed(true); // 否则直接显示pressed feedback
                        checkForLongClick(0); // 并启动长按检测
                    }
                    break;

                case MotionEvent.ACTION_CANCEL: // 针对CANCEL事件的话,恢复各种状态,移除各种callback
                    setPressed(false);
                    removeTapCallback();
                    removeLongPressCallback();
                    break;

                case MotionEvent.ACTION_MOVE: // MOVE事件
                    final int x = (int) event.getX();
                    final int y = (int) event.getY();

                    // Be lenient about moving outside of buttons
                    if (!pointInView(x, y, mTouchSlop)) { // 如果移动到view的边界之外了,
                        // Outside button
                        removeTapCallback(); // 则取消Tap callback,这样当你松手的时候onClick不会被触发
                        if ((mPrivateFlags & PFLAG_PRESSED) != 0) { // 当已经是按下状态的话
                            // Remove any future long press/tap checks
                            removeLongPressCallback(); // 移除长按callback

                            setPressed(false); // 恢复按下状态
                        }
                    }
                    break;
            }
            return true; // 最后返回true,表示对touch事件处理过了,消费了
        }

        return false; // 既不能单击也不能长按的View,返回false,表示不处理touch事件
    }


0 0
原创粉丝点击