I\'m using RecyclerView with GridLayoutManager. The goal I want to achieve is when I click on an item, It\'ll scale up and overlaps the adjacent items. Just like the picture
According aga's answer, i use ViewCompat.setElevation(View view, float elevation) to support API prior to 21, It works like a charming.
static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View root) {
// bind views
// ...
// bind focus listener
root.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// run scale animation and make it bigger
ViewCompat.setElevation(root, 1);
} else {
// run scale animation and make it smaller
ViewCompat.setElevation(root, 0);
}
}
});
}
}
The item layout file is very simple like below:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:background="@drawable/sl_live_item" />
Try to invoke v.bringToFront() before running the animation.
If it doesn't work another variant is to use View#setElevation(float val) where val > 0. The drawback is that you'll need to set elevation back to 0 when you're deselecting the item.
1.Override the getChildDrawingOrder method.
@Override
protected int getChildDrawingOrder(int childCount, int i) {
View view = getLayoutManager().getFocusedChild();
if (null == view) {
return super.getChildDrawingOrder(childCount, i);
}
int position = indexOfChild(view);
if (position < 0) {
return super.getChildDrawingOrder(childCount, i);
}
if (i == childCount - 1) {
return position;
}
if (i == position) {
return childCount - 1;
}
return super.getChildDrawingOrder(childCount, i);
}
2.RecyclerView setChildrenDrawingOrderEnabled is true.
setChildrenDrawingOrderEnabled(true);
3.When item view has focus, invalidate its parent.
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
v.setScaleX(1.5f);
v.setScaleY(1.5f);
mRecyclerView.invalidate();
} else {
v.setScaleX(1.0f);
v.setScaleY(1.0f);
}
}
You need to do it the old way you do with normal ViewGroups, overriding the draw order of children. This example forces the first view to always be drawn last - you need to customize for your use case.
public TopForcingRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setChildrenDrawingOrderEnabled(true);
}
@Override protected int getChildDrawingOrder(int childCount, int i) {
if (i >= childCount - 1) return 0;
//when asked for the last view to draw, answer ZERO
else return i + 1;
//when asked for the i-th view to draw, answer "the next one"
}
Pay attention to off by one errors.