深入理解: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获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在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的集合,不

深入解析Java NIO在高并发场景下的性能优化实践指南

《深入解析JavaNIO在高并发场景下的性能优化实践指南》随着互联网业务不断演进,对高并发、低延时网络服务的需求日益增长,本文将深入解析JavaNIO在高并发场景下的性能优化方法,希望对大家有所帮助... 目录简介一、技术背景与应用场景二、核心原理深入分析2.1 Selector多路复用2.2 Buffer

Python获取浏览器Cookies的四种方式小结

《Python获取浏览器Cookies的四种方式小结》在进行Web应用程序测试和开发时,获取浏览器Cookies是一项重要任务,本文我们介绍四种用Python获取浏览器Cookies的方式,具有一定的... 目录什么是 Cookie?1.使用Selenium库获取浏览器Cookies2.使用浏览器开发者工具

Java获取当前时间String类型和Date类型方式

《Java获取当前时间String类型和Date类型方式》:本文主要介绍Java获取当前时间String类型和Date类型方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录Java获取当前时间String和Date类型String类型和Date类型输出结果总结Java获取

C#监听txt文档获取新数据方式

《C#监听txt文档获取新数据方式》文章介绍通过监听txt文件获取最新数据,并实现开机自启动、禁用窗口关闭按钮、阻止Ctrl+C中断及防止程序退出等功能,代码整合于主函数中,供参考学习... 目录前言一、监听txt文档增加数据二、其他功能1. 设置开机自启动2. 禁止控制台窗口关闭按钮3. 阻止Ctrl +

Java Spring的依赖注入理解及@Autowired用法示例详解

《JavaSpring的依赖注入理解及@Autowired用法示例详解》文章介绍了Spring依赖注入(DI)的概念、三种实现方式(构造器、Setter、字段注入),区分了@Autowired(注入... 目录一、什么是依赖注入(DI)?1. 定义2. 举个例子二、依赖注入的几种方式1. 构造器注入(Con

一文详解如何使用Java获取PDF页面信息

《一文详解如何使用Java获取PDF页面信息》了解PDF页面属性是我们在处理文档、内容提取、打印设置或页面重组等任务时不可或缺的一环,下面我们就来看看如何使用Java语言获取这些信息吧... 目录引言一、安装和引入PDF处理库引入依赖二、获取 PDF 页数三、获取页面尺寸(宽高)四、获取页面旋转角度五、判断