Android自定義ViewGroup實(shí)現(xiàn)朋友圈九宮格控件
一、簡(jiǎn)介
最近項(xiàng)目里有個(gè)類似微信朋友圈的九圖控件的需求,Github找了一下,發(fā)現(xiàn)都不太滿足需求,我需要單張圖片的時(shí)候可以按照?qǐng)D片寬高比列在一定范圍內(nèi)自適應(yīng),而大多開(kāi)源項(xiàng)目單張圖片也是一個(gè)小正方形,所以,干脆自己動(dòng)手寫(xiě)一個(gè)
1.1、效果圖如下
1.2、主要功能如下
1:?jiǎn)螐垐D片的時(shí)候支持按照?qǐng)D片寬高比列在設(shè)定區(qū)域內(nèi)自適應(yīng)
2:Adapter方式綁定數(shù)據(jù)和UI
3:圖片點(diǎn)擊事件回調(diào)
4:設(shè)置圖片間隔大小
5:自由通過(guò)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、列表里面使用
頁(yè)面放一個(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)造一下測(cè)試數(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過(guò)程,可以查看NineImageLayout
四、總結(jié)
到此這篇關(guān)于Android自定義ViewGroup實(shí)現(xiàn)朋友圈九宮格控件的文章就介紹到這了,更多相關(guān)Android朋友圈九宮格控件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android控件ListView用法(讀取聯(lián)系人示例代碼)
本文以一個(gè)讀取聯(lián)系人的代碼為大家講解下Android控件中ListView的使用方法,這個(gè)listView有個(gè)setAdapter 適配器,里面可以直接實(shí)現(xiàn)接口,或者寫(xiě)個(gè)類2013-06-06android studio開(kāi)發(fā)實(shí)現(xiàn)APP開(kāi)機(jī)自啟動(dòng)
這篇文章主要為大家詳細(xì)介紹了android studio開(kāi)發(fā)實(shí)現(xiàn)APP開(kāi)機(jī)自啟動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05Android開(kāi)發(fā)中的9個(gè)常見(jiàn)錯(cuò)誤和解決方法
這篇文章主要介紹了Android開(kāi)發(fā)中的9個(gè)常見(jiàn)錯(cuò)誤和解決方法,這是Android開(kāi)發(fā)中最常見(jiàn)的9個(gè)錯(cuò)誤,經(jīng)過(guò)各種各樣的整理,以及和熱心網(wǎng)友討論總結(jié)而來(lái),需要的朋友可以參考下2015-01-01Android 開(kāi)發(fā)中Volley詳解及實(shí)例
這篇文章主要介紹了Android 開(kāi)發(fā)中Volley詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-04-04Android studio git創(chuàng)建與刪除標(biāo)簽(Tag)的教程詳解
這篇文章主要介紹了Android studio git創(chuàng)建與刪除標(biāo)簽(Tag)的教程詳解,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12Android App實(shí)現(xiàn)應(yīng)用內(nèi)部自動(dòng)更新的最基本方法示例
這篇文章主要介紹了實(shí)現(xiàn)Android App內(nèi)部自動(dòng)更新的最基本方法示例,包括IIS服務(wù)器端的簡(jiǎn)單布置,需要的朋友可以參考下2016-03-03FragmentTabHost FrameLayout實(shí)現(xiàn)底部導(dǎo)航欄
這篇文章主要為大家詳細(xì)介紹了FragmentTabHost和FrameLayout實(shí)現(xiàn)底部導(dǎo)航欄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03Android編程獲取設(shè)備MAC地址的實(shí)現(xiàn)方法
這篇文章主要介紹了Android編程獲取設(shè)備MAC地址的實(shí)現(xiàn)方法,涉及Android針對(duì)硬件設(shè)備的操作技巧,需要的朋友可以參考下2017-01-01