【发布时间】:2014-11-10 12:35:47
【问题描述】:
我想在RecyclerView 中制作一个动画,它要求一个孩子的 z-index 比另一个孩子大。但是,当我在ViewGroup 中使用bringToFront 方法时,它不起作用。
有没有什么办法可以在RecyclerView 中把孩子带到前面?
【问题讨论】:
标签: android android-layout android-recyclerview
我想在RecyclerView 中制作一个动画,它要求一个孩子的 z-index 比另一个孩子大。但是,当我在ViewGroup 中使用bringToFront 方法时,它不起作用。
有没有什么办法可以在RecyclerView 中把孩子带到前面?
【问题讨论】:
标签: android android-layout android-recyclerview
确实,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 中,我们可以指定要渲染的子节点(通过返回其索引)。
【讨论】:
子项的顺序由 LayoutManager 控制。出于性能原因,内置 LayoutManager 有自己严格的子顺序。
bringToFront 的当前实现只是将子级移动到子级列表的末尾,这与现有的 LayoutManager 不兼容。
如果你的目标是 Lollipop,你可以使用setElevation 方法。 要针对旧平台,您需要一个不依赖子级顺序的自定义 LayoutManager。
【讨论】:
setChildDrawingOrderCallback() 覆盖绘图顺序。
@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)
【讨论】: