仿微信朋友圈圖片的九宮格效果

前言

在寫(xiě)這個(gè)之前呢,我也百度(谷歌需要梯子)了一波,在github上也找了一番,實(shí)現(xiàn)的方式很多,還有很多封裝好的庫(kù)可以直接使用。鄙人有個(gè)習(xí)慣,就是很多東西都喜歡使用輕量級(jí)的,所以很多庫(kù)的功能太全了,不符合鄙人的習(xí)慣。微信朋友朋友圈圖片的九宮格效果并不難,尤其是RecyclerView如此強(qiáng)大的情況下,所以鄙人決定自己擼一個(gè),不求功能多全面,滿(mǎn)足自己的項(xiàng)目需求就好,于是就有了此文。

正文

沒(méi)圖說(shuō)個(gè)雞兒:


效果圖

先照著朋友圈分析一下列表數(shù)據(jù)(只分析圖片,視頻跟單圖其實(shí)是差不多的)的大概樣子:

  • 頭部下拉刷新(這個(gè)效果不在本文的考慮范圍內(nèi));
  • 列表的圖片大概分為單張,兩列4張,三列N張;
  • 最多可以顯示9張;
  • 單張圖片自適應(yīng)高度,寬度最大為列表寬度;
  • 多張圖片為正方形圖片,田字格或者九宮格。

所以我們可以把列表看做是三種viewType的集合,于是乎,我們的getViewType重寫(xiě)如下:


            int size ; // size的值是列表圖片數(shù)量
            if (size < 2) {
              //沒(méi)有圖片或者單張圖片
                return 1;
            } else if (size == 4) {
                //四張圖片
                return 2;
            } else {
                //其他情況
                return 3;
            }

在onCreateViewHolder方法中,我們需要去創(chuàng)建我們的holder。其實(shí)四張圖片的田字格可以當(dāng)做是九宮格的一種特殊形式,當(dāng)然一張圖片也可以當(dāng)做是九宮格的一種特殊形式,但鄙人將一張圖片的情況跟九宮格的分開(kāi),那么我們就需要兩個(gè)不同的holder去分別承載一張圖和多張圖的情況。多張圖的情況,里面圖片的列表我還是使用RecylcerView(RV簡(jiǎn)直不要太好用)。
對(duì)于總體的item來(lái)說(shuō),除了圖片展示部分,其他的部分都是一樣的,我們可以創(chuàng)建一個(gè)父類(lèi)的holder,父類(lèi)的holder提供了一個(gè)抽象的方法loadSelf ()提供給子類(lèi)的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);
    }

根據(jù)上面的分析,我們還需要?jiǎng)?chuàng)建兩個(gè)子類(lèi)的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 ; //圖片的數(shù)組
            // 如果沒(méi)有圖片,那就是只有文字,隱藏圖片控件
            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);

這一句不要忘了,不然會(huì)出現(xiàn)item閃爍的現(xiàn)象。

holder創(chuàng)建好了,下面就是onBindViewHolder()方法里面的代碼了。由于上面封裝的holder里面提供了setData()的方法,所以onBindViewHolder()方法里面的內(nèi)容就簡(jiǎn)單多了:

@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點(diǎn)擊事件
                }
            });
        }

    }

核心其實(shí)就調(diào)用holder的setData()方法和添加itemView的點(diǎn)擊事件。

前面有講到九宮格的情況下,圖片展示的是方圖,田字格是九宮格的一種特殊情況,上面OtherHolder 的構(gòu)造方法里面需要傳入圖片格子的column,所以圖片RecyclerView的寬度是wrap_content,那么我們需要手動(dòng)的去實(shí)際計(jì)算一下圖片的寬度。這個(gè)老鐵們根據(jù)實(shí)際情況去計(jì)算就可以了。
另外還有一些交互的功能需要暴露出去,老鐵們根據(jù)實(shí)際情況添加自己的接口就好了,比如我的:

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);
    }

到此效果就實(shí)現(xiàn)完了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容