Android “RecyclerView”和“RecyclerView.Adapter”使用和特殊场景

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012218652/article/details/81192157

RecyclerView和RecyclerView.Adapter是现在Android使用列表时是用的类;前者是列表整个布局,后者是处理数据和单个行/列的布局进行绑定显示工作。

1. 基础用法

RecyclerView写的时候直接扔在布局里。使用时需要设置列表的排列方式。设置方式很简单,例如:

recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));

RecyclerView.Adapter是个抽象类,这个类定义了泛型的ViewHolder,在Adapter中使用。

Adapter<VH extends ViewHolder>

RecyclerView.Adapter有三个抽象方法需要实现(摘取了部分源码注释):

第一个方法

        /**
         * Called when RecyclerView needs a new {@link ViewHolder} of the given type to represent
         * an item.
         * <p>
         * This new ViewHolder should be constructed with a new View that can represent the items
         * of the given type. You can either create a new View manually or inflate it from an XML
         * layout file.
         */
        @NonNull
        public abstract VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType);

注释中可看出,当需要一个新的ViewHolder加载时,会用这个方法来获取。也就是旧的ViewHolder和需要的新的ViewHolder类型不同时调用(此处涉及ViewHolder复用机制。ViewHolder中主要是进行的findViewById从布局中获取控件的方法,复用ViewHolder也是为了减少使用findViewById时的性能消耗)。

第二个方法

        /**
         * Called by RecyclerView to display the data at the specified position. This method should
         * update the contents of the {@link ViewHolder#itemView} to reflect the item at the given
         * position.
         */
        public abstract void onBindViewHolder(@NonNull VH holder, int position);

用于数据和Item布局的绑定。具体的显示逻辑写在这个方法中。这里的参数position是列表中Item的位置,从0开始计数,类比数组。holder就是获取到的ViewHolder。

第三个方法

        /**
         * Returns the total number of items in the data set held by the adapter.
         *
         * @return The total number of items in this adapter.
         */
        public abstract int getItemCount();

返回列表中Item个数

另外有个方法

有个方法要注意,这个方法返回列表中Item的类型。可以重写这个方法来自定义Item的Type。这里的Type就是onCreateViewHolder中的参数viewType。

        /**
         * Return the view type of the item at <code>position</code> for the purposes
         * of view recycling.
         */
        public int getItemViewType(int position) {
            return 0;
        }

2.特殊场景

场景一

(Activity启动模式为standard)点击Item后进入下一个页面,从下一个页面回来后,刷新列表并将焦点放在特定的一个Item上。此时注意,刷新列表调用notifyDataSetChanged()方法。列表刷新顺序为:从之前选中的Item向后刷新,类似循环链表,将Item顺序刷新一遍。

场景二

在Android TV上,Item获取焦点使用方法为itemView.requestFocus()。需要注意ViewHolder中调用此方法:itemView.setFocusable(true)。

场景三

选中Item后,Item的布局显示放大效果,此Item会覆盖其他的Item显示。

默认情况Item会显示在RecyclerView的高度范围内,放大后Item布局超出的部分会被裁减掉显示不出来。可以调用方法recyclerView.setClipToPadding(false)【让控件可以绘制在padding里】和recyclerView.setClipChildren(false)【让子布局可以超出父布局显示】,使Item显示完全。这两个属性也可以在XML布局文件的RecyclerView的属性设置中进行设置(android:clipChildren和 android:clipToPadding)。

显示的Item如果要正常显示,需要将此Item设置为RecyclerView的Item中最后绘制的一项。调用recyclerView.setChildDrawingOrderCallback使用自定义的顺序绘制方式。这个方法的参数为ChildDrawingOrderCallback。

    /**
     * A callback interface that can be used to alter the drawing order of RecyclerView children.
     * <p>
     * It works using the {@link ViewGroup#getChildDrawingOrder(int, int)} method, so any case
     * that applies to that method also applies to this callback. For example, changing the drawing
     * order of two views will not have any effect if their elevation values are different since
     * elevation overrides the result of this callback.
     */
    public interface ChildDrawingOrderCallback {
        /**
         * Returns the index of the child to draw for this iteration. Override this
         * if you want to change the drawing order of children. By default, it
         * returns i.
         *
         * @param i The current iteration.
         * @return The index of the child to draw this iteration.
         *
         * @see RecyclerView#setChildDrawingOrderCallback(RecyclerView.ChildDrawingOrderCallback)
         */
        int onGetChildDrawingOrder(int childCount, int i);
    }

注释中可以看出,android的elevation属性会影响绘制顺序。

场景四

对在Adapter中对RecyclerView的Item进行隐藏处理。直接设置itemView.setVisible(View.GONE)隐藏后,itemView所在区域会出现一块儿空白。正确做法参考这篇文章:https://blog.csdn.net/u011060103/article/details/52780844

方案代码(摘自上面博客):

    public void setVisibility(boolean isVisible){
        RecyclerView.LayoutParams param = (RecyclerView.LayoutParams)itemView.getLayoutParams();
        if (isVisible){
            param.height = LinearLayout.LayoutParams.WRAP_CONTENT;
            param.width = LinearLayout.LayoutParams.MATCH_PARENT;
            itemView.setVisibility(View.VISIBLE);
        }else{
            itemView.setVisibility(View.GONE);
            param.height = 0;
            param.width = 0;
        }
        itemView.setLayoutParams(param);
    }

猜你喜欢

转载自blog.csdn.net/u012218652/article/details/81192157