是什么

一般点击一个button,就会执行onclick 事件, 但是有些情况,我们想要点击button之后, 先获取焦点,然后再次点击一次,才执行onClick 事件。这时候,setFocusableInTouchMode 就派上用场了。

实践出真知:

布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.example.fragment.FocusableInTouchModeFragment"android:orientation="vertical"><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="bt1"android:id="@+id/bt1"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="bt2"android:id="@+id/bt2"/></LinearLayout>

代码1: 只给bt1 设置setFocusableInTouchMode

        bt1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.d(TAG, "onClick: " + bt1);}});bt1.setOnFocusChangeListener(new View.OnFocusChangeListener() {@Overridepublic void onFocusChange(View v, boolean hasFocus) {Log.d(TAG, "onFocusChange: " + bt1);}});bt1.setFocusableInTouchMode(true);bt2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.d(TAG, "onClick: " + bt2);}});bt2.setOnFocusChangeListener(new View.OnFocusChangeListener() {@Overridepublic void onFocusChange(View v, boolean hasFocus) {Log.d(TAG, "onFocusChange: " + bt2);}});

我们看下打印:

2021-03-29 20:24:39.201 9863-9863/com.pipiyang.cn03 D/FocusableInTouchModeFra: onFocusChange: androidx.appcompat.widget.AppCompatButton{2988e98 VFED..C.. .F.P..ID 0,0-1440,175 #7f080091 app:id/bt1}
2021-03-29 20:24:45.872 9863-9863/com.pipiyang.cn03 D/FocusableInTouchModeFra: onClick: androidx.appcompat.widget.AppCompatButton{f5b73f3 VFED..C.. ...P.... 0,175-1440,350 #7f080092 app:id/bt2}
2021-03-29 20:24:52.783 9863-9863/com.pipiyang.cn03 D/FocusableInTouchModeFra: onClick: androidx.appcompat.widget.AppCompatButton{2988e98 VFED..C.. .F.P.... 0,0-1440,175 #7f080091 app:id/bt1}

bt1 因为设置了setFocusableInTouchMode,第一次点击会获取焦点,第二次点击才会触发onClick,而bt2 直接响应了onClick.

代码2: 两个bt都设置setFocusableInTouchMode

        bt1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.d(TAG, "onClick: " + bt1);}});bt1.setOnFocusChangeListener(new View.OnFocusChangeListener() {@Overridepublic void onFocusChange(View v, boolean hasFocus) {Log.d(TAG, "onFocusChange: " + bt1);}});bt1.setFocusableInTouchMode(true);bt2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.d(TAG, "onClick: " + bt2);}});bt2.setFocusableInTouchMode(true);bt2.setOnFocusChangeListener(new View.OnFocusChangeListener() {@Overridepublic void onFocusChange(View v, boolean hasFocus) {Log.d(TAG, "onFocusChange: " + bt2);}});
2021-03-29 20:26:36.830 10074-10074/com.pipiyang.cn03 D/FocusableInTouchModeFra: onFocusChange: androidx.appcompat.widget.AppCompatButton{65c8907 VFED..C.. .F.P..ID 0,175-1440,350 #7f080092 app:id/bt2}
2021-03-29 20:26:39.886 10074-10074/com.pipiyang.cn03 D/FocusableInTouchModeFra: onFocusChange: androidx.appcompat.widget.AppCompatButton{65c8907 VFED..C.. ......ID 0,175-1440,350 #7f080092 app:id/bt2}
2021-03-29 20:26:39.886 10074-10074/com.pipiyang.cn03 D/FocusableInTouchModeFra: onFocusChange: androidx.appcompat.widget.AppCompatButton{a5c551e VFED..C.. .F.P..ID 0,0-1440,175 #7f080091 app:id/bt1}
2021-03-29 20:26:49.648 10074-10074/com.pipiyang.cn03 D/FocusableInTouchModeFra: onFocusChange: androidx.appcompat.widget.AppCompatButton{a5c551e VFED..C.. ......ID 0,0-1440,175 #7f080091 app:id/bt1}
2021-03-29 20:26:49.649 10074-10074/com.pipiyang.cn03 D/FocusableInTouchModeFra: onFocusChange: androidx.appcompat.widget.AppCompatButton{65c8907 VFED..C.. .F.P..ID 0,175-1440,350 #7f080092 app:id/bt2}

如果两个都是被设置了setFocusableInTouchMode,那么只有连续两次点击一个button,才会触发onClick,如果你点了另外一个,那么本来点击的button 就会失去焦点。你需要再次点击之前的button 获取焦点,然后再点击一次才会执行onClick。

但是一旦一个view 已经获取了焦点,而且焦点没有发生变化,那么再次点击会直接执行onClick 方法。

怎么实现的?

android.view.View#onTouchEvent

    public boolean onTouchEvent(MotionEvent event) {if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {switch (action) {case MotionEvent.ACTION_UP:mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;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;//如果是isFocusableInTouchMode 那么就调用requestFocus 方法if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {focusTaken = requestFocus();}if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {// This is a tap, so remove the longpress checkremoveLongPressCallback();// Only perform take click actions if we were in the pressed state// 如果说获取了焦点 那么就不执行onClick 了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)) {performClickInternal();}}}             }break;

我们直接看View 的onTouchEvent 方法的ACTION_UP,我们发现如果你设置了setFocusableInTouchMode,并且没有获取到焦点,那么他会首先去获取焦点,不执行onClick。

Android setFocusableInTouchMode 方法使用和源码详解相关推荐

  1. 第28课:彻底解密Spark Sort-Based Shuffle排序具体实现内幕和源码详解

    第28课:彻底解密Spark Sort-Based Shuffle排序具体实现内幕和源码详解 本文根据家林大神系列课程编写 http://weibo.com/ilovepains 为什么讲解Sorte ...

  2. Android编程之Intent源码详解

    Intent源码详解,直接开始入题: Intent源码6700多行代码,但真正核心代码 就那么几百行,大部分都用来定义常量字符串了 先来看一下 public class Intent implemen ...

  3. Android OkHttp使用和源码详解

    介绍 OkHttp 是一套处理 HTTP 网络请求的依赖库,由 Square 公司设计研发并开源,目前可以在 Java 和 Kotlin 中使用.对于 Android App 来说,OkHttp 现在 ...

  4. Android编程之DialogFragment源码详解(一)

    DialogFragment是Fragment家族成员之一,如果你把它简单的理解成Dialog,那就错了.它的确可以做作dialog显示,还可以显示出自己定义的Dialog或者AlertDialog, ...

  5. android dismiss方法,Android编程之DialogFragment源码详解(一)注:对 dismissAllowingStateLoss()理解...

    DialogFragment是Fragment家族成员之一,如果你把它简单的理解成Dialog,那就错了.它的确可以做作dialog显示,还可以显示出自己定义的Dialog或者AlertDialog, ...

  6. Android源代码介绍,Android-Log源码详解

    Log.java 源码目录:frameworks/base/core/java/android/util 编译目录:frameworks/base image.png 我惊奇的发现,Log.java里 ...

  7. Android编程之ArrayList源码详解及使用

    ArrayList 本是 java中的代码,放到android这边显得不太合适,但由于它在android开发中又大量应用,所以就放到这里,供大家学习. 相信大家对ArrayList不陌生,但要说到细节 ...

  8. Android编程之DialogFragment源码详解(二)

    接上篇,继续: 然后就是setShowsDialog(boolean showsDialog)方法.官方文档是这样解释的:控制DialogFragment是否是一个dislog,如果设置为false, ...

  9. android 远程视频监控程序源码,详解基于Android已开放源代码的远程视频监控系统教程...

    网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket.Socket的英文原义是"孔"或"插座".通常也称作"套接字 ...

最新文章

  1. 事务策略: 了解事务陷阱--转
  2. Ubuntu中安装包时提示:you might want to run 'sudo dpkg --configure -a' to correct the problem
  3. fenby C语言 P20
  4. StringBuilder 、StringBuffer 、 String
  5. TensorRT安装教程
  6. SonarQube6.2源码解析(四)
  7. java radix sort_用于Radix Sort的Java程序
  8. Mac使用技巧:在“快速查看”中查看和编辑文件
  9. Pyspark:随机森林
  10. glassfish配置Oracle数据源,GlassFish链接数据库
  11. flink本地运行及访问webui
  12. Python简单版本flappy_bird
  13. Android 使用Navigation 跳转页面时发生crash
  14. PowerQuery操作分类3
  15. java foreach标签_Java中Velocity foreach循环标签详解
  16. 椭圆曲线加密(ECC)
  17. 软件测试中Bug的生命周期以及Bug的严重等级
  18. GPS车辆定位,汽车实时在线防止公车私用!
  19. 生日贺卡---flash逐帧动画练习
  20. matlab网页制作代码

热门文章

  1. 怎么查硬盘序列号_担心硬盘体质?不妨先给硬盘做一次体检
  2. c++ gets()、scanf() 、getline()、cin读取字符、字符串
  3. skipping non-radio button in group解决方法
  4. echarts前后端交互数据_如何避免前后端在数据交互方面的相爱相杀?
  5. python中嵌套循环的运行原理_python中while嵌套循环的执行流程问题?
  6. BIO与NIO、AIO的区别(这个容易理解)
  7. linux下screen工具使用
  8. php编写TCP服务端和客户端程序
  9. corosync+pacemaker实现高可用(HA)集群(二)
  10. c#中在规定时间弹出窗体