美文网首页Android UIAndroid iOS开发知识库Android技术知识
【从 0 开始开发一款直播 APP】3.2 高层封装之 Adap

【从 0 开始开发一款直播 APP】3.2 高层封装之 Adap

作者: 菜鸟窝 | 来源:发表于2017-07-24 16:07 被阅读121次
    图帮主_317537_761858.png
    本文为菜鸟窝作者蒋志碧的连载。“从 0 开始开发一款直播 APP ”系列来聊聊时下最火的直播 APP,如何完整的实现一个类"腾讯直播"的商业化项目

    项目地址:http://www.cniao5.com/course/10121


    【从 0 开始开发一款直播 APP】3.1 高层封装之 Adapter — ListView & GridView
    【从 0 开始开发一款直播 APP】3.2 高层封装之 Adapter — RecyclerView 实现单布局展示
    【从 0 开始开发一款直播 APP】3.3 高层封装之 Adapter -- RecyclerView 实现多条目展示
    【从 0 开始开发一款直播 APP】3.4 高层封装之 Adapter -- RecyclerView 优雅的添加 Header、Footer


    一、前言

    之前已经讲过 ListView、GridView 的 Adapter 封装,这次将带来 RecyclerView 的封装。

    RecyclerView 是一种新的视图组,目标是为任何基于适配器的视图提供相似的渲染方式。该控件用于在有限的窗中展示大量数据集,它被作为 ListView 和 GridView 控件的继承者。

    主要有以下功能:

    1、简单数据绑定(单种 item)

    2、多布局绑定 (多种 item)

    **3、设置监听 **

    4、优雅的添加 header、footer

    老规矩,先封装 ViewHolder,再封装 Adapter。

    二、ViewHolder 的封装

    2.1、RecyclerView 在使用之前需要添加依赖

    dependencies {
        compile 'com.android.support:recyclerview-v7:25.2.0'
    }
    

    2.2、创建一个类继承 RecyclerView.ViewHolder,实现其构造函数

    public class RecyclerViewHolder extends RecyclerView.ViewHolder {
      public RecyclerViewHolder(View itemView) {
            super(itemView);
        }
    }
    

    2.3、其它的封装和之前写过对 Adapter 封装类似,讲了封装的大致步骤,这里不细讲了,直接看 从 0 开始开发一款直播 APP | 3.1 高层封装之 Adapter — ListView & GridView,一个 getView() 获取控件,通过 SparseArray 存储控件。

    private SparseArray<View> mViews;
    
    public RecyclerViewHolder(View itemView) {
        super(itemView);
        this.mViews = new SparseArray<>();
    }
    
    /**
     * 从ItemView获取View
     * @param id  ItemView里包含的ViewId
     * @param <V> 返回View
     * @return
     */
    public <V extends View> V getView(int id) {
        View view = mViews.get(id);
        if (view == null) {
            view = itemView.findViewById(id);
            mViews.put(id, view);
        }
        return (V) view;
    }
    

    2.4、设置控件以及监听(采用链式编程方法)

    /**
     * 设置TextView的值
     * @param viewId
     * @param text
     * @return
     */
    public RecyclerViewHolder setText(int viewId, String text) {
        TextView tv = getView(viewId);
        tv.setText(text);
        return this;
    }
    
    /**
     * 设置ImageView的值
     * @param viewId
     * @param resId
     * @return
     */
    public RecyclerViewHolder setImageResource(int viewId, int resId) {
        ImageView view = getView(viewId);
        view.setImageResource(resId);
        return this;
    }
    
    /**
     * 设置ImageView的值
     * 第三方  ImageLoder Glide Picasso
     * 不能直接写死第三方图片加载
     * 使用自己的一套规范  ImageLoder
     * @param viewId
     * @return
     */
    public RecyclerViewHolder setImagePath(int viewId,ImageLoder imageLoder) {
        ImageView view = getView(viewId);
        imageLoder.loadImage(view,imageLoder.getPath());
        return this;
    }
    
    //图片加载 (对第三方库加载图片等封装)
    public abstract static class ImageLoder{
        private String path;
        public ImageLoder(String path){
            this.path = path;
        }
        //需要复写该方法加载图片
        public abstract void loadImage(ImageView imageView,String path);
        public String getPath() {
            return path;
        }
    }
    
    /**
     * 设置是否可见
     * @param viewId
     * @param visible
     * @return
     */
    public RecyclerViewHolder setVisible(int viewId, boolean visible) {
        View view = getView(viewId);
        view.setVisibility(visible ? View.VISIBLE : View.GONE);
        return this;
    }
    
    /**
     * 设置tag
     * @param viewId
     * @param tag
     * @return
     */
    public RecyclerViewHolder setTag(int viewId, Object tag) {
        View view = getView(viewId);
        view.setTag(tag);
        return this;
    }
    
    public RecyclerViewHolder setTag(int viewId, int key, Object tag) {
        View view = getView(viewId);
        view.setTag(key, tag);
        return this;
    }
    
    /**
     * 设置Checkable
     * @param viewId
     * @param checked
     * @return
     */
    public RecyclerViewHolder setChecked(int viewId, boolean checked) {
        Checkable view = (Checkable) getView(viewId);
        view.setChecked(checked);
        return this;
    }
    
    //点击事件
    public RecyclerViewHolder setOnClickListener(int viewId,View.OnClickListener listener) {
        View view = getView(viewId);
        view.setOnClickListener(listener);
        return this;
    }
    
    //触摸事件
    public RecyclerViewHolder setOnTouchListener(int viewId,View.OnTouchListener listener) {
        View view = getView(viewId);
        view.setOnTouchListener(listener);
        return this;
    }
    
    //长按事件
    public RecyclerViewHolder setOnLongClickListener(int viewId,View.OnLongClickListener listener) {
        View view = getView(viewId);
        view.setOnLongClickListener(listener);
        return this;
    }
    

    三、Adapter 的封装

    首先创建 Adapter 并继承 RecyclerView.Adapter ,将 ViewHolder 作为范型传入,将数据作为范型传入,并实现其方法。方法和 ListView 封装类似,传入布局,数据,上下文,通过 onCreateViewHolder() 实例化 ViewHolder,onBindViewHolder() 绑定 ViewHolder,用于数据,事件绑定,将该方法抽象出去,让用户实现,用户通过该方法拿到 item 对象。

    public abstract class RecyclerViewAdapter<T> extends RecyclerView.Adapter<RecyclerViewHolder> {
      
        protected int mLayoutId;//布局id
        protected List<T> mDatas;//数据源
        protected Context mContext;//上下文
        private LayoutInflater mInflater;
    
        public RecyclerViewAdapter(Context context, int layoutId, List<T> datas) {
            this.mContext = context;
            this.mLayoutId = layoutId;
            this.mDatas = datas;
            this.mInflater = LayoutInflater.from(mContext);
        }
    
        @Override
        public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View itemView = mInflater.inflate(mLayoutId,parent,false);
            return new RecyclerViewHolder(itemView);
        }
    
        @Override
        public void onBindViewHolder(RecyclerViewHolder holder, final int position) {
            bindData(holder,mDatas.get(position),position);
        }
    
        /**
         * 把必要参数传进去,让每个 Adapter 去设置具体值
         * @param holder RecyclerViewHolder 
         * @param t 数据
         * @param position 当前位置
         */
        protected abstract void bindData(RecyclerViewHolder holder, T t,int position);
    
        @Override
        public int getItemCount() {
            return mDatas.size();
        }
    }
    

    四、Demo 演示单布局显示

    4.1、由于用到网络图片,我使用的Glide加载,先添加依赖

    dependencies {
        compile 'com.github.bumptech.glide:glide:3.7.0'
        compile 'com.android.support:recyclerview-v7:25.2.0'
    }
    

    4.2、在 AndroidManifest.xml 中添加网络访问权限

        <uses-permission android:name="android.permission.INTERNET"/>
    

    4.3、创建一个类继承 RecyclerView.ViewHolder,实现其构造函数
    RecyclerAdapterDemo.java

    public class RecyclerAdapterDemo extends RecyclerViewAdapter<Item> {
    
        public RecyclerAdapterDemo(Context context, List<Item> datas) {
            super(context, R.layout.list_item, datas);
        }
    
        @Override
        protected void bindData(RecyclerViewHolder holder, final Item item, int position) {
    
            holder.setText(R.id.tv1,item.getTv1())
    //                .setImageResource(R.id.img,item.getRes())
                    .setOnClickListener(R.id.tv1, new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            Toast.makeText(mContext,item.getTv1(),Toast.LENGTH_SHORT).show();
                        }
                    }).setOnLongClickListener(R.id.tv1, new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    Toast.makeText(mContext,"长按:"+item.getTv1(),Toast.LENGTH_SHORT).show();
                    return true;//true 表示不响应点击事件 false 长按事件结束还会响应点击事件
                }
            });
    
            //加载网络图片
            holder.setImagePath(R.id.img, new RecyclerViewHolder.ImageLoder("http://tomcat.apache.org/images/tomcat.png") {
                @Override
                public void loadImage(ImageView imageView, String path) {
                    Glide.with(mContext).load(path).into(imageView);
                }
            });
        }
    }
    

    4.5、单布局 Adapter 的使用

    public class AdapterActivity extends BaseActivity {
    
        private RecyclerAdapterDemo mAdapterDemo;
        private ArrayList<Item> Datas;
        private RecyclerView mRecyclerView;
    
        @Override
        protected void setToolbar() {
        }
    
        @Override
        protected void setListener() {
        }
    
        //填充数据
        @Override
        protected void initData() {
            Datas = new ArrayList<>();
            for (int i = 1; i <= 30; i++) {
                Datas.add(new Item(R.drawable.tab_publish_normal,"我 get 新技能 " + i));
            }
    
            mAdapterDemo = new RecyclerAdapterDemo(this, Datas);
            mRecyclerView.setAdapter(mAdapterDemo);
        }
    
        @Override
        protected void initView() {
            mRecyclerView = obtainView(R.id.recyclerView);
            //LinearLayoutManager
            //添加分割线
            mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));  
            //添加布局管理器
            mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
          
          //分割线网上有很多示例,这里不贴代码
            //GridLayoutManager
    //        mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this));
    //        mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));
        }
    
        @Override
        protected int getLayoutId() {
            return R.layout.activity_adapter;
        }
    }
    

    4.6、activity_adapter.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.dali.admin.fragment.AdapterActivity">
    
       <android.support.v7.widget.RecyclerView
           android:id="@+id/recyclerView"
           android:layout_width="match_parent"
           android:layout_height="wrap_content">
       </android.support.v7.widget.RecyclerView>
    
    </LinearLayout>
    

    五、运行效果

    **5.1、LinearLayoutManager **

    5.2、GridLayoutManager

    总结

    单条目封装步骤

    1、 ViewHolder 的封装,继承 RecyclerView.ViewHolder,实现其方法和构造函数
    2、封装 ViewHolder 的 getView() 方法,避免 findViewById 及类型转换,提供设置控件和监听的一系列方法
    3、Adapter 的封装,继承 RecyclerView.Adapter 类,将封装的 ViewHolder 作为范型传入,将数据源作为范型传入。如:BaseAdapter<T> extends RecyclerView.Adapter<BaseViewHolder>。实现其构造方法和抽象方法。
    4、设置数据源,上下文对象,布局 ID,抽象绑定 ViewHolder 具体实现,将 ViewHolder 和数据源作为参数传递出去,让用户对数据进行相应处理。

    单条目 Adapter 封装及其使用讲解完,下一章讲解多条目 Adapter 封装
    </br>

    关注菜鸟窝官网,免费领取“140套开源项目”

    </br>


    菜鸟窝官网公号二维码.png

    </br>

    扫码进菜鸟直播学习群,与大咖交流

    </br>


    菜鸟直播二维码.png

    相关文章

      网友评论

        本文标题:【从 0 开始开发一款直播 APP】3.2 高层封装之 Adap

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