自定义View的一些注意点

View的坐标系

View坐标系

自定义View重写OnTouchEvent(MotionEvent event)方法后Android Studio提示重写performClick(方法)

我们在重写OnTouchEvent(MotionEvent event)方法时,Android Studio总是提示我们“Custom View XXXX overrides onTouchEvent but no performClick more…”, 分析performClick()源码后我们知道:

 public boolean performClick() {
        // We still need to call this method to handle the cases where performClick() was called
        // externally, instead of through performClickInternal()
        notifyAutofillManagerOnClick();

        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);

        notifyEnterOrExitForAutoFillIfNeeded(true);

        return result;
    }

performClick() 方法中实际上会执行CustomView.setOnClickListener(){}中的事件(前提是我们设置了setOnClickListener()),而我们重写OnTouchEvent后,setOnClickListener可能会得不到执行,当然,我们发现自己即使不关心Android Studio给出的这个警告,仍然运行正常,我们仔细想想也符合逻辑:既然自定义View重写了OnTouchEvent()方法,那么就不应该再设置setOnClickListener监听事件,Android Studio给出提示只是为了当开发者重写onTouchEvent方法后,又在外部给这个自定义View设置了监听事件,如何能执行到监听事件(setOnClickListener是事件分发的最后一层)。
其实消不消除这个waring都没什么问题,我们在这里说下如何消除这个waring, 首先在控件中重写performClick方法,然后在onTouchEvent中的某个Action行为中执行performClick(),如下所示,

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                performClick();
                break;
        }

        return false;
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }

不过,我们还发现,我们即使重写了onTouchEvent方法,依旧可以执行到setOnClickListener级别(我在上面也说了,它并不是执行不到,只是在某些情况下执行不到), 我们在onTouchEvent方法末尾一般会返回父类该方法执行的结果。

@Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

我们分析View的onTouchEvent源代码得知,

public boolean onTouchEvent(MotionEvent event) {
switch (action) {
                case MotionEvent.ACTION_UP:
                     if (mPerformClick == null) {
                              mPerformClick = new PerformClick();
                        }
                    if (!post(mPerformClick)) {
                             performClickInternal();
                         }
                 }
}

private final class PerformClick implements Runnable {
        @Override
        public void run() {
            recordGestureClassification(TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP);
            performClickInternal();
        }
    }


 private boolean performClickInternal() {
        // Must notify autofill manager before performing the click actions to avoid scenarios where
        // the app has a click listener that changes the state of views the autofill service might
        // be interested on.
        notifyAutofillManagerOnClick();

        return performClick();
    }

在父类的Up事件中,同样也会执行performClick(),进而我们就看到了,我们设置的自定义View的setOnClickListener也执行到了。
个人总结:自定义的View如果在onTouchEvent(MotionEvent event)中没有使用过super.onTouchEvent(event)代码的话(在一些文章中也见过直接根据情况返回true/false的),这时候如果也在外部(比如Activity)给这个自定义View设置了setOnClickListener,那么我们就需要在onTouchEvent中根据具体情况来决定把performClick()代码放在哪个位置合适(一般也是放在UP事件中),然后在控件中重写performClick()。不建议在onTouchEvent(MotionEvent event)方法中performClick()与super.onTouchEvent(event)都出现。

Paint关于PorterDuffXfermode的几个问题

PorterDuffXfermode类似数学中关于图形之间的交集,并集,差集问题,需要注意的是:dst是下层,先画上去的图形;src是上层,后画上的图形;用句谚语来形容的话就是“后来者居上”。
首先看下google给出的官方样例,
在这里插入图片描述
但我们真正使用的时候回发现实际情况与此图并不完全符合,具体情况可以查看此博客:https://blog.youkuaiyun.com/wingichoy/article/details/50534175,
这里我们主要说下结论:
首先PorterDuffXfermode会受硬件加速的影响,建议自定义View如果使用PorterDuffXfermode关闭硬件加速;
其次,google给出的官方图成立的前提是存在两个bitmap

PorterDuffXfermode的各种模式详解https://www.jianshu.com/p/0f64daf202f2
###ViewGroup 中 onInterceptTouchEvent()的几条结论。

  • down事件首先传递到onInterceptTouchEvent()方法;
  • 如果该ViewGroup的onInterceptTouchEvent()方法在接收到down事件并处理完成后return false,则内部View也将会获取到down事件,后续的move,up事件也将继续先传递到该ViewGroup中,之后一样传递给最终的目标childView的onTouchEvent()处理。
  • 如果该ViewGroup的onInterceptTouchEvent()接收down事件并处理完成后return true,则表明子View不需要接收接收事件,后续的move,up事件也不再传递给onInterceptTouchEvent(), 该事件接着交给ViewGroup自身的onTouchEvent()方法去执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值