复杂RecyclerView的实现

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

之前周末的时候写过一篇复杂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
谢谢!

猜你喜欢

转载自blog.csdn.net/u010724819/article/details/75226377
今日推荐