复杂RecyclerView的实现

来源:互联网 发布:淘宝入驻村淘的的条件 编辑:程序博客网 时间:2024/06/06 00:29

之前周末的时候写过一篇复杂ListView相关的文章,但是写的不够详尽(具体到每个方法),只是个人觉得没有必要写的那么详细,因为大部分的内容对于一个拥有安卓开发开发经验的人来说跑完Demo之后都会很好理解的。

但是现如今使用ListView的部分朋友已经转到RecyclerView这一黑科技控件下了,所以我便将之前的思路试着看移植到RecyclerView之中,中间遇到了两个坑,下面来喝大家分享一下!

首先,按照规律,我们来看下效果图:



下面我们来一步步实现:

首先想到的是RecyclerView的一些设置,这些其实也没啥好说的:

看代码:

   myRecyclerViewAdapter = new MyRecyclerViewAdapter(this, users);        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);        recyclerView.setLayoutManager(linearLayoutManager);        recyclerView.setAdapter(myRecyclerViewAdapter);
主要是一些设置的东西。


下面我们来看重点:

MyRecyclerViewAdapter的实现
我们一步步进行分解

1.首先看顶部的ViewPager布局:



下面来看布局代码:

<?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="match_parent">    <android.support.v4.view.ViewPager        android:id="@+id/item1_vp"        android:layout_width="match_parent"        android:layout_height="200dp"        android:text="item00"/></LinearLayout>

其实也很简单直接声明下,之后我们来看ViewPager的Adapter设定,我这里就简单地设定了Adapter:

public class ViewPagerAdapter extends PagerAdapter {    private Context context;    public ViewPagerAdapter(Context context) {        this.context = context;    }    @Override    public Object instantiateItem(ViewGroup container, int position) {        TextView textView = new TextView(context);        textView.setText(position + "");        container.addView(textView);        return textView;    }    @Override    public void destroyItem(ViewGroup container, int position, Object object) {        container.removeView((View) object);    }    @Override    public boolean isViewFromObject(View view, Object object) {        return view == object;    }    @Override    public int getCount() {        return 4;    }}
也是最最基础的东西了,没啥好说的,看不懂的童鞋面壁思过去。。。

2.两个线性布局,他俩存在的意义就是为了体现咱们的思路适应多种布局:


3.横向ScrollView,其实这里也可以用横向RecyclerView,只是这里为了避免嵌套引发的问题,使用了横向ScrollVIew:

布局如下:

<?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="match_parent">    <HorizontalScrollView        android:id="@+id/horizontalscrollview"        android:layout_width="match_parent"        android:layout_height="match_parent"        >        <LinearLayout            android:id="@+id/ll_main"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:orientation="horizontal">        </LinearLayout>    </HorizontalScrollView></LinearLayout>

实现动态添加的代码如下:

 LinearLayout rl_layout = null;            TextView tv_title = null;            TextView tv_sub_title = null;            ImageView iv_test = null;            for (int i = 0; i < 10; i++) {                View view = LayoutInflater.from(ctx).inflate(R.layout.scroll_item_layout, null);                int screenWidth = CommonUtil.getScreenWidth(ctx);                int screenHeight = CommonUtil.getScreenHeight(ctx);                //根据屏幕宽度设定横向滑动子View的宽度                view.setLayoutParams(new LinearLayout.LayoutParams(screenWidth / 2, 120));                rl_layout = (LinearLayout) view.findViewById(R.id.rl_layout);                tv_title = (TextView) view.findViewById(R.id.tv_title);                tv_sub_title = (TextView) view.findViewById(R.id.tv_sub_title);                tv_sub_title = (TextView) view.findViewById(R.id.tv_sub_title);                iv_test = (ImageView) view.findViewById(R.id.iv_test);                tv_title.setText("主标题" + i);                tv_sub_title.setText("子标题" + i);                iv_test.setImageResource(R.mipmap.ic_launcher);                final int finalI = i;                rl_layout.setOnClickListener(new View.OnClickListener() {                    @Override                    public void onClick(View view) {                        Toast.makeText(ctx, "view" + finalI, Toast.LENGTH_SHORT).show();                    }                });                itemHolder4.ll_main.addView(view);            }
这里犹豫ScrollView只能有一个直接的子布局,所以我们在这里向LinearLayout中添加布局,然后再添加到HorizontalScrollView之中。

其次,为了保证布局中,横向滚动的ScrollView保证一屏之中只有两个,所以这里我们获取屏幕的宽度,然后设定每个子View的宽度为半个屏幕,哈哈!

下面就来到了最精彩的时候了:

我们应该怎样整合这些复杂的布局呢?

RecyclerView.Adapter<RecyclerView.ViewHolder>中给我们提供了几个非常好用的方法:
 @Override    public int getItemViewType(int position) {}

   //为每种布局定义自己的ViewHolder    public class ViewHolder1 extends RecyclerView.ViewHolder {        private ViewPager item1_vp;        public ViewHolder1(View itemView) {            super(itemView);            item1_vp = (ViewPager) itemView.findViewById(R.id.item1_vp);        }        public void setData() {            item1_vp.setAdapter(new ViewPagerAdapter(ctx));        }    }
下面我们来一步步解释下:
创建ViewHolder的时候会调用该方法:
    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        RecyclerView.ViewHolder holder = null;        switch (viewType) {            case TYPE1:                holder = new ViewHolder1(View.inflate(ctx, R.layout.itemlayout1, null));                break;            case TYPE2:                holder = new ViewHolder2(View.inflate(ctx, R.layout.itemlayout2, null));                break;            case TYPE3:                holder = new ViewHolder3(View.inflate(ctx, R.layout.itemlayout3, null));                break;            case TYPE4:                holder = new ViewHolder4(View.inflate(ctx, R.layout.horizontal_crollview_main, null));                break;            default:                break;        }        return holder;    }
总共有四种类型,分别标记下:
  //为三种布局定义一个标识    private final int TYPE1 = 0;    private final int TYPE2 = 1;    private final int TYPE3 = 2;    private final int TYPE4 = 3;

绑定ViewHolder的时候,调用如下方法:
    @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        //由于木有相关的viewType参数,只能通过方法来获取了        int viewType = getItemViewType(position);        switch (viewType) {            case TYPE1:                ((ViewHolder1) holder).setData();                break;            case TYPE2:                ((ViewHolder2) holder).setData(position);                break;            case TYPE3:                ((ViewHolder3) holder).setData(position);                break;            case TYPE4:                ((ViewHolder4) holder).setData((ViewHolder4) holder);                break;        }    }

在这里我把设定的方法全部放到ViewHolder里面了。
这里我们需要根据返回类型的不同进行相关设定:
    @Override    public int getItemViewType(int position) {        //获取当前布局的数据        User u = users.get(position);        //哪个字段不为空就说明这是哪个布局        //比如第一个布局只有item1_str这个字段,那么就判断这个字段是不是为空,        //如果不为空就表明这是第一个布局的数据        //根据字段是不是为空,判断当前应该加载的布局        Log.i("LHD", u.toString());        Log.i("LHD", "第一个返回值" + u.getItem1_str());        Log.i("LHD", "第二个返回值" + u.getItem2_str());        Log.i("LHD", "第三个返回值" + u.getItem3_str());        if (u.getItem1_str() != null) {            return TYPE1;        } else if (u.getItem2_str() != null) {            return TYPE2;        } else if (u.getItem3_str() != null) {//如果前两个字段都为空,那就一定是加载第三个布局啦。            return TYPE3;        } else {            return TYPE4;        }    }

这样就可以得出了各种条目类型以及对应关系。
但是看到这里是不是有点儿乱呢,乱就对了,说明你已经在认真思考了,哈哈!
我来总结下,处理复杂RecyclerView的方法:
1.重写
 @Override    public int getItemViewType(int position) {}
非常重要,这里是进行子条目布局区分的重要方法,
2.重写
 @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {}
方法可以根据type的不同返回不同的条目布局ViewHolder
3.重写:
 @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
可以进行相关的绑定,也就是说白了进行初始化。
下面来贴上Adpater的完整源码:
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {    //定义常用的参数    private Context ctx;    private int resourceId;    //JavaBean    private List<User> users;    private LayoutInflater inflater;    //为三种布局定义一个标识    private final int TYPE1 = 0;    private final int TYPE2 = 1;    private final int TYPE3 = 2;    private final int TYPE4 = 3;    public MyRecyclerViewAdapter(Context ctx, List<User> objects) {        this.ctx = ctx;        this.users = objects;        //别忘了初始化inflater        inflater = LayoutInflater.from(ctx);    }    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        RecyclerView.ViewHolder holder = null;        switch (viewType) {            case TYPE1:                holder = new ViewHolder1(View.inflate(ctx, R.layout.itemlayout1, null));                break;            case TYPE2:                holder = new ViewHolder2(View.inflate(ctx, R.layout.itemlayout2, null));                break;            case TYPE3:                holder = new ViewHolder3(View.inflate(ctx, R.layout.itemlayout3, null));                break;            case TYPE4:                holder = new ViewHolder4(View.inflate(ctx, R.layout.horizontal_crollview_main, null));                break;            default:                break;        }        return holder;    }    @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        //由于木有相关的viewType参数,只能通过方法来获取了        int viewType = getItemViewType(position);        switch (viewType) {            case TYPE1:                ((ViewHolder1) holder).setData();                break;            case TYPE2:                ((ViewHolder2) holder).setData(position);                break;            case TYPE3:                ((ViewHolder3) holder).setData(position);                break;            case TYPE4:                ((ViewHolder4) holder).setData((ViewHolder4) holder);                break;        }    }    @Override    public int getItemViewType(int position) {        //获取当前布局的数据        User u = users.get(position);        //哪个字段不为空就说明这是哪个布局        //比如第一个布局只有item1_str这个字段,那么就判断这个字段是不是为空,        //如果不为空就表明这是第一个布局的数据        //根据字段是不是为空,判断当前应该加载的布局        Log.i("LHD", u.toString());        Log.i("LHD", "第一个返回值" + u.getItem1_str());        Log.i("LHD", "第二个返回值" + u.getItem2_str());        Log.i("LHD", "第三个返回值" + u.getItem3_str());        if (u.getItem1_str() != null) {            return TYPE1;        } else if (u.getItem2_str() != null) {            return TYPE2;        } else if (u.getItem3_str() != null) {//如果前两个字段都为空,那就一定是加载第三个布局啦。            return TYPE3;        } else {            return TYPE4;        }    }    @Override    public int getItemCount() {        return users.size();    }    //为每种布局定义自己的ViewHolder    public class ViewHolder1 extends RecyclerView.ViewHolder {        private ViewPager item1_vp;        public ViewHolder1(View itemView) {            super(itemView);            item1_vp = (ViewPager) itemView.findViewById(R.id.item1_vp);        }        public void setData() {            item1_vp.setAdapter(new ViewPagerAdapter(ctx));        }    }    public class ViewHolder2 extends RecyclerView.ViewHolder {        private TextView item2_tv;        public ViewHolder2(View itemView) {            super(itemView);            item2_tv = (TextView) itemView.findViewById(R.id.item2_tv);        }        public void setData(int position) {            item2_tv.setText(users.get(position).getItem2_str());        }    }    public class ViewHolder3 extends RecyclerView.ViewHolder {        private Button item3_btn;        public ViewHolder3(View itemView) {            super(itemView);            item3_btn = (Button) itemView.findViewById(R.id.item3_btn);        }        public void setData(int position) {            item3_btn.setText(users.get(position).getItem3_str());        }    }    public class ViewHolder4 extends RecyclerView.ViewHolder {        private LinearLayout ll_main;        public ViewHolder4(View itemView) {            super(itemView);            ll_main = (LinearLayout) itemView.findViewById(R.id.ll_main);        }        public void setData(ViewHolder4 itemHolder4) {            LinearLayout rl_layout = null;            TextView tv_title = null;            TextView tv_sub_title = null;            ImageView iv_test = null;            for (int i = 0; i < 10; i++) {                View view = LayoutInflater.from(ctx).inflate(R.layout.scroll_item_layout, null);                int screenWidth = CommonUtil.getScreenWidth(ctx);                int screenHeight = CommonUtil.getScreenHeight(ctx);                //根据屏幕宽度设定横向滑动子View的宽度                view.setLayoutParams(new LinearLayout.LayoutParams(screenWidth / 2, 120));                rl_layout = (LinearLayout) view.findViewById(R.id.rl_layout);                tv_title = (TextView) view.findViewById(R.id.tv_title);                tv_sub_title = (TextView) view.findViewById(R.id.tv_sub_title);                tv_sub_title = (TextView) view.findViewById(R.id.tv_sub_title);                iv_test = (ImageView) view.findViewById(R.id.iv_test);                tv_title.setText("主标题" + i);                tv_sub_title.setText("子标题" + i);                iv_test.setImageResource(R.mipmap.ic_launcher);                final int finalI = i;                rl_layout.setOnClickListener(new View.OnClickListener() {                    @Override                    public void onClick(View view) {                        Toast.makeText(ctx, "view" + finalI, Toast.LENGTH_SHORT).show();                    }                });                itemHolder4.ll_main.addView(view);            }        }    }}


我在编写代码中遇到的两个坑:
子布局已经设置match_parent了,但是条目布局还是包裹内容的形式展示出来了,这里做了个处理就好了,
    <View        android:layout_width="match_parent"        android:layout_height="1dp"        android:background="@color/colorBlack"        />
在布局的最下面加了一个View布局,撑开了整个布局条目,使之匹配父布局,目前原因未知,先这样处理了。
2.刷新控件适应的是XRefreshView,非常感谢作者啊,但是在上拉加载的时候始终会遮盖最新的条目,使之没法展示出来,这里我做了个小小的处理:
   recyclerView.scrollBy(0,30);
上滑一段距离,这样就可以展示出来了,提示用户下面还有内容可以下拉查看。嗯嗯,还行吧!

下面照旧是放出源码的时候了:
ComplexRecyclerView
谢谢!

阅读全文
0 0
原创粉丝点击