Android自定義ViewGroup實(shí)現(xiàn)朋友圈九宮格控件
一、簡介
最近項(xiàng)目里有個(gè)類似微信朋友圈的九圖控件的需求,Github找了一下,發(fā)現(xiàn)都不太滿足需求,我需要單張圖片的時(shí)候可以按照?qǐng)D片寬高比列在一定范圍內(nèi)自適應(yīng),而大多開源項(xiàng)目單張圖片也是一個(gè)小正方形,所以,干脆自己動(dòng)手寫一個(gè)
1.1、效果圖如下

1.2、主要功能如下
1:單張圖片的時(shí)候支持按照?qǐng)D片寬高比列在設(shè)定區(qū)域內(nèi)自適應(yīng)
2:Adapter方式綁定數(shù)據(jù)和UI
3:圖片點(diǎn)擊事件回調(diào)
4:設(shè)置圖片間隔大小
5:自由通過Glide設(shè)置ImageView圓角效果
二、使用
2.1、自定義屬性如下
<resources>
<declare-styleable name="NineImageLayout">
<!-- 控件寬高 -->
<attr name="nine_layoutWidth" format="dimension"/>
<!-- 單張圖片時(shí)的最大寬高范圍-->
<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方式綁定數(shù)據(jù)和UI
其中Glide.asBitmap是為了計(jì)算圖片寬高,如果后臺(tái)有返回圖片的寬高可以省略這一步,直接setSingleImage(width, height,imageView),
Ps:如果可以建議后臺(tái)返回圖片寬高,這樣可以避免單張圖片的時(shí)候控件高度跳屏,比如我限制單張圖片寬高在200dp范圍,要展示寬1000px高500px的時(shí)候,在圖片未加載完成時(shí)控件寬高為200dp,圖片加載完成后高度變?yōu)?00dp,會(huì)有一個(gè)不好的用戶體驗(yàn),所以建議上傳圖片的時(shí)候記錄圖片寬高信息
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、列表里面使用
頁面放一個(gè)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="標(biāo)題"
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中構(gòu)造一下測試數(shù)據(jù),大致代碼如下
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中設(shè)置數(shù)據(jù)
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() + "張圖片的標(biāo)題");
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
四、總結(jié)
到此這篇關(guān)于Android自定義ViewGroup實(shí)現(xiàn)朋友圈九宮格控件的文章就介紹到這了,更多相關(guān)Android朋友圈九宮格控件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android 點(diǎn)擊editview以外位置實(shí)現(xiàn)隱藏輸入法
這篇文章主要介紹了Android 點(diǎn)擊editview以外位置實(shí)現(xiàn)隱藏輸入法的相關(guān)資料,需要的朋友可以參考下2017-06-06
Android LuBan與Compressor圖片壓縮方式
本篇文章主要介紹了Android LuBan與Compressor圖片壓縮方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-04-04
Android設(shè)計(jì)模式之Builder模式解析
這篇文章主要為大家詳細(xì)介紹了Android設(shè)計(jì)模式之Builder模式解析的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
PowerManagerService之自動(dòng)滅屏流程解析
這篇文章主要為大家介紹了PowerManagerService之自動(dòng)滅屏流程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
Android應(yīng)用開發(fā)中使用GridView網(wǎng)格布局的代碼示例
GridView布局比較基礎(chǔ),可以取代已經(jīng)逐漸淡出人們視線的TableLayout,這里我們就來看一下Android應(yīng)用開發(fā)中使用GridView網(wǎng)格布局的代碼示例:2016-06-06
Android開發(fā)之自定義刮刮卡實(shí)現(xiàn)代碼
本篇文章主要介紹了Android開發(fā)之自定義刮刮卡實(shí)現(xiàn)代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07
詳解VirtualApk啟動(dòng)插件Activity
這篇文章主要介紹了詳解VirtualApk啟動(dòng)插件Activity,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05

