本篇讲焦点移动不了的问题,先下下图效果。

进入“添加网络摄像机”页面后,遥控器按下往右的按键,焦点只落在第一个框上面,再也移动不了,页面拍的不是很清楚,需要仔细看下。
正常焦点移动,是系统根据某个具体的方向去查找,然后判断每个可以获取焦点的view的坐标是否是最合适获取焦点的
经过定位:发现是三个框子的view是代码动态生成的,坐落于屏幕中的位置是通过setTranslationX确定的。

下面是出问题的代码:

 private void initSize() {LinearLayout.LayoutParams imageParams = new LinearLayout.LayoutParams(mItemWidth, mItemHeight);mImageViews.get(0).setLayoutParams(imageParams);mImageViews.get(1).setLayoutParams(imageParams);mImageViews.get(2).setLayoutParams(imageParams);FrameLayout.LayoutParams text1Params = new FrameLayout.LayoutParams(mItemWidth, ViewGroup.LayoutParams.WRAP_CONTENT);// text1Params.setMargins(mMarginLeft1, mMarginTop, 0, 0);mCameraViews.get(0).setLayoutParams(text1Params);FrameLayout.LayoutParams text2Params = new FrameLayout.LayoutParams(mItemWidth, ViewGroup.LayoutParams.WRAP_CONTENT);//text2Params.setMargins(mMarginLeft2, mMarginTop, 0, 0);mCameraViews.get(1).setLayoutParams(text2Params);FrameLayout.LayoutParams text3Params = new FrameLayout.LayoutParams(mItemWidth, ViewGroup.LayoutParams.WRAP_CONTENT);// text3Params.setMargins(mMarginLeft3, mMarginTop, 0, 0);mCameraViews.get(2).setLayoutParams(text3Params);initData();initListen();initTransmator();}private void initTransmator() {mCameraViewLayout.setTranslationY(mMarginTop);//确定第一个框的位置mCameraViews.get(0).setTranslationX(mMarginLeft1);//确定第二个框的位置mCameraViews.get(1).setTranslationX(mMarginLeft2);//确定第三个框的位置mCameraViews.get(2).setTranslationX(mMarginLeft3);}

思路:
setTranslationX是不是影响了坐标?或者view的坐标不对了?

下面进入源码分析:

FocusFinder 这个类专门负责查找焦点,里面包含着不同方向的查找条件,下面看下它的这个方法

    View findNextFocusInAbsoluteDirection(ArrayList<View> focusables, ViewGroup root, View focused,Rect focusedRect, int direction) {// initialize the best candidate to something impossible// (so the first plausible view will become the best choice)mBestCandidateRect.set(focusedRect);switch(direction) {case View.FOCUS_LEFT:mBestCandidateRect.offset(focusedRect.width() + 1, 0);break;case View.FOCUS_RIGHT:mBestCandidateRect.offset(-(focusedRect.width() + 1), 0);break;case View.FOCUS_UP:mBestCandidateRect.offset(0, focusedRect.height() + 1);break;case View.FOCUS_DOWN:mBestCandidateRect.offset(0, -(focusedRect.height() + 1));}View closest = null;int numFocusables = focusables.size();//遍历当前页面上所有的可获取焦点的viewfor (int i = 0; i < numFocusables; i++) {View focusable = focusables.get(i);// only interested in other non-root views//如果是已经获取焦点的view,跳过if (focusable == focused || focusable == root) continue;// get focus bounds of other view in same coordinate system//得到候选者view的Rectfocusable.getFocusedRect(mOtherRect);//重点看下这个方法,该方法是将view的Rect转换成坐标系root.offsetDescendantRectToMyCoords(focusable, mOtherRect);//找出最合适可以获取焦点的方法if (isBetterCandidate(direction, focusedRect, mOtherRect, mBestCandidateRect)) {mBestCandidateRect.set(mOtherRect);closest = focusable;}}//返回焦点viewreturn closest;}

经过定位,是offsetDescendantRectToMyCoords“出了问题”,该方法是将view的Rect转换成响应的坐标系,包含x,y坐标。

看下实现:

    public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {offsetRectBetweenParentAndChild(descendant, rect, true, false);}void offsetRectBetweenParentAndChild(View descendant, Rect rect,boolean offsetFromChildToParent, boolean clipToBounds) {// already in the same coord system :)if (descendant == this) {return;}ViewParent theParent = descendant.mParent;//从当前view遍历,一直到根view的直接下一个view// search and offset up to the parentwhile ((theParent != null)&& (theParent instanceof View)&& (theParent != this)) {if (offsetFromChildToParent) {//依次增加左边距-scrollxrect.offset(descendant.mLeft - descendant.mScrollX,descendant.mTop - descendant.mScrollY);if (clipToBounds) {View p = (View) theParent;boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,p.mBottom - p.mTop);if (!intersected) {rect.setEmpty();}}} else {if (clipToBounds) {View p = (View) theParent;boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,p.mBottom - p.mTop);if (!intersected) {rect.setEmpty();}}rect.offset(descendant.mScrollX - descendant.mLeft,descendant.mScrollY - descendant.mTop);}descendant = (View) theParent;theParent = descendant.mParent;}//到达根viewif (theParent == this) {if (offsetFromChildToParent) {//算上根view的left,top值。rect.offset(descendant.mLeft - descendant.mScrollX,descendant.mTop - descendant.mScrollY);} else {rect.offset(descendant.mScrollX - descendant.mLeft,descendant.mScrollY - descendant.mTop);}} else {throw new IllegalArgumentException("parameter must be a descendant of this view");}}

这段代码,是如何计算出view具体的坐标的呢?

下面我附上我画的一张图,没有考虑滑动(scroll)情况,看了这张图你就能知道了,画的不好,请忽略啊。

在该bug中,由于view调用了setTranstionX这个属性动画的方式设置了坐落在屏幕中的位置,依次在view层级树上计算的时候,这个view相关的mLeft,与mTop是缺失的。以mLeft举例,mLeft指的是view相对于父View的左边距,我们正常在xml中设置marginLeft或者代码中动态设置setMarginLeft,最后setLayoutParams都可以生效,mLeft是有值的。
setTranstionx本质上是通过动画的方式,没有调用onLayout,mLeft没有值。

项目疑难杂症记录(二):焦点移动不了相关推荐

  1. 项目疑难杂症记录(一):fragment单例导致的界面异常

    前言:之前项目中也会遇到一些头疼的问题或者难解的bug,有些可能花费不少时间精力解决了,但是没有记录,打算从本篇博客开始,记录下项目中遇到的我认为的疑难杂症,算是对自己学习的总结,如果凑巧你也看到了, ...

  2. 项目疑难杂症记录(五):fragment生命周期都回调了,却不见其页面展示

    继续记录我的疑难bug解决过程,这次要说的bug相比前几篇来说,更难定位,因为影响较大,直接导致不解决这个bug,根本就没有办法出版本,两三个同事定位了半天也没有结果,最后我自告奋勇的暂时放下手中的工 ...

  3. 项目疑难杂症记录(四):Activity被重新创建的原因分析

    在项目中遇到一个奇怪的Bug,插上带有升级包固件的U盘,选择升级框中的放弃按钮,Activity被onDestroy,随后又重新onCreate,相应的图片和日志如下: [一] 现象和日志 1.升级框 ...

  4. 项目疑难杂症记录(三):EditText获取不到焦点了?

    本篇依然讲的是焦点方面的问题,还是老样子,先看下出问题的现象,gif走起~ 从动图上可以看到,进入二级页面,焦点向下移动,编辑框没有获取到焦点,后向上移动焦点,才获取到,是不是很神奇? 我们知道Edi ...

  5. 开源项目Krita学习(二)

    开源项目Krita学习(二) 专有名词记录 nightly版本: 所谓nightly版本,通常是开发者自己维护的一个版本.白天的时候开发者们将各自的修改提交到一个中心代码库,然后在晚上做一次编译得到的 ...

  6. Vue + Spring Boot 项目实战(二十一):缓存的应用

    重要链接: 「系列文章目录」 「项目源码(GitHub)」 本篇目录 前言 一.缓存:工程思想的产物 二.Web 中的缓存 1.缓存的工作模式 2.缓存的常见问题 三.缓存应用实战 1.Redis 与 ...

  7. 古文字识别助手与众包平台——项目博客二

    古文字识别助手与众包平台--项目博客二 背景: 由于众包算法的系统是为了让更多的人通过描绘图像而获取更多的原始数据,所以在手机端的功能流程不能做的太复杂,否则用户会直接被过于复杂的流程劝退,于是,经过 ...

  8. Azure Kinect 使用记录 (二)

    Azure Kinect 使用记录 (二) 20211118 - 占坑 因项目需要,得用Azure Kinect以及它的SDK进行开发,在这里记录下心得体会,不定时更新 一.多机位同步 1.1 Tim ...

  9. Web基础之Servlet+JDBC+JSP项目实战记录(一)

    Web基础之Servlet+JDBC+JSP项目实战记录(一) 一.项目说明: 通过前面的学习,我们已经对Servlet有了一定的了解:接下来我们要结合数据库和JSP技术一步一步完成一个小型的动态we ...

最新文章

  1. Flink最锋利的武器:Flink SQL入门和实战 | 附完整实现代码
  2. qt判断读入的字符串是否含有英文_459. 重复的子字符串
  3. linux 的git的安装目录,Linux下Git安装及配置较详细-Go语言中文社区
  4. ALLyeSNO 优化版浩方 第二版 Ver 2007 06 15 清除广告 自动挤房间
  5. 著名数学大师丘成桐:我们为什么要读数学科普书
  6. actionscript 3 mysql driver_在ActionScript 3 MySql Driver连接MYSQL数据库经验分享
  7. MATLAB 随机过程基本理论
  8. ionic build android release,ionic build android -release运行报错
  9. listPageData传jsp隐藏域,在传回java
  10. Kafka之与Spring集成
  11. word怎么设置左侧显示目录大纲
  12. altium PCB文件瘦身
  13. 计算机图形图像设计构图的基本形式,设计构图的八大基本表现手法!你造吗?...
  14. FX5U MODBUS_TCP通讯
  15. git 调换提交顺序
  16. ubuntu 桌面卡死,鼠标能动但是点击无效。
  17. SpringBoot+Vue+Mybatis-plus 博客(一):完成博客后台前端登录页面、后端登录接口
  18. Python 解压rar类型文件
  19. 安装虚拟光驱时提示windows无法访问指定设备、路径或文件。可能没有权限访问该项目
  20. java properties文件 变量_properties文件和环境变量

热门文章

  1. 查看Python函数含义的快速,准确方法unique
  2. 联合概率,条件概率,边缘概率的通俗理解
  3. C语言 标准I/O库: stdio.h
  4. Microsoft SQL Server 2000整合规划
  5. md5值最大长度_豆长老之比特币-哈希值是什么11月16日分享篇
  6. python datatime 平均值_python-熊猫时间序列:时间戳列的平均值
  7. python海龟交易策略_Python的海龟交易法
  8. 苹果推出Apple Pay防欺诈功能 目前仅限于Visa
  9. 小米获京东自营安卓平板销量冠军 小米平板5 Pro全版本闪降100元
  10. 郭明錤:iPhone 13 Pro系列将有1TB储存空间