DoToFront not working in RecyclerView

I want to make an animation in RecyclerView that requires a child to have a larger z-index than another child. However, when I used the bringToFront method in the ViewGroup , it did not work.

Is there a way to bring a child to the forefront in RecyclerView ?

+5
source share
3 answers

The order of the children is controlled by the LayoutManager. Built in LayoutManagers have their own strict order of children for performance reasons.

The current bringToFront implementation simply moves the child to the end of the list of children, which will not work well with existing layout managers.

If you are targeting Lollipop, you can use the setElevation method. To focus on older platforms, you will need a custom LayoutManager that does not rely on the order of children.

+4
source

Indeed, bringToFront() does not help; it just changes the order of the children in its parent child array, but it does not change the playback order of the children.

If you use API-21 or higher, you can simply change the Z value of the view ( view.setZ(..) ) to bring it to the forefront.

Below API-21 there is a callback you can use: RecyclerView.ChildDrawingOrderCallback . With it, you can determine in which order the children should be displayed. (You can also use this with API-21 + if you don't like the extra shadow you get by changing the Z value.)

Example:

 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(); 

Basically, onGetChildDrawingOrder(...) will be called childCount times, and in each iteration we can specify which child object should be displayed (returning its index).

+7
source

The answer above @Zsolt Safrany is based on the assumption that the callback is always called from iteration 0, which, as I checked, is incorrect.

Here I am posting a working implementation that does not relay to an external counter.

 //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; } 

In my case, objects were able to change their height so that 1 element could display the entire screen. So it's a good idea to check if indexOfFrontChild is available

  if (indexOfFrontChild < childCount) 
0
source

Source: https://habr.com/ru/post/1206559/


All Articles