andorid,把控件置于最顶端。bringToFront的意外发现

2018-01-23 02:22:17

 最近在项目终于到了View.bringToFront()方法,简单看了下其源码,在这儿总结一下。

  bringToFront方法在SDK中的说明是“Change the view's z order in the tree, so it's on top of other sibling views”,翻译过来就是改变view的z轴,使其处在他父view的顶端。关于bringToFront的实现,网上有很多资料介绍,大体来说就是将这个view从父view中移除,然后再加入父view的顶端。具体实现如何呢?

  bringToFront的具体实现要参看ViewGroup中的bringChildToFront方法。代码很简单,如下:

复制代码

  public void bringChildToFront(View child) {        int index = indexOfChild(child);        if (index >= 0) {
            removeFromArray(index);
            addInArray(child, mChildrenCount);
            child.mParent = this;
        }
    }

复制代码

  分两步,首先remove,然后add,实际上ViewGroup维持了一个View数组,addInArray方法会把这个child加入到数组最末端,在draw的时候,将依次画数组中的child,最后一个自然就放到了顶端。

  removeFromArray方法中有一段奇怪的代码:

if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
            children[index].mParent = null;
}

  mTransitioningViews官方解释如下:

  The set of views that are currently being transitioned. This list is used to track views being removed that should not actually be removed from the parent yet because they are being animated.

  正如上述,当某个child正在做动画的时候(这里指android.app.Fragment和android.animation.LayoutTransition移除view的动画),还不能删除这个child,应该等到动画结束,所以在ViewGroup中暂时保留这个child,直到动画真正结束后再真正删除。ViewGroup有两个成对出现的方法:startViewTransition和endViewTransition。在startViewTransition方法中将child加入mTransitioningViews中,在endViewTransition中最终执行view.dispatchDetachedFromWindow(),并在函数最后调用invalidate()。

  值得一提的是,在removeView的时候,如果当前child在mTransitioningViews中,ViewGroup并不会执行view.dispatchDetachedFromWindow(),也不会设置当前view的mParent为空。

  没想到分析bringToFront方法竟然还意外发现一个mTransitioningViews,由此可以看到一个潜在的问题,如果我们在执行LayoutTransition的DISAPPEARING动画同时removeView,这时子view还并未删除,如果直接将子view加入其它ViewGroup中则会报错“The specified child already has a parent. You must call removeView() on the child's parent first.” 因为此时这个view还未从上一个ViewGroup中删除。


  • 2018-02-04 23:46:16

    Android SQLite 升级数据库,在原有数据库的基础上添加一列

    原本以为很简单的问题,直接在原来创建数据库的语句中加上需要添加的列new_column,但是运行时发现,应用crash。原因是,原有数据库文件已经存在的情况下并不会重新创建数据库,也就是说此时数据库中并没有new_column列,这个时候,运行query()来查询数据库如果包括new_column列,就会导致应用crash。

  • 2018-02-06 22:23:01

    HTML5 Canvas 的事件处理

    DOM是Web前端领域非常重要的组成部分,不仅在处理HTML元素时会用到DOM,图形编程也同样会用到。比如SVG绘图,各种图形都是以DOM节点的形式插入到页面中,这就意味着可以使用DOM方法对图形进行操作。比如有一个<path id=”p1″>元素,可以直接用jquery增加click事件$(‘#p1’).click(function(){…})”。然而这种DOM处理方法在HTML5的Canvas里不再适用,Canvas使用的是另外一套机制,无论在Canvas上绘制多少图形,Canvas都是一个整体,图形本身实际都是Canvas的一部分,不可单独获取,所以也就无法直接给某个图形增加JavaScript事件。

  • 2018-02-09 01:32:48

    PHP时间戳和日期相互转换

    在php中我们要把时间戳转换日期可以直接使用date函数来实现,如果要把日期转换成时间戳可以使用strtotime()函数实现,下面我来给大家举例说明。

  • 2018-02-09 02:57:46

    如何防止多次打开Activity?

    android:launchMode="singleTask" 加上这句,每次打开如果已有此activity,就会打开原来的实例,否则会创建新的activity​

  • 2018-02-17 18:51:26

    Context都没弄明白,还怎么做Android开发?

    作为Android开发者,不知道你有没有思考过这个问题,Activity可以new吗?Android的应用程序开发采用JAVA语言,Activity本质上也是一个对象,那上面的写法有什么问题呢?估计很多人说不清道不明。