Android自定義ViewGroup實現朋友圈九宮格控件

一、簡介

最近項目裡有個類似微信朋友圈的九圖控件的需求,Github找瞭一下,發現都不太滿足需求,我需要單張圖片的時候可以按照圖片寬高比列在一定范圍內自適應,而大多開源項目單張圖片也是一個小正方形,所以,幹脆自己動手寫一個

1.1、效果圖如下

1.2、主要功能如下

1:單張圖片的時候支持按照圖片寬高比列在設定區域內自適應

2:Adapter方式綁定數據和UI

3:圖片點擊事件回調

4:設置圖片間隔大小

5:自由通過Glide設置ImageView圓角效果

二、使用

2.1、自定義屬性如下

<resources>
    <declare-styleable name="NineImageLayout">
        <!-- 控件寬高 -->
        <attr name="nine_layoutWidth" format="dimension"/>
        <!-- 單張圖片時的最大寬高范圍-->
        <attr name="nine_singleImageWidth" format="dimension" />
        <!-- 圖片之間間隙大小 -->
        <attr name="nine_imageGap" format="dimension" />
    </declare-styleable>
</resources>

2.2、佈局中使用自定義NineImageLayout

 <com.cyq.customview.nineLayout.view.NineImageLayout
        android:id="@+id/nine_image_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tv_title"
        android:layout_marginTop="20dp"
        app:nine_imageGap="4dp"
        app:nine_layoutWidth="300dp"
        app:nine_singleImageWidth="180dp" />

2.3、Adapter方式綁定數據和UI

其中Glide.asBitmap是為瞭計算圖片寬高,如果後臺有返回圖片的寬高可以省略這一步,直接setSingleImage(width, height,imageView),

Ps:如果可以建議後臺返回圖片寬高,這樣可以避免單張圖片的時候控件高度跳屏,比如我限制單張圖片寬高在200dp范圍,要展示寬1000px高500px的時候,在圖片未加載完成時控件寬高為200dp,圖片加載完成後高度變為100dp,會有一個不好的用戶體驗,所以建議上傳圖片的時候記錄圖片寬高信息

nineImageLayout.setAdapter(new NineImageAdapter() {
            @Override
            protected int getItemCount() {
                return mData.size();
            }

            @Override
            protected View createView(LayoutInflater inflater, ViewGroup parent, int i) {
                return inflater.inflate(R.layout.item_img_layout, parent, false);
            }

            @Override
            protected void bindView(View view, final int i) {
                final ImageView imageView = view.findViewById(R.id.iv_img);
                Glide.with(mContext).load(mData.get(i)).into(imageView);
                if (mData.size() == 1) {
                    Glide.with(mContext)
                            .asBitmap()
                            .load(mData.get(0))
                            .into(new SimpleTarget<Bitmap>() {
                                @Override
                                public void onResourceReady(Bitmap bitmap, Transition<? super Bitmap> transition) {
                                    final int width = bitmap.getWidth();
                                    final int height = bitmap.getHeight();
                                    nineImageLayout.setSingleImage(width, height,imageView);
                                }
                            });
                    Glide.with(mContext).load(mData.get(0)).into(imageView);
                } else {
                    Glide.with(mContext).load(mData.get(i)).into(imageView);
                }
            }

            @Override
            public void OnItemClick(int i, View view) {
                super.OnItemClick(position, view);
                Toast.makeText(mContext, "position:" + mData.get(i), Toast.LENGTH_SHORT).show();
            }
        });

2.4、列表裡面使用

頁面放一個RecyclerView

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".nineLayout.NineImageLayoutActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</FrameLayout>

item佈局如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="20dp">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="標題"
        android:textColor="@android:color/black"
        android:textSize="18sp" />

    <com.cyq.customview.nineLayout.view.NineImageLayout
        android:id="@+id/nine_image_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tv_title"
        android:layout_marginTop="20dp"
        app:nine_imageGap="4dp"
        app:nine_layoutWidth="300dp"
        app:nine_singleImageWidth="180dp" />
</RelativeLayout>

Activity中構造一下測試數據,大致代碼如下

public class NineImageLayoutActivity extends AppCompatActivity {
    private RecyclerView mRecyclerView;
    private MyAdapter mAdapter;
    private Random random;
    private final String URL_IMG = "http://q3x62hkt1.bkt.clouddn.com/banner/58f57dfa5bb73.jpg";
    private final String URL_IMG_2 = "http://q3x62hkt1.bkt.clouddn.com/timg.jpeg";
    private List<List<String>> mList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_nine_image_layout);
        random = new Random();
        List<String> testList = new ArrayList<>();
        testList.add(URL_IMG_2);
        for (int i = 0; i < 100; i++) {
            int count = i % 9 + 1;
            List<String> list = new ArrayList<>();
            for (int j = 0; j < count; j++) {
                list.add(URL_IMG);
            }
            if (i % 8 == 0) {
                mList.add(testList);
            }
            mList.add(list);
        }
        mRecyclerView = findViewById(R.id.recyclerview);
        mAdapter = new MyAdapter(mList, this);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerView.setAdapter(mAdapter);
    }
}

MyAdapter中設置數據

import java.util.List;

/**
 * @author : ChenYangQi
 * date   : 2020/1/16 13:49
 * desc   :
 */
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    private List<List<String>> mList;
    private Context mContext;

    public MyAdapter(List<List<String>> mList, Context mContext) {
        this.mList = mList;
        this.mContext = mContext;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.item_nine_img_layout_list, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
        final List<String> mData = mList.get(position);
        holder.tvTitle.setText("這是" + mData.size() + "張圖片的標題");
        final NineImageLayout nineImageLayout = holder.nineImageLayout;
        holder.nineImageLayout.setAdapter(new NineImageAdapter() {
            @Override
            protected int getItemCount() {
                return mData.size();
            }

            @Override
            protected View createView(LayoutInflater inflater, ViewGroup parent, int i) {
                return inflater.inflate(R.layout.item_img_layout, parent, false);
            }

            @Override
            protected void bindView(View view, final int i) {
                final ImageView imageView = view.findViewById(R.id.iv_img);
                Glide.with(mContext).load(mData.get(i)).into(imageView);
                if (mData.size() == 1) {
                    Glide.with(mContext)
                            .asBitmap()
                            .load(mData.get(0))
                            .into(new SimpleTarget<Bitmap>() {
                                @Override
                                public void onResourceReady(Bitmap bitmap, Transition<? super Bitmap> transition) {
                                    final int width = bitmap.getWidth();
                                    final int height = bitmap.getHeight();
                                    nineImageLayout.setSingleImage(width, height,imageView);
                                }
                            });
                    Glide.with(mContext).load(mData.get(0)).into(imageView);
                } else {
                    Glide.with(mContext).load(mData.get(i)).into(imageView);
                }
            }

            @Override
            public void OnItemClick(int i, View view) {
                super.OnItemClick(position, view);
                Toast.makeText(mContext, "position:" + mData.get(i), Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public int getItemCount() {
        return mList.size();
    }
 
    class MyViewHolder extends RecyclerView.ViewHolder {
        TextView tvTitle;
        NineImageLayout nineImageLayout;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            tvTitle = itemView.findViewById(R.id.tv_title);
            nineImageLayout = itemView.findViewById(R.id.nine_image_layout);
        }
    }
}

三、源碼地址

具體自定義NineImageLayout過程,可以查看NineImageLayout

四、總結

到此這篇關於Android自定義ViewGroup實現朋友圈九宮格控件的文章就介紹到這瞭,更多相關Android朋友圈九宮格控件內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: