zoukankan      html  css  js  c++  java
  • RecyclerView多item布局实现

     

    第一家公司做外包,做过不少电商项目,首页设计基本都是这个样 
    从上至下分别一个轮播图框,一个横向滑动的view用来展示一些特殊的列表,几个快捷菜单,和一个显示商品的列表。

    实际应用里截图:

    这里就用一个基本的例子来实现如何RecyclerView怎么进行多item布局。

    先看效果图:

    首先,轮播图的bean,横向List的bean,和正常list的bean肯定不同,而adapter只有一个与一个数组绑定,所以三种bean要可以是统一类型的bean,所以我定义了一个三种bean的父类bean就叫它ExampleBaseBean

    public class ExampleBaseBean {
    
        private int viewType;
    
        public int getViewType() {
            return viewType;
        }
    
        public void setViewType(int viewType) {
            this.viewType = viewType;
        }
    }

    如代码所示,这个BaseBean主要作用就是提供一个int类型的vieType的对象用来区分不同类型的bean。

    有了BaseBean,接下来就是三种bean了。

    public class TitleBean extends ExampleBaseBean {
        //轮播bean,为了方便叫titleBean
    private List<String> titles;//轮播的数据源一般都为数组。
    public List<String> getTitles() {
            return titles;
        }
    
        public void setTitles(List<String> titles) {
            this.titles = titles;
        }
    }

    public class BodyBean extends ExampleBaseBean {
        //中间横向滑动的bean  ,通常都有图片展示,这里用本地图片展示
    private List<Integer> res;
    
        public List<Integer> getRes() {
            return res;
        }
    
        public void setRes(List<Integer> res) {
            this.res = res;
        }
    }
    public class FootBean extends ExampleBaseBean {
        //正常列表的bean
    private String str;
    
        public FootBean(String str) {
            this.str = str;
        }
    
        public String getStr() {
            return str;
        }
    
    }

    三种bean定义完,该着手adapter了。

    public class ExampleAdapter extends RecyclerView.Adapter {
    
        public final static int TITLE = 1001;//标题的viewType
    public final static int BODY = 1002;//横向列表的viewType
    public final static int FOOT = 1003;//正常列表的viewType
    private List<ExampleBaseBean> mlist;//adapter的数据源
    private Context context;
        private LayoutInflater inflater;
    
    
        public ExampleAdapter(List<ExampleBaseBean> mlist) {
            this.mlist = mlist;
        }

    首先在这个adapter里将会用到viewtype写成静态常量,方便外面统一。

    先写三种bean对应的ViewHolder:

    private class TitleHolder extends RecyclerView.ViewHolder {
    
        ViewPager vp;
    
        public TitleHolder(View itemView) {
            super(itemView);
            vp = itemView.findViewById(R.id.vp);
        }
    }
    
    private class BodyHolder extends RecyclerView.ViewHolder {
    
        RecyclerView rv;
    
        public BodyHolder(View itemView) {
            super(itemView);
            rv = itemView.findViewById(R.id.rv);
        }
    }
    
    private class FootHolder extends RecyclerView.ViewHolder {
    
        TextView tv_foot;
    
        public FootHolder(View itemView) {
            super(itemView);
            tv_foot = itemView.findViewById(R.id.tv_foot);
        }
    }

    三种ViewHolder写完了,然后就是复写RecyclerView.Adapter的getItemViewType方法来控制它返回给onCreateViewHolder的viewType:

    @Override
    public int getItemViewType(int position) {
        if (mlist.size() > 0) {
            return mlist.get(position).getViewType();
        }
        return super.getItemViewType(position);
    }

    然后就是adapter的主要方法onCreateViewHolder方法:

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (context == null)
            context = parent.getContext();
        if (inflater == null)
            inflater = LayoutInflater.from(context);
        View view;
        switch (viewType) {
            case TITLE:
                view = inflater.inflate(R.layout.listitem_title, parent, false);
                return new TitleHolder(view);
            case BODY:
                view = inflater.inflate(R.layout.listitem_body, parent, false);
                return new BodyHolder(view);
            case FOOT:
                view = inflater.inflate(R.layout.listitem_foot, parent, false);
                return new FootHolder(view);
        }
        return null;
    }

    根据onCreateViewHolder方法传来的viewType进行判断然后返回对应item布局的ViewHolder。

    ViewHolder会被传到onBindViewHolder方法,接下来就只再要实现onBindViewHolder里就OK了。

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof TitleHolder) {
            TitleBean titleBean = (TitleBean) mlist.get(position);
            ((TitleHolder) holder).vp.setAdapter(new PagerAdapter(titleBean.getTitles()));
        }
    
        if (holder instanceof BodyHolder) {
            BodyBean bodyBean = (BodyBean) mlist.get(position);
            ((BodyHolder) holder).rv.setLayoutManager(new LinearLayoutManager(context, LinearLayout.HORIZONTAL, false));
            ((BodyHolder) holder).rv.setAdapter(new BodyAdapter(bodyBean.getRes()));
        }
    
        if (holder instanceof FootHolder) {
            FootBean footBean = (FootBean) mlist.get(position);
            ((FootHolder) holder).tv_foot.setText(footBean.getStr());
        }
    }

    这里的viewPager的adapter我图省事直接写成内部类了

    private class PagerAdapter extends android.support.v4.view.PagerAdapter {
    
        List<String> stringList;
    
        public PagerAdapter(List<String> stringList) {
            this.stringList = stringList;
        }
    
        @NonNull
        @Override
        public Object instantiateItem(@NonNull ViewGroup container, int position) {
            ViewPager.LayoutParams params = new ViewPager.LayoutParams();
            params.width = ViewPager.LayoutParams.WRAP_CONTENT;
            params.height = ViewPager.LayoutParams.WRAP_CONTENT;
            params.gravity = Gravity.CENTER;
            TextView textView = new TextView(container.getContext());
            textView.setText(stringList.get(position));
            textView.setTextSize(30);
            textView.setTextColor(Color.parseColor("#333333"));
            textView.setLayoutParams(params);
            container.addView(textView);
            return textView;
        }
    
        @Override
        public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
            container.removeView((View) object);
        }
    
        @Override
        public int getCount() {
            return stringList.size();
        }
    
        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
            return view == object;
        }
    }

    还有一个Body的adapter就是平时展示一种数据的adapter,这里也贴一下。

    public class BodyAdapter extends RecyclerView.Adapter {
    
        private List<Integer> res;
    
        public BodyAdapter(List<Integer> res) {
            this.res = res;
        }
    
        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem_body_img, parent, false);
            return new ImgHolder(view);
        }
    
        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            if (holder instanceof ImgHolder) {
                ((ImgHolder) holder).iv.setImageResource(res.get(position));
            }
        }
    
        private class ImgHolder extends RecyclerView.ViewHolder {
    
            ImageView iv;
    
            public ImgHolder(View itemView) {
                super(itemView);
                iv = itemView.findViewById(R.id.iv);
            }
        }
    
        @Override
        public int getItemCount() {
            return res.size();
        }
    }

    还有就是Acitivy里模拟数据的添加代码:

    public class ExampleActivity extends AppCompatActivity {
    
        private ExampleAdapter adapter;
        private List<ExampleBaseBean> mlist = new ArrayList<>();
        private RecyclerView rv;
        private Context context;
        
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_example);
            context = this;
            rv = findViewById(R.id.rv);
            initTitle();
            initBody();
            initFoot();
            initAdapter();
        }
    
        private void initFoot() {
            for (int i = 0; i < 10; i++) {
                FootBean footBean=new FootBean("foot:"+i);
                footBean.setViewType(ExampleAdapter.FOOT);//正常列表
    mlist.add(footBean);
            }
        }
    
        private void initBody() {
            List<Integer> res = new ArrayList<>(6);
            res.add(R.mipmap.pic1);
            res.add(R.mipmap.pic2);
            res.add(R.mipmap.pic3);
            res.add(R.mipmap.pic4);
            res.add(R.mipmap.pic5);
            res.add(R.mipmap.pic6);
            BodyBean bodyBean = new BodyBean();
            bodyBean.setRes(res);
            bodyBean.setViewType(ExampleAdapter.BODY);//设置横向列表的类型
    mlist.add(bodyBean);
        }
    
        private void initTitle() {
            List<String> titles = new ArrayList<>(5);
            for (int i = 0; i < 5; i++) {
                titles.add(new StringBuilder("标题").append(i).toString());
            }
            TitleBean titleBean = new TitleBean();
            titleBean.setTitles(titles);
            titleBean.setViewType(ExampleAdapter.TITLE);//设置为轮播类型
    mlist.add(titleBean);
        }
    
        private void initAdapter() {
            if (adapter == null) {
                adapter = new ExampleAdapter(mlist);
                rv.setLayoutManager(new LinearLayoutManager(context));
                rv.setAdapter(adapter);
            } else {
                adapter.notifyDataSetChanged();
            }
        }
    
    }

    Item的xml布局也极其简单都是只有一个控件,就不贴了。

  • 相关阅读:
    指针传递的一些必要的记录,避免以后又忘记了。
    记录下这几个FMX控件的地址
    boost.ASIO-可能是下一代C++标准的网络库
    对本程序使用自己的代理服务器
    C# 为网络程序添加用户代理
    InternetOpen怎么使用代理
    改变代理服务器
    在Delphi中,关于数组名称
    Delphi 获取进程路径及命令行参数
    关于在asp.net的web页面中的全局变量问题
  • 原文地址:https://www.cnblogs.com/xgjblog/p/14081349.html
Copyright © 2011-2022 走看看