android 关于自定义View在特殊情况下触发setPressed方法(View源码解析)


前言

最近在负责一些UI相关的工作,测试给到一个UI的bug,说是搜索框在点击的时候,旁边的’‘X’'变成按压的效果了,我转手就把bug转给负责公控的同事了,因为这个搜索框是公控同事提供的,但是公控大佬不一会就找到我说,我这里都是好的鸭,是不是你哪里没用对,我直接就晕乎了,我左看右看也没干啥鸭,于是开始对线,巴拉巴拉…但是问题还是没有解决,于是有了这篇文章.


一、为什么样式会变?

首先公控大佬给我讲了他是怎么做X的按压效果的,就是说监听了搜索框的onTouchEvent事件,然后当onTouchEvent传入的rect包含了X的时候,将其设置为点按效果,其他时候是不会对这个X控件的样式进行改变的,没办法,我只好将公控同事的源码要来,加上日志调试.

二、调试发现原因并解决

1.找到原因

加了日志发现代码并没有走到公控同事的代码逻辑当中,但是进入onTouchEvent事件时,X控件的样式已经变成点按状态了,而公控同事的demo项目,X控件的样式确实并没有改变,鉴定为G.最后监听setPressed的时候发现在点击控件时,会触发 setPressed = true 事件,随后分析VIEW 源码,定位到如下代码位置:

				
                case MotionEvent.ACTION_DOWN:
                   .....这里忽略部分代码
                    // 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) {
                        mPrivateFlags |= PFLAG_PREPRESSED;
                        if (mPendingCheckForTap == null) {
                            mPendingCheckForTap = new CheckForTap();
                        }
                        mPendingCheckForTap.x = event.getX();
                        mPendingCheckForTap.y = event.getY();
                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                    } else {
                        // Not inside a scrolling container, so show the feedback right away 
                        setPressed(true, x, y);
                        checkForLongClick(
                                ViewConfiguration.getLongPressTimeout(),
                                x,
                                y,
                                TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS);
                    }
                    break;

在View.java的源码当中的onTouchEvent方法的MotionEvent.ACTION_DOWN事件,有一个 isInScrollingContainer的醒目判断,并加上了注释,我们继续看下isInScrollingContainer方法

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public boolean isInScrollingContainer() {
        ViewParent p = getParent();
        while (p != null && p instanceof ViewGroup) {
            if (((ViewGroup) p).shouldDelayChildPressedState()) {
                return true;
            }
            p = p.getParent();
        }
        return false;
    }

可以看到会判断一个shouldDelayChildPressedState方法,然后返回true,到这里基本可以确定这就是我和公控同事触发的不一致的地方,这是一个ViewGroup的方法,点进去过后注释是这样写的:

Return true if the pressed state should be delayed for children or
descendants of this ViewGroup. Generally, this should be done for
containers that can scroll, such as a List. This prevents the pressed
state from appearing when the user is actually trying to scroll the
content. The default implementation returns true for compatibility
reasons. Subclasses that do not scroll should generally override this
method and return false.

我们机翻一下:如果应延迟此ViewGroup的子代或子代的按下状态,则返回true。通常,这应该针对可以滚动的容器(如List)进行。这防止了当用户实际试图滚动内容时出现按下状态。由于兼容性原因,默认实现返回true。不滚动的子类通常应该覆盖此方法并返回false。

2.解决

到了上面这里,我们基本可以明白,这是因为我们搜索框公控的父布局使用的可滑动的控件,导致进入isInScrollingContainer返回true,并触发了setPressed方法,然后改变了控件的样式 为点按状态,针对这个问题,我们有这几种方式可以解决.

  1. 重写公控的这个控件的setPressed方法,每次都返回false
  2. 重写父布局的shouldDelayChildPressedState方法,使其返回false
  3. 更改公控代码对 这种特殊情况做兼容
    前面两种方法改的快,但是不能确保不出其它问题,因此这个问题最后还是由公控大佬对这种情况做兼容,over

总结

通过调试和分析源码,我们找到了问题的原因和解决方法。问题是因为在可滑动的父布局中,触发了setPressed方法,导致控件样式变为点按状态。解决方法有重写setPressed方法、重写shouldDelayChildPressedState方法或者对公控代码做兼容处理。选择合适的解决方法,能够解决这个UI bug。

  • 32
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我怀里的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值