Android仿微信群聊頭像效果
在網(wǎng)上找了些仿微信群聊頭像的開(kāi)源庫(kù)后,發(fā)現(xiàn)沒(méi)特別好用的,或者說(shuō)滿足我需求的,就只好在別人的基礎(chǔ)上改了下,也就有了這樣的自定義控件了,以此來(lái)實(shí)現(xiàn)微信群聊頭像的效果,效果圖如下所示:
主要實(shí)現(xiàn):
一、自定義viewGroup,以此來(lái)實(shí)現(xiàn)主要的代碼邏輯
public class NineGridImageView<T> extends ViewGroup{ private int mRowCount; //行數(shù) private int mColumnCount; //列數(shù) private int mMaxSize = 9; //最大圖片數(shù) private int mGap; //宮格間距 private int parentWidth;//父組件寬 private int parentHeight;//父組件高 private List<ImageView> mImageViewList = new ArrayList<>(); private List<T> mImgDataList; private NineGridImageViewAdapter<T> mAdapter; public NineGridImageView(Context context) { this(context,null); } public NineGridImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public NineGridImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NineGridImageView); this.mGap = (int) typedArray.getDimension(R.styleable.NineGridImageView_imgGap, 8); typedArray.recycle(); } /** * 設(shè)定寬高 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); parentWidth = measureWidth(widthMeasureSpec); parentHeight = measureHeight(heightMeasureSpec); setMeasuredDimension(parentWidth,parentHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { layoutChildrenView(); } /** * 為子ImageView布局 */ private void layoutChildrenView(){ if(mImgDataList == null){ return; } int childrenCount = mImgDataList.size(); for(int i = 0; i < childrenCount; i++){ ImageView childrenView = (ImageView)getChildAt(i); if(mAdapter != null){ mAdapter.onDisplayImage(getContext(), childrenView, mImgDataList.get(i)); } int rowNum = i / mColumnCount;//當(dāng)前行數(shù) int columnNum = i % mColumnCount;//當(dāng)前列數(shù) int mImageSize = (parentWidth-(mColumnCount+1)*mGap)/mColumnCount;//圖片尺寸 int t_center = (parentHeight + mGap)/2;//中間位置以下的頂點(diǎn)(有宮格間距) int b_center = (parentHeight - mGap)/2;//中間位置以上的底部(有宮格間距) int l_center = (parentWidth + mGap)/2;//中間位置以右的左部(有宮格間距) int r_center = (parentWidth - mGap)/2;//中間位置以左的右部(有宮格間距) int center = (parentHeight - mImageSize)/2;//中間位置以上頂部(無(wú)宮格間距) int left = mImageSize * columnNum + mGap * (columnNum + 1); int top = mImageSize * rowNum + mGap * (rowNum + 1); int right = left + mImageSize; int bottom = top + mImageSize; /** * 不同子view情況下的不同顯示 */ if(childrenCount == 1){ childrenView.layout(left, top, right, bottom); }else if(childrenCount == 2){ childrenView.layout(left, center, right, center + mImageSize); }else if(childrenCount == 3){ if(i == 0){ childrenView.layout(center, top, center+mImageSize, bottom); }else { childrenView.layout(mGap * i +mImageSize * (i - 1), t_center, mGap * i +mImageSize * i, t_center+mImageSize); } }else if(childrenCount == 4){ childrenView.layout(left, top, right, bottom); }else if(childrenCount == 5){ if(i == 0){ childrenView.layout(r_center - mImageSize, r_center - mImageSize, r_center, r_center); }else if(i == 1){ childrenView.layout(l_center , r_center - mImageSize, l_center + mImageSize, r_center); }else{ childrenView.layout(mGap * (i - 1) + mImageSize * (i - 2),t_center,mGap * (i - 1) + mImageSize * (i - 1),t_center+mImageSize); } }else if(childrenCount == 6){ if(i < 3) { childrenView.layout(mGap * (i + 1) +mImageSize * i, b_center - mImageSize, mGap * (i + 1) + mImageSize * (i+1), b_center); }else{ childrenView.layout(mGap * (i - 2) + mImageSize * (i - 3),t_center,mGap * (i - 2) + mImageSize * (i - 2),t_center+mImageSize); } }else if(childrenCount == 7){ if(i == 0){ childrenView.layout(center,mGap,center+mImageSize,mGap+mImageSize); }else if(i > 0 && i < 4){ childrenView.layout(mGap * i +mImageSize * (i - 1),center,mGap * i +mImageSize * i,center+mImageSize); }else{ childrenView.layout(mGap * (i - 3) + mImageSize * (i - 4),t_center+mImageSize/2,mGap * (i - 3) + mImageSize * (i - 3),t_center+mImageSize/2+mImageSize); } }else if(childrenCount == 8){ if(i == 0){ childrenView.layout(r_center - mImageSize,mGap,r_center,mGap+mImageSize); }else if(i == 1){ childrenView.layout(l_center,mGap,l_center+mImageSize,mGap+mImageSize); }else if(i > 1 && i < 5){ childrenView.layout(mGap * (i - 1) +mImageSize * (i - 2), center, mGap * (i - 1) +mImageSize * (i - 1), center+mImageSize); }else{ childrenView.layout(mGap * (i - 4) + mImageSize * (i - 5), t_center+mImageSize/2, mGap * (i - 4) + mImageSize * (i - 4), t_center+mImageSize/2+mImageSize); } }else if(childrenCount == 9){ childrenView.layout(left, top, right, bottom); } } } /** * 設(shè)置圖片數(shù)據(jù) * * @param lists 圖片數(shù)據(jù)集合 */ public void setImagesData(List lists){ if(lists == null || lists.isEmpty()){ this.setVisibility(GONE); return; }else { this.setVisibility(VISIBLE); } if(mMaxSize > 0 && lists.size() > mMaxSize){ lists = lists.subList(0, mMaxSize); } int[] gridParam = calculateGridParam(lists.size()); mRowCount = gridParam[0]; mColumnCount = gridParam[1]; if(mImgDataList == null){ int i = 0; while (i < lists.size()){ ImageView iv = getImageView(i); if(iv == null){ return; } addView(iv,generateDefaultLayoutParams()); i++; } }else { int oldViewCount = mImgDataList.size(); int newViewCount = lists.size(); if(oldViewCount > newViewCount){ removeViews(newViewCount, oldViewCount - newViewCount); }else if(oldViewCount < newViewCount){ for(int i = oldViewCount; i < newViewCount; i++){ ImageView iv = getImageView(i); if(iv == null){ return; } addView(iv, generateDefaultLayoutParams()); } } } mImgDataList = lists; requestLayout(); } /** * 獲得 ImageView * 保證了 ImageView的重用 * * @param position 位置 */ private ImageView getImageView(final int position){ if(position < mImageViewList.size()){ return mImageViewList.get(position); }else{ if(mAdapter != null){ ImageView imageView = mAdapter.generateImageView(getContext()); mImageViewList.add(imageView); return imageView; }else{ Log.e("NineGirdImageView", "Your must set a NineGridImageViewAdapter for NineGirdImageView"); return null; } } } /** * 設(shè)置宮格參數(shù) * * @param imagesSize 圖片數(shù)量 * @return 宮格參數(shù) gridParam[0] 宮格行數(shù) gridParam[1] 宮格列數(shù) */ protected static int[] calculateGridParam(int imagesSize){ int[] gridParam = new int[2]; if(imagesSize < 3){ gridParam[0] = 1; gridParam[1] = imagesSize; }else if(imagesSize <= 4){ gridParam[0] = 2; gridParam[1] = 2; }else{ gridParam[0] = imagesSize/3 + (imagesSize % 3 == 0?0:1); gridParam[1] = 3; } return gridParam; } /** * 設(shè)置適配器 * * @param adapter 適配器 */ public void setAdapter(NineGridImageViewAdapter adapter){ mAdapter = adapter; } /** * 設(shè)置宮格間距 * * @param gap 宮格間距 px */ public void setGap(int gap){ mGap = gap; } /** * 對(duì)宮格的寬高進(jìn)行重新定義 */ private int measureWidth(int measureSpec){ int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if(specMode == MeasureSpec.EXACTLY){ result = specSize; }else{ result = 200; if(specMode == MeasureSpec.AT_MOST){ result = Math.min(result,specSize); } } return result; } private int measureHeight(int measureSpec){ int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if(specMode == MeasureSpec.EXACTLY){ result = specSize; }else{ result = 200; if(specMode == MeasureSpec.AT_MOST){ result = Math.min(result,specSize); } } return result; } }
二、你要顯示你的網(wǎng)絡(luò)圖片所需要的代碼
public abstract class NineGridImageViewAdapter<T> { protected abstract void onDisplayImage(Context context, ImageView imageView, T t); protected ImageView generateImageView(Context context){ ImageView imageView = new ImageView(context); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); return imageView; } //這里可以添加你所需要的事件之類(lèi)的方法 }
對(duì)了,別忘了配置間隔屬性,記得添加attrs.xml文件,加上如下代碼
<declare-styleable name="NineGridImageView"> <attr format="dimension" name="imgGap"/> </declare-styleable>
三、用法
NineGridImageViewAdapter<String> mAdapter = new NineGridImageViewAdapter<String>() { @Override protected void onDisplayImage(Context context, ImageView imageView, String s) { Picasso.with(context).load(s).placeholder(R.mipmap.ic_holding).error(R.mipmap.ic_error).into(imageView); } @Override protected ImageView generateImageView(Context context) { return super.generateImageView(context); } }; groudIcon1.setAdapter(mAdapter); groudIcon1.setImagesData(mPostList1);
四、總結(jié)
用適配器模式的方法給群聊頭像加圖片的方式是想可以在這里可以用不同方式來(lái)實(shí)現(xiàn)圖片的加載方式,這里普及下適配器模式的知識(shí),主要是把一個(gè)類(lèi)的接口變換成客戶(hù)端所期待的另一種接口,從而使原本因接口不匹配而無(wú)法在一起工作的兩個(gè)類(lèi)能夠在一起工作,優(yōu)點(diǎn)是更好的復(fù)用性和擴(kuò)展性,缺點(diǎn)則是過(guò)多使用會(huì)使系統(tǒng)零亂,不易整體把握。好像有點(diǎn)偏題了,這里就附上:GroupIconSample源碼地址
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
android實(shí)現(xiàn)搜索功能并將搜索結(jié)果保存到SQLite中(實(shí)例代碼)
這篇文章主要介紹了android實(shí)現(xiàn)搜索功能并將搜索結(jié)果保存到SQLite中,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04RxJava2和Retrofit2封裝教程(整潔、簡(jiǎn)單、實(shí)用)
這篇文章主要給大家介紹了關(guān)于RxJava2和Retrofit2封裝的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),整潔、簡(jiǎn)單、實(shí)用,非常適合大家學(xué)習(xí)使用,需要的朋友可以參考下2018-11-11vscode通過(guò)wifi調(diào)試真機(jī)的Flutter應(yīng)用的教程
這篇文章主要介紹了vscode通過(guò)wifi調(diào)試真機(jī)的Flutter應(yīng)用的教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04Android 路徑查詢(xún)具體實(shí)現(xiàn)
可以通過(guò)RasterMap的getDirection()方法來(lái)查詢(xún)路徑,和查詢(xún)地址類(lèi)似,路徑查詢(xún)的結(jié)果也是通過(guò)回調(diào)函數(shù)的方式來(lái)通知應(yīng)用程序的,下面的例子返回南京到北京的路徑2013-10-10Android控件之EditView常用屬性及應(yīng)用方法
本篇文章介紹了,Android控件之EditView常用屬性及應(yīng)用方法。需要的朋友參考下2013-04-04Android開(kāi)發(fā)之Picasso通過(guò)URL獲取用戶(hù)頭像的圓形顯示
這篇文章主要介紹了android開(kāi)發(fā)之Picasso通過(guò)URL獲取用戶(hù)頭像的圓形顯示,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-06-06Android開(kāi)發(fā)中ProgressDialog簡(jiǎn)單用法示例
這篇文章主要介紹了Android開(kāi)發(fā)中ProgressDialog簡(jiǎn)單用法,結(jié)合實(shí)例形式分析了Android使用ProgressDialog的進(jìn)度條顯示與關(guān)閉、更新等事件響應(yīng)相關(guān)操作技巧,需要的朋友可以參考下2017-10-10超實(shí)用的android網(wǎng)絡(luò)工具類(lèi)
這篇文章主要為大家詳細(xì)介紹了超實(shí)用的android網(wǎng)絡(luò)工具類(lèi),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04Android 5.0 實(shí)現(xiàn)水波擴(kuò)散效果
這篇文章主要為大家詳細(xì)介紹了Android 5.0 實(shí)現(xiàn)水波擴(kuò)散效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01