Android RecyclerView item选中放大被遮挡问题

在Android TV上一般选中某个View, 都会有焦点突出放大的效果, 但是当在RecyclerView中(ListView或GridView)实现当item View执行放大动画后会被其他的item View遮挡.
原因是: RecyclerView的机制是越靠后的View z-order越高, 所以bringToFront方法是不管用的.

在实现针对TV端的自定义控件 TvRecyclerView 时遇到此问题, 最后的解决方案是:
自定义RecyclerView, 重写getChildDrawingOrder方法, 让选中的item最后绘制, 这样就不会让其他view遮挡.

public class ScaleRecyclerView extends RecyclerView {

    private int mSelectedPosition = 0;

    public ScaleRecyclerView(Context context) {
        super(context);
        init();
    }

    public ScaleRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ScaleRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        //启用子视图排序功能
        setChildrenDrawingOrderEnabled(true);
    }

    @Override
    public void onDraw(Canvas c) {
        mSelectedPosition = getChildAdapterPosition(getFocusedChild());
        super.onDraw(c);
    }

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {
        int position = mSelectedPosition;
        if (position < 0) {
            return i;
        } else {
            if (i == childCount - 1) {
                if (position > i) {
                    position = i;
                }
                return position;
            }
            if (i == position) {
                return childCount - 1;
            }
        }
        return i;
    }
}

最好还需要设置RecyclerView的父类的属性: clipChildren = false, clipToPadding = false, 避免边缘的子view被父类遮挡.

"http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    android:clipToPadding="false">

    .support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="245dp"
        android:layout_centerInParent="true" />

使用介绍:
(1) 自定具有放大缩小的布局:

public class FocusRelativeLayout extends RelativeLayout {

    private Animation scaleSmallAnimation;
    private Animation scaleBigAnimation;

    public FocusRelativeLayout(Context context) {
        super(context);
    }

    public FocusRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FocusRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
        if (gainFocus) {
            getRootView().invalidate();
            zoomOut();
        } else {
            zoomIn();
        }
    }

    private void zoomIn() {
        if (scaleSmallAnimation == null) {
            scaleSmallAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.anim_scale_small);
        }
        startAnimation(scaleSmallAnimation);
    }

    private void zoomOut() {
        if (scaleBigAnimation == null) {
            scaleBigAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.anim_scale_big);
        }
        startAnimation(scaleBigAnimation);
    }
}

(2) 放大动画xml配置如下:


<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:shareInterpolator="false">
    <scale
        android:duration="150"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:pivotX="50.0%"
        android:pivotY="50.0%"
        android:repeatCount="0"
        android:toXScale="1.08"
        android:toYScale="1.08" />
set>

(3) 主布局xml:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    android:clipToPadding="false">

    <com.app.tvviewpager.ScaleRecyclerView
        android:id="@+id/main_recyclerView"
        android:layout_width="match_parent"
        android:layout_height="210dp"
        android:layout_centerInParent="true"/>

RelativeLayout>

(4) 子视图的xml:

<FocusRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rl_main_layout"
    android:layout_width="300dp"
    android:layout_height="210dp"
    android:focusable="true">

    <TextView
        android:layout_width="300dp"
        android:layout_height="30dp"
        android:layout_alignParentBottom="true" />
FocusRelativeLayout>

(5) adapter配置:

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private Context mContext;
    private OnItemStateListener mListener;
    private static int[] mColorIds = {R.color.amber, R.color.brown, R.color.cyan,
            R.color.deepPurple, R.color.green, R.color.lightBlue, R.color.lightGreen,
            R.color.lime, R.color.orange, R.color.pink, R.color.cyan, R.color.deepPurple};

    MyAdapter(Context context) {
        mContext = context;
    }

    public void setOnItemStateListener(OnItemStateListener listener) {
        mListener = listener;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new RecyclerViewHolder(View.inflate(mContext, R.layout.item_recyclerview, null));
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        final RecyclerViewHolder viewHolder = (RecyclerViewHolder) holder;
        viewHolder.mRelativeLayout.setBackgroundColor(ContextCompat.getColor(mContext, mColorIds[position]));
    }

    @Override
    public int getItemCount() {
        return mColorIds.length;
    }

    private class RecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        FocusRelativeLayout mRelativeLayout;

        RecyclerViewHolder(View itemView) {
            super(itemView);
            mRelativeLayout = (FocusRelativeLayout) itemView.findViewById(R.id.rl_main_layout);
            mRelativeLayout.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            if (mListener != null) {
                mListener.onItemClick(v, getAdapterPosition());
            }
        }
    }

    public interface OnItemStateListener {
        void onItemClick(View view, int position);
    }
}

(6) Activity中的配置:

public class RecyclerActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler);

        final ScaleRecyclerView recyclerView = (ScaleRecyclerView) findViewById(R.id.main_recyclerView);

        GridLayoutManager manager = new GridLayoutManager(RecyclerActivity.this, 1);
        manager.setOrientation(LinearLayoutManager.HORIZONTAL);
        manager.supportsPredictiveItemAnimations();
        recyclerView.setLayoutManager(manager);

        int itemSpace = getResources().
                getDimensionPixelSize(R.dimen.recyclerView_item_space);
        recyclerView.addItemDecoration(new SpaceItemDecoration(itemSpace));
        final MyAdapter mAdapter = new MyAdapter(RecyclerActivity.this);
        recyclerView.setAdapter(mAdapter);
    }

    private class SpaceItemDecoration extends RecyclerView.ItemDecoration {

        private int space;

        SpaceItemDecoration(int space) {
            this.space = space;
        }

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                                   RecyclerView.State state) {
            outRect.left = space;
        }
    }
}

效果图如下:

Android RecyclerView item选中放大被遮挡问题_第1张图片

你可能感兴趣的:(android,笔记)