仿微信朋友圈图片的九宫格效果

前言

在写这个之前呢,我也百度(谷歌需要梯子)了一波,在github上也找了一番,实现的方式很多,还有很多封装好的库可以直接使用。鄙人有个习惯,就是很多东西都喜欢使用轻量级的,所以很多库的功能太全了,不符合鄙人的习惯。微信朋友朋友圈图片的九宫格效果并不难,尤其是RecyclerView如此强大的情况下,所以鄙人决定自己撸一个,不求功能多全面,满足自己的项目需求就好,于是就有了此文。

正文

没图说个鸡儿:


效果图

先照着朋友圈分析一下列表数据(只分析图片,视频跟单图其实是差不多的)的大概样子:

  • 头部下拉刷新(这个效果不在本文的考虑范围内);
  • 列表的图片大概分为单张,两列4张,三列N张;
  • 最多可以显示9张;
  • 单张图片自适应高度,宽度最大为列表宽度;
  • 多张图片为正方形图片,田字格或者九宫格。

所以我们可以把列表看做是三种viewType的集合,于是乎,我们的getViewType重写如下:


            int size ; // size的值是列表图片数量
            if (size < 2) {
              //没有图片或者单张图片
                return 1;
            } else if (size == 4) {
                //四张图片
                return 2;
            } else {
                //其他情况
                return 3;
            }

在onCreateViewHolder方法中,我们需要去创建我们的holder。其实四张图片的田字格可以当做是九宫格的一种特殊形式,当然一张图片也可以当做是九宫格的一种特殊形式,但鄙人将一张图片的情况跟九宫格的分开,那么我们就需要两个不同的holder去分别承载一张图和多张图的情况。多张图的情况,里面图片的列表我还是使用RecylcerView(RV简直不要太好用)。
对于总体的item来说,除了图片展示部分,其他的部分都是一样的,我们可以创建一个父类的holder,父类的holder提供了一个抽象的方法loadSelf ()提供给子类的holder去处理自己的逻辑。

abstract class ItemHolder extends RecyclerView.ViewHolder  {
       

        public ItemHolder(View itemView) {
            super(itemView);
           
        }

        private void setData(final int position, final CircleListModel model) {
            
            //todo 公共的逻辑
          

            loadSelf(position, model);
        }

        public abstract void loadSelf(final int position, final CircleListModel model);
    }

根据上面的分析,我们还需要创建两个子类的holder。

  • 提供给单张图片使用的:
private class OneHolder extends ItemHolder  {
        AppCompatImageView ivCover;
     
        public OneHolder(View itemView) {
            super(itemView);
            ivCover = itemView.findViewById(R.id.iv_cover);
        }

        @Override
        public void loadSelf(int position, CircleListModel model) {
            List<> mediaList ; //图片的数组
            // 如果没有图片,那就是只有文字,隐藏图片控件
            if (mediaList == null || mediaList.isEmpty()) {
                ivCover.setVisibility(View.GONE);
            } else {
                ivCover.setVisibility(View.VISIBLE);
               //todo 显示图片
                
            }
        }


  • 提供给多张使用的:
private class OtherHolder extends ItemHolder {
        RecyclerView rvItems;
        RAdapter<CircleListModel.CircleMsgMediaList> mAdapter;
        private ArrayList<CircleListModel.CircleMsgMediaList> mStrings = new ArrayList<>();

        public OtherHolder(final View itemView, int columns) {
            super(itemView);
            rvItems = itemView.findViewById(R.id.rv_items);

            mAdapter = new RAdapter<CircleListModel.CircleMsgMediaList>(mContext, R.layout.other_item, mStrings) {
                @Override
                protected void init(RViewHolder holder, final CircleListModel.CircleMsgMediaList circleMsgMediaList) {
                    LinearLayoutCompat.LayoutParams layoutParams = new LinearLayoutCompat.LayoutParams(widthPixels, widthPixels);
                    final AppCompatImageView image = holder.getView(R.id.image);
                    image.setLayoutParams(layoutParams);
                    //todo 加载图片

                    });

                }
            };
            GridLayoutManager manager = new GridLayoutManager(mContext, columns);
            rvItems.setLayoutManager(manager);
            rvItems.setAdapter(mAdapter);
            rvItems.addItemDecoration(new GridSpacingItemDecoration(columns, SPACE, false));
            rvItems.setHasFixedSize(true);
            ((SimpleItemAnimator) rvItems.getItemAnimator()).setSupportsChangeAnimations(false);

        }

        public void loadSelf(final int position, final CircleListModel model) {
            mStrings.clear();
            mStrings.addAll(model.getCircleMsgMediaList());
            mAdapter.notifyDataSetChanged();
        }
    }

上面的代码涉及到我自己封装Adapter和添加分割线的方法。老铁可以自己灵活的去换一下。

 ((SimpleItemAnimator) rvItems.getItemAnimator()).setSupportsChangeAnimations(false);

这一句不要忘了,不然会出现item闪烁的现象。

holder创建好了,下面就是onBindViewHolder()方法里面的代码了。由于上面封装的holder里面提供了setData()的方法,所以onBindViewHolder()方法里面的内容就简单多了:

@Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int p) {
        final int position = holder.getAdapterPosition();
        
            final CircleListModel model = mList.get(position);

            ((ItemHolder) holder).setData(position, model);
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //todo item点击事件
                }
            });
        }

    }

核心其实就调用holder的setData()方法和添加itemView的点击事件。

前面有讲到九宫格的情况下,图片展示的是方图,田字格是九宫格的一种特殊情况,上面OtherHolder 的构造方法里面需要传入图片格子的column,所以图片RecyclerView的宽度是wrap_content,那么我们需要手动的去实际计算一下图片的宽度。这个老铁们根据实际情况去计算就可以了。
另外还有一些交互的功能需要暴露出去,老铁们根据实际情况添加自己的接口就好了,比如我的:

public interface OnItemListener {
        void onItemClick(int position, CircleListModel t);

        void showComments(int position, CircleListModel t);

        void delete(int position, CircleListModel t);

        void onLinkClick(String url);
    }

到此效果就实现完了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容