深入理解:View和ViewGroup如何才能获取焦点

2024-04-29 17:32

本文主要是介绍深入理解:View和ViewGroup如何才能获取焦点,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

简介

一般我们知道View请求获取焦点调用requestFocus方法

查找流程

我们看看requestFocus方法

public final boolean requestFocus() {return requestFocus(View.FOCUS_DOWN);}

requestFocus中调用了requestFocus(View.FOCUS_DOWN) 我们接着看

public final boolean requestFocus(int direction) {return requestFocus(direction, null);}

又调用了 requestFocus(direction, null) 我们接着看

public boolean requestFocus(int direction, Rect previouslyFocusedRect) {return requestFocusNoSearch(direction, previouslyFocusedRect);}

注意:ViewGroup重写了requestFocus(direction, null)此方法,在里面处理焦点先给子View还是先给自己处理

又调用了requestFocusNoSearch(direction, previouslyFocusedRect) 着看

private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) {// need to be focusableif (!canTakeFocus()) { //判断是否具可以获取焦点return false;}// need to be focusable in touch mode if in touch modeif (isInTouchMode() &&(FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) {return false;}// need to not have any parents blocking usif (hasAncestorThatBlocksDescendantFocus()) {return false;}if (!isLayoutValid()) {mPrivateFlags |= PFLAG_WANTS_FOCUS;} else {clearParentsWantFocus();}handleFocusGainInternal(direction, previouslyFocusedRect);return true;}

看到这个方法我们发现了一个方法 canTakeFocus 这个方法就是判断View是否可以聚焦,不可聚焦直接返回false

private boolean canTakeFocus() {return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) //View可见&& ((mViewFlags & FOCUSABLE) == FOCUSABLE)//Viewfocuable&& ((mViewFlags & ENABLED_MASK) == ENABLED)//View enable&& (sCanFocusZeroSized || !isLayoutValid() || hasSize()); //sCanFocusZeroSized 这个值在Android P以下默认就是true,也就是在Android P以下一个View没有大小也是可聚焦的;}

看到这儿我们就明白了view获取焦点的条件是:

可见性为 VISIBLE 并且 focusable并且状态 enabled 并且有尺寸(有尺寸不管在哪个版本都是可聚焦的)。

ViewGroup的重写的方法

ViewGroup重写了 requestFocusNoSearch(direction, previouslyFocusedRect) 方法,看下

 @Overridepublic boolean requestFocus(int direction, Rect previouslyFocusedRect) {if (DBG) {System.out.println(this + " ViewGroup.requestFocus direction="+ direction);}int descendantFocusability = getDescendantFocusability(); //获取descendantFocusability 的值boolean result;switch (descendantFocusability) {case FOCUS_BLOCK_DESCENDANTS://是BLOCK则调用父类的方法,直接进入自己的聚焦流程result = super.requestFocus(direction, previouslyFocusedRect);break;case FOCUS_BEFORE_DESCENDANTS: {//如果是before则先自己尝试聚焦,如果自己不能聚焦则去查找子View是否可以聚焦final boolean took = super.requestFocus(direction, previouslyFocusedRect);result = took ? took : onRequestFocusInDescendants(direction,previouslyFocusedRect);break;}case FOCUS_AFTER_DESCENDANTS: {//如果是AFTER 先给子View去聚焦,子View没有处理焦点则自己去请求聚焦final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);result = took ? took : super.requestFocus(direction, previouslyFocusedRect);break;}default:throw new IllegalStateException("descendant focusability must be "+ "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "+ "but is " + descendantFocusability);}if (result && !isLayoutValid() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) {mPrivateFlags |= PFLAG_WANTS_FOCUS;}return result;}

首先获取descendantFocusability 的值

  • 如果FOCUS_BLOCK_DESCENDANTS则调用父类的方法,直接进入自己的聚焦流程,不给子View处理焦点的机会
  • 如果是FOCUS_BEFORE_DESCENDANTS则先自己尝试聚焦,如果自己不能聚焦则去查找子View聚焦
  • 如果是FOCUS_AFTER_DESCENDANTS先给子View去聚焦,子View没有处理焦点则自己去请求聚焦

descendantFocusability 决定了ViewGroup和子View请求焦点的先后顺序

descendantFocusability
xml属性  android:descendantFocusability=""
方法:setDescendantFocusability(int focusability)
取值:FOCUS_BEFORE_DESCENDANTS或者FOCUS_AFTER_DESCENDANTS或者FOCUS_BLOCK_DESCENDANTSViewGroup中 initViewGroup方法设置了默认值 FOCUS_BEFORE_DESCENDANTS

结论

  • 对于ViewGroup,我们调用ViewGroup的requestFocus方法时
    • 如果是FOCUS_BLOCK_DESCENDANTS,ViewGroup获取焦点和子View是一样的
    • 非FOCUS_BLOCK_DESCENDANTS的情况,焦点可能是ViewGroup获取到也可能是子View获取到

ViewGroup中descendantFocusability 决定了子View和ViewGroup获取焦点的先后顺序

无论是View还是ViewGroup,这个对象本身获取焦点:
必须同时满足三个条件:可见性Visible、focusable为true、状态为enable
对应代码就是setFocusable(true),setVisbility(View.Visible)、setEnable(true)。

这篇关于深入理解:View和ViewGroup如何才能获取焦点的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/946708

相关文章

Python版本信息获取方法详解与实战

《Python版本信息获取方法详解与实战》在Python开发中,获取Python版本号是调试、兼容性检查和版本控制的重要基础操作,本文详细介绍了如何使用sys和platform模块获取Python的主... 目录1. python版本号获取基础2. 使用sys模块获取版本信息2.1 sys模块概述2.1.1

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

Java发送SNMP至交换机获取交换机状态实现方式

《Java发送SNMP至交换机获取交换机状态实现方式》文章介绍使用SNMP4J库(2.7.0)通过RCF1213-MIB协议获取交换机单/多路状态,需开启SNMP支持,重点对比SNMPv1、v2c、v... 目录交换机协议SNMP库获取交换机单路状态获取交换机多路状态总结交换机协议这里使用的交换机协议为常

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe

C#使用iText获取PDF的trailer数据的代码示例

《C#使用iText获取PDF的trailer数据的代码示例》开发程序debug的时候,看到了PDF有个trailer数据,挺有意思,于是考虑用代码把它读出来,那么就用到我们常用的iText框架了,所... 目录引言iText 核心概念C# 代码示例步骤 1: 确保已安装 iText步骤 2: C# 代码程

Spring Boot中获取IOC容器的多种方式

《SpringBoot中获取IOC容器的多种方式》本文主要介绍了SpringBoot中获取IOC容器的多种方式,包括直接注入、实现ApplicationContextAware接口、通过Spring... 目录1. 直接注入ApplicationContext2. 实现ApplicationContextA

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

SpringBoot 获取请求参数的常用注解及用法

《SpringBoot获取请求参数的常用注解及用法》SpringBoot通过@RequestParam、@PathVariable等注解支持从HTTP请求中获取参数,涵盖查询、路径、请求体、头、C... 目录SpringBoot 提供了多种注解来方便地从 HTTP 请求中获取参数以下是主要的注解及其用法:1

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

深入理解go中interface机制

《深入理解go中interface机制》本文主要介绍了深入理解go中interface机制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前言interface使用类型判断总结前言go的interface是一组method的集合,不