【问题标题】:bringToFront does not work in RecyclerViewBringToFront 在 RecyclerView 中不起作用
【发布时间】:2014-11-10 12:35:47
【问题描述】:

我想在RecyclerView 中制作一个动画,它要求一个孩子的 z-index 比另一个孩子大。但是,当我在ViewGroup 中使用bringToFront 方法时,它不起作用。

有没有什么办法可以在RecyclerView 中把孩子带到前面?

【问题讨论】:

    标签: android android-layout android-recyclerview


    【解决方案1】:

    确实,bringToFront() 没有帮助;它只是改变了其父子数组中子元素的顺序,但不会改变子元素的呈现顺序。

    如果您使用的是 API-21 或更高版本,您只需更改视图的 Z 值 (view.setZ(..)) 即可将其置于最前面。

    在 API-21 下方有一个可以使用的回调:RecyclerView.ChildDrawingOrderCallback。使用它,您可以定义应呈现子级的顺序。(您也可以将其与 API-21+ 一起使用,以防您不喜欢通过更改 Z 值获得的额外阴影。)

    例子:

    final int indexOfFrontChild = rv.indexOfChild(desiredFrontView);
    rv.setChildDrawingOrderCallback(new RecyclerView.ChildDrawingOrderCallback() {
    
        private int nextChildIndexToRender;
    
        @Override
        public int onGetChildDrawingOrder(int childCount, int iteration) {
            if (iteration == childCount - 1) {
                // in the last iteration return the index of the child 
                // we want to bring to front (and reset nextChildIndexToRender)  
                nextChildIndexToRender = 0;  
                return indexOfFrontChild;
            } else {
                if (nextChildIndexToRender == indexOfFrontChild) {
                    // skip this index; we will render it during last iteration
                    nextChildIndexToRender++;
                }
                return nextChildIndexToRender++;
            }
        }
    });
    rv.invalidate();
    

    基本上,onGetChildDrawingOrder(...) 将被调用 childCount 次,在每个 iteration 中,我们可以指定要渲染的子节点(通过返回其索引)。

    【讨论】:

    • 试过这个代码。尝试滚动 RecyclerView 时使应用程序在使用后崩溃。
    • @0101100101,你确定你的 indexOfFrontChild 在 [0, childCount-1] 的范围内吗?或者换个说法,你确定你想要的FrontView 是你的 RecyclerView 的孩子吗?
    • 两者都是。动画实际上与该代码完美配合,只是在它没有滚动之后才滚动。
    • @AlexNewman,取决于 onGetChildDrawingOrder() 的成本。上面的实现是一个非常便宜的实现。
    【解决方案2】:

    子项的顺序由 LayoutManager 控制。出于性能原因,内置 LayoutManager 有自己严格的子顺序。

    bringToFront 的当前实现只是将子级移动到子级列表的末尾,这与现有的 LayoutManager 不兼容。

    如果你的目标是 Lollipop,你可以使用setElevation 方法。 要针对旧平台,您需要一个不依赖子级顺序的自定义 LayoutManager。

    【讨论】:

    • 谢谢,但自定义 LayoutManager 可能会增加一些复杂性,我设法做了一些技巧来克隆我想要动画的视图。
    • 对这个 5 年前的答案的一些更新:RecyclerView 现在提供了一个 API 来使用 setChildDrawingOrderCallback() 覆盖绘图顺序。
    【解决方案3】:

    @Zsolt Safrany 的上述回答是基于回调总是从迭代 0 调用的假设,正如我测试的那样,这是不正确的。

    我在这里发布不依赖外部计数器的工作实现。

    //index of item you want to be displayed on top
    private int indexOfFrontChild = 2;
    
      @Override
            public int onGetChildDrawingOrder(int childCount, int iteration) {
                int childPos = iteration;
                //index must be in at least smaller than all children's
                if (indexOfFrontChild < childCount) {
                    //in the last iteration we return view we want to have on top
                    if (iteration == childCount - 1) {
                        childPos = indexOfFrontChild;
                    }else if (iteration >= indexOfFrontChild) {
                        childPos = iteration + 1;
                    }
                }
                return childPos;
            }
    

    在我的情况下,项目能够改变它们的高度,因此 1 个项目可以占据整个屏幕。因此,最好检查 indexOfFrontChild 项目是否可显示

     if (indexOfFrontChild < childCount) 
    

    【讨论】:

      猜你喜欢
      • 2011-04-02
      • 2017-06-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 2021-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多