美文网首页RecyclerViewAndroid 进阶之路Android开发
【 Android 】使用 RecyclerView 实现页面滑

【 Android 】使用 RecyclerView 实现页面滑

作者: Tyhoo_Wu | 来源:发表于2017-09-02 16:37 被阅读268次

    示例图片:


    1.gif

    实现思路:
    开发文档要求这个页面,上半部分不动,下半部分当一个页面展示不全,是可以滑动的。
    我最初的想法是 ScrollView + RecyclerView 。但是在机器上运行之后,发现控件之间发生了冲突,RecyclerView 显示不全。经过了一段时间的思考,最终选择使用 RecyclerView + RecyclerView 实现页面滑动和多个不同类别的 item 展示。

    其实网上关于 RecyclerView 的相关文档有很多,但是我觉得都是打补丁的方法,没有真正意义上的使用 RecyclerView 。

    代码实现(核心代码部分):

    从示例图中,可以看到,整个页面分为两大部分 A 是不可以滑动的上半部分,B 是可以滑动的下半部分。而 B 又分为三个小部分,B1 是一大堆文字描述,B2 是一个用于展示有多少个演员的 RecyclerView ,B3 是一个用于展示有多少个作品的 RecyclerView 。

    那么很显然,我们要在主布局页面创建一个 RecyclerView:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
        ...
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />
    
    </LinearLayout>
    

    并在主类里面将 B1,B2,B3,按照顺序一次添加:

    public class MainActivity extends AppCompatActivity {
    
        private List<Integer> mTypeList = new ArrayList<>();
    
        ...
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initParam();
    
            ...
        }
    
        private void initParam() {
            mTypeList.add(1);   // B1
            mTypeList.add(2);   // B2
            mTypeList.add(3);   // B3
        }
    
        ...
    }
    

    然后就是我们的核心部分 Adapter ,继承 RecyclerView.Adapter<RecyclerView.ViewHolder>
    定义 B1,B2,B3 三个常量:

    private static final int TYPE_B1 = 1;
    private static final int TYPE_B2 = 2;
    private static final int TYPE_B3 = 3;
    

    重写 getItemViewType 方法,参数 position 代表 RecyclerView 的位置,而 int 型的返回值代表了布局的类型,即 B1 是 1,B2 是 2,B3 是 3。

    @Override
    public int getItemViewType(int position) {
        if (mTypeList.get(position) == 1) {         // B1
            return TYPE_B1;
        } else if (mTypeList.get(position) == 2) {  // B2
            return TYPE_B2;
        } else if (mTypeList.get(position) == 3) {  // B3
            return TYPE_B3;
        } else {
            return 0;
        }
    }
    

    自定义三个 ViewHolder:

    public class B1ViewHolder extends RecyclerView.ViewHolder {
    
        public MainDetailsViewHolder(View itemView) {
            super(itemView);
        }
    }
    
    public class B2ViewHolder extends RecyclerView.ViewHolder {
    
        public RecyclerView b2RecyclerView;
    
        public MainActorsViewHolder(View itemView) {
            super(itemView);
            aRecyclerView = itemView.findViewById(R.id.rcv_b2);
        }
    }
    
    public class B3ViewHolder extends RecyclerView.ViewHolder {
    
        public RecyclerView b3RecyclerView;
    
        public MainActorsViewHolder(View itemView) {
            super(itemView);
            aRecyclerView = itemView.findViewById(R.id.rcv_b3);
        }
    }
    

    重写 onCreateViewHolder 方法,返回一个自定义的 ViewHolder (当 RecyclerView 需要一个 ViewHolder 时会回调该方法,如果有可复用的 View 不会回调)。

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_B1) {        // B1
            View viewB1 = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_b1, parent, false);
            B1ViewHolder b1Holder = new B1ViewHolder(viewB1);
            return b1Holder;
        } else if (viewType == TYPE_B2) {  // B2
            View viewB2 = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_b2, parent, false);
            B2ViewHolder b2Holder = new B2ViewHolder(viewB2);
            return b2Holder;
        } else if (viewType == TYPE_B3) {   // B3
            View viewB3 = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_b3, parent, false);
            B3ViewHolder b3Holder = new B3ViewHolder(viewB3);
            return b3Holder;
        }
        return null;
    }
    

    重写 onBindViewHolder 方法,填充 onCreateViewHolder 方法返回的 holder 中的控(当一个 View 需要出现在屏幕上时,该方法会被回调,我们需要再该方法中根据数据来更改视图)。

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof B2ViewHolder) {
            setB2Data((B2ViewHolder) holder);
        } else if (holder instanceof B3ViewHolder) {
            setB3Data((B3ViewHolder) holder);
        }
    }
    

    重写 getItemCount 方法,获取数据的数量(告诉 RecyclerView 有多少个视图需要显示)。

    private final Context mContext;
    private final List<Integer> mTypeList;
    
    public MainAdapter(Context context, List<Integer> list) {
        this.mContext = context;
        this.mTypeList = list;
    }
    
    @Override
    public int getItemCount() {
        return mTypeList.size();
    }
    

    上面代码涉及到三个子布局 layout_b1 、layout_b2 、layout_b3 。
    layout_b1 从上面的示例图中可以看到就是一堆文字排列。
    layout_b2 、layout_b3 是我们今天的重点:RecyclerView 嵌套 RecyclerView 。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    
        ...
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/rcv_b2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    
    </LinearLayout>
    

    既然有 RecyclerView 那么就会有 Adapter ,自定义 B2 和 B3 对应的 Adapter 。
    (item 布局就不啰嗦了,很简单)

    public class B2Adapter extends RecyclerView.Adapter<B2Adapter.B2Holder> {
    
        private final Context mContext;
    
        private OnItemClickListener mListener;
    
        public B2Adapter(Context context) {
            this.mContext = context;
        }
    
        @Override
        public B2Holder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(mContext)
                    .inflate(R.layout.item_b2, parent, false);
            B2Holder holder = new B2Holder(view);
            return holder;
        }
    
        @Override
        public void onBindViewHolder(final B2Holder holder, int position) {
            if (mListener != null) {
                holder.itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        mListener.onItemClick(holder.getLayoutPosition());
                    }
                });
            }
        }
    
        @Override
        public int getItemCount() {
            return 5;
        }
    
        public class B2Holder extends RecyclerView.ViewHolder {
    
            public B2Holder(View itemView) {
                super(itemView);
            }
        }
    
        public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
            this.mListener = onItemClickListener;
        }
    }
    
    public interface OnItemClickListener {
        void onItemClick(int position);
    }
    

    B3 和 B2 类似,就不赘述了。

    自定义完 子 Adapter ,我们就要回到主 Adapter 里面去调用。

    private void setB2Data(B2ViewHolder holder) {
        setB2RecyclerView(holder.b2RecyclerView);
    }
    
    private void setB2RecyclerView(RecyclerView b2RecyclerView) {
        B2Adapter b2Adapter = new B2Adapter(mContext);
        LinearLayoutManager layoutManager = new LinearLayoutManager(mContext);
        layoutManager.setOrientation(OrientationHelper.VERTICAL);
        b2RecyclerView.setLayoutManager(layoutManager);
        b2RecyclerView.setHasFixedSize(false);
        b2RecyclerView.setAdapter(b2Adapter);
    
        b2Adapter.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(int position) {
                // TODO:
            }
        });
    }
    

    B3 和 B2 类似,就不赘述了。

    注意:
    如果我们的界面是嵌套在可以左右滑动的控件里,这时会发生焦点的问题,导致整体界面向上移动一小部分,解决办法是在布局的最外层加入:

    android:focusable="true"
    android:focusableInTouchMode="true"
    

    综上所述,就完成了 RecyclerView 的使用,避免了 ScrollView + RecyclerView 在一起使用会出现冲突的问题。

    相关文章

      网友评论

      本文标题:【 Android 】使用 RecyclerView 实现页面滑

      本文链接:https://www.haomeiwen.com/subject/hsdrjxtx.html