Android仿微信群聊頭像效果
在網(wǎng)上找了些仿微信群聊頭像的開源庫后,發(fā)現(xiàn)沒特別好用的,或者說滿足我需求的,就只好在別人的基礎(chǔ)上改了下,也就有了這樣的自定義控件了,以此來實(shí)現(xiàn)微信群聊頭像的效果,效果圖如下所示:

主要實(shí)現(xiàn):
一、自定義viewGroup,以此來實(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;//中間位置以上頂部(無宮格間距)
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;
}
//這里可以添加你所需要的事件之類的方法
}
對(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é)
用適配器模式的方法給群聊頭像加圖片的方式是想可以在這里可以用不同方式來實(shí)現(xiàn)圖片的加載方式,這里普及下適配器模式的知識(shí),主要是把一個(gè)類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個(gè)類能夠在一起工作,優(yōu)點(diǎn)是更好的復(fù)用性和擴(kuò)展性,缺點(diǎn)則是過多使用會(huì)使系統(tǒng)零亂,不易整體把握。好像有點(diǎn)偏題了,這里就附上:GroupIconSample源碼地址
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android服務(wù)應(yīng)用ClockService實(shí)現(xiàn)鬧鐘功能
這篇文章主要為大家詳細(xì)介紹了Android服務(wù)應(yīng)用ClockService實(shí)現(xiàn)鬧鐘功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11
android實(shí)現(xiàn)圖片驗(yàn)證碼方法解析(自繪控件)
本文主要介紹了android自繪控件的應(yīng)用--實(shí)現(xiàn)圖片驗(yàn)證碼方法案例,具有一定的參考價(jià)值,下面跟著小編一起來看下吧2017-01-01
Android如何利用svg實(shí)現(xiàn)可縮放的地圖控件
這篇文章主要給大家介紹了關(guān)于Android如何利用svg實(shí)現(xiàn)可縮放的地圖控件的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01
Android權(quán)限機(jī)制帶來的一些安全問題介紹
這篇文章主要介紹了Android權(quán)限機(jī)制帶來的一些安全問題介紹,本文講解了權(quán)限機(jī)制的缺陷和不足、樹立權(quán)限意識(shí)、越過權(quán)限機(jī)制等內(nèi)容,需要的朋友可以參考下2015-04-04
OpenGL ES正交投影實(shí)現(xiàn)方法(三)
這篇文章主要為大家詳細(xì)介紹了OpenGL ES正交投影的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05
Android開發(fā)實(shí)戰(zhàn)之漂亮的ViewPager引導(dǎo)頁
這篇文章主要介紹了Android開發(fā)實(shí)戰(zhàn)中漂亮ViewPager引導(dǎo)頁的制作過程,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08
Androd 勇闖高階性能優(yōu)化之布局優(yōu)化篇
Android性能優(yōu)化方面也有很多文章了,這里就做一個(gè)總結(jié),從原理到方法,工具等做一個(gè)簡(jiǎn)單的了解,從而可以慢慢地改變編碼風(fēng)格,從而提高性能2021-10-10
Android ViewPager實(shí)現(xiàn)無限循環(huán)輪播廣告位Banner效果
這篇文章主要為大家詳細(xì)介紹了Android ViewPager實(shí)現(xiàn)無限循環(huán)輪播廣告位Banner效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07

