Java 自定义视图。。。覆盖onTouchEvent但不覆盖performClick

Java 自定义视图。。。覆盖onTouchEvent但不覆盖performClick,java,android,android-view,android-custom-view,Java,Android,Android View,Android Custom View,我在开发的自定义Android视图中得到了这个警告(来自问题标题) 为什么我会被警告?它背后的逻辑是什么,即为什么它是好的 当您重写onTouchEvent时,也要练习重写performClick?此警告告诉您重写performClick @Override public boolean performClick() { // Calls the super implementation, which generates an AccessibilityEvent // a

我在开发的自定义Android视图中得到了这个警告(来自问题标题)

为什么我会被警告?它背后的逻辑是什么,即为什么它是好的

当您重写onTouchEvent时,也要练习重写
performClick

此警告告诉您重写
performClick

@Override
 public boolean performClick() {
  // Calls the super implementation, which generates an AccessibilityEvent
        // and calls the onClick() listener on the view, if any
        super.performClick();

        // Handle the action for the custom click here

        return true;
 }

但这不是强制性的。因为我已经创建了一个自定义knobView,它在我面临此警告的地方运行得非常好。

某些辅助功能服务不会调用
onTouchEvent
,单击警告详细信息中的“更多…”链接可以解释这一点

它建议您为所需操作覆盖
performClick
,或者至少在
onTouchEvent
旁边覆盖它

如果您的代码更适合触摸事件,则可以使用类似于:

@Override
public boolean performClick() {
    if (actionNotAlreadyExecuted) {
        MotionEvent myEvent = MotionEvent.obtain(long downTime, long eventTime, int action, float x, float y, int metaState);
        onTouch(myView, myEvent);
    }
    return true; // register it has been handled
}
有关通过代码访问触摸事件的更多信息,请访问

目的是什么? 在其他一些答案中,您可以看到消除警告的方法,但首先要理解为什么系统希望您覆盖
performClick()

世界上有数以百万计的盲人。也许你平时不怎么想他们,但你应该。他们也使用安卓系统。“怎么做?”你可能会问。一个重要的方法是通过应用程序。它是一个屏幕阅读器,提供音频反馈。您可以通过进入设置>辅助功能>对讲来在手机中打开它。在那里完成教程。真的很有趣。现在试着闭上眼睛使用你的应用程序。你可能会发现你的应用程序在最好的情况下非常令人讨厌,在最坏的情况下完全崩溃。这对你来说是个失败,任何视力受损的人都可以快速卸载

观看谷歌的这段精彩视频,了解如何让你的应用程序变得可访问

如何覆盖
performClick()
让我们看一个示例自定义视图,看看重写
performClick()
实际上是如何工作的。我们将制作一个简单的导弹发射应用程序。自定义视图将是启动它的按钮

如果启用了对讲功能,听起来会更好,但是动画GIF不允许音频,所以你只能自己尝试

代码 activity_main.xml

注释

  • 还使用了一个
    mDownTouch
    变量,该变量似乎用于过滤掉额外的润色事件,但由于对我们的应用程序没有很好的解释或严格的必要性,我将其忽略了。如果你做了一个真正的导弹发射器应用程序,我建议你多看看这个
  • 发射导弹的主要方法(
    launch飞弹()
    )仅从
    performClick()
    调用。如果在
    onTouchEvent
    中也有它,请小心不要调用它两次。您将需要根据自定义视图的具体情况决定如何以及何时调用业务逻辑方法
  • 不要覆盖
    performClick()
    ,然后对其不做任何处理,只是为了消除警告。如果你想忽视世界上数以百万计的盲人,那么你可以压制这个警告。至少这样,你对自己的无情是诚实的

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) { ... }
    
进一步研究
  • (特别是该科)

,@shayanpourvatan我看到了这些链接。但它们和我的问题不一样。@peter.petrov它们是完全一样的。它们都有同样无用的答案——没有什么需要处理的,performClick()似乎也没有什么用处。我现在决定对此取消Lint警告。关键是您只有注释“处理自定义单击此处的操作”的部分。我应该在那里处理什么?我认为没有什么有用的事可做。我不想写无用的代码只是为了填补空白。@TheincredibleJan没有为你的(有些多余的)评论留下单独的回复,我在这里标记了你,因为这个答案应该涵盖你的大部分困惑(如果不是全部的话)。但是如果你使用:SwitchCompat.setOnTouchListener(this);在这种情况下,我无法覆盖performClick,或者我怎么能覆盖它?@David,对不起,我没有这方面的经验。不过,如果你找到了答案,请留下另一条评论。读者问题:你说,“发射导弹的主要方法(
launch飞弹()
)是从
performClick()
)调用的。如果在
ontochevent
中也有,请小心不要调用它两次。”我不知道我是否明白你的意思-你能帮我理解你所说的“如果你在
onTouchEvent
中也有它,就不要叫它两次”是什么意思吗。你指的是别的什么地方?另外,您只能从内部调用
performClick()
,对吗?或者,您的意思是说,在
onTouchEvent()
中,由于您可以获得
ACTION\u UP
ACTION\u DOWN
,所以不要同时调用这两个属性?@Reader,系统会调用
performClick()
以获取可访问性事件。在上面的代码中,我正在调用
performClick()。这意味着系统和我都可能调用
performClick()
,从而导致两次调用。我想我记得在子类化按钮或其他东西时遇到过这种情况。无论如何,如果你测试你的自定义视图,你应该能够知道有多少次调用了
performClick()
。我喜欢这个答案,我也喜欢这个说教。感谢你在让世界变得更容易接近方面发挥了自己的作用
public class CustomView extends View {

    private final static int NORMAL_COLOR = Color.BLUE;
    private final static int PRESSED_COLOR = Color.RED;

    public CustomView(Context context) {
        super(context);
        init();
    }

    public CustomView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        setBackgroundColor(NORMAL_COLOR);
    }

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

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                setBackgroundColor(PRESSED_COLOR);
                return true;

            case MotionEvent.ACTION_UP:
                setBackgroundColor(NORMAL_COLOR);

                // For this particular app we want the main work to happen
                // on ACTION_UP rather than ACTION_DOWN. So this is where
                // we will call performClick(). 
                performClick();
                return true;
        }
        return false;
    }

    // Because we call this from onTouchEvent, this code will be executed for both
    // normal touch events and for when the system calls this using Accessibility 
    @Override
    public boolean performClick() {
        super.performClick();

        launchMissile();

        return true;
    }

    private void launchMissile() {
        Toast.makeText(getContext(), "Missile launched", Toast.LENGTH_SHORT).show();
    }
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) { ... }