Android仿微信群聊头像效果

在网上找了些仿微信群聊头像的开源库后,发现没特别好用的,或者说满足我需求的,就只好在别人的基础上改了下,也就有了这样的自定义控件了,以此来实现微信群聊头像的效果,效果图如下所示:

主要实现:

一、自定义viewGroup,以此来实现主要的代码逻辑

public class NineGridImageView<T> extends ViewGroup{

 private int mRowCount; //行数
 private int mColumnCount; //列数

 private int mMaxSize = 9; //最大图片数
 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();
 }

 /**
  * 设定宽高
  */
 @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;//当前行数
   int columnNum = i % mColumnCount;//当前列数

   int mImageSize = (parentWidth-(mColumnCount+1)*mGap)/mColumnCount;//图片尺寸

   int t_center = (parentHeight + mGap)/2;//中间位置以下的顶点(有宫格间距)
   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);
   }
  }
 }

 /**
  * 设置图片数据
  *
  * @param lists 图片数据集合
  */
 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;
   }
  }
 }

 /**
  * 设置宫格参数
  *
  * @param imagesSize 图片数量
  * @return 宫格参数 gridParam[0] 宫格行数 gridParam[1] 宫格列数
  */
 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;
 }

 /**
  * 设置适配器
  *
  * @param adapter 适配器
  */
 public void setAdapter(NineGridImageViewAdapter adapter){
  mAdapter = adapter;
 }

 /**
  * 设置宫格间距
  *
  * @param gap 宫格间距 px
  */
 public void setGap(int gap){
  mGap = gap;
 }

 /**
  * 对宫格的宽高进行重新定义
  */
 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;
 }
}

二、你要显示你的网络图片所需要的代码

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;
 }

 //这里可以添加你所需要的事件之类的方法
}

对了,别忘了配置间隔属性,记得添加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);

四、总结

用适配器模式的方法给群聊头像加图片的方式是想可以在这里可以用不同方式来实现图片的加载方式,这里普及下适配器模式的知识,主要是把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作,优点是更好的复用性和扩展性,缺点则是过多使用会使系统零乱,不易整体把握。好像有点偏题了,这里就附上:GroupIconSample源码地址

参考:NineGridImageView

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android仿微信和QQ多图合并框架(类似群头像)的实现方法

    前言 现在多数app里面加入聊天已经是一个非常普遍的现象了,而微信和qq则是通讯领域的鼻祖了.如果产品经理在考虑做聊天设计的时候,多数会参考. 常常你会听到,你看微信和qq都是这么做的,你就这么来吧,虽然心理有一万个不痛快,但谁叫我们是有一个有追求的程序员呢. 所以产品的要求是实现类似微信的群头像. 类似如下 作为程序员,首先会评估下工作量吧.在产品眼里,就是把图片合成一起嘛,有啥难度吗?所以工作时间决定了你能做成什么样吧 方案分析: 方案1.直接写成布局,然后按照不同的布局加载不同张数的图片.

  • android 实现类似微信缓存和即时更新好友头像示例

    引言 使用微信时我们会发现,首次进入微信的好友列表时,会加载好友头像,但是再次进入时,就不用重新加载了,而且其他页面都不用重新加载,说明微信的好友头像是缓存在本地的,然后好友修改头像后,又会及时的更新,这个功能是如何实现的呢,我们来分析一下 分析 关于头像缓存的实现 头像是网络图片,而且数据量较大,如果用我们常用的SharedPreferences将头像以Bitmap的形式存储,势必会造成OOM,这个方法是行不通的,我们存储的只能是图片的地址,但是如果只存储地址的话,要转化成图片,还是要通过网络

  • Android仿微信QQ设置图形头像裁剪功能

    最近在做毕业设计,想有一个功能和QQ一样可以裁剪头像并设置圆形头像,额,这是设计狮的一种潮流. 而纵观现在主流的APP,只要有用户系统这个功能,这个需求一般都是在(bu)劫(de)难(bu)逃(xue)! 图片裁剪实现方式有两种,一种是利用系统自带的裁剪工具,一种是使用开源工具Cropper.本节就为大家带来如何使用系统自带的裁剪工具进行图片裁剪~ 还是先来个简单的运行图. 额,简单说下,我待会会把代码写成小demo分享给大家,在文章末尾会附上github链接,需要的可以自行下载~ 下面来简单分

  • Android仿微信群聊头像

    工作中需要实现仿钉钉群头像的一个功能,就是个人的头像拼到一起显示,看了一下市场上的APP好像微信的群聊头像是组合的,QQ的头像不是,别的好像也没有了. 给大家分享一下怎么实现的吧.首先我们先看一下效果图: 好了,下面说一下具体怎么实现的: 实现思路 1.首先获取Bitmap图片(本地.网络) 2.创建一个指定大小的缩略图 3.组合Bitmap图片 很简单,本地图片需要我们从本地读取,如果是网络图片我们也可以根据URL来获取bitmap进行组合 具体实现过程 1.布局文件: <LinearLayo

  • Android仿微信群聊头像效果

    在网上找了些仿微信群聊头像的开源库后,发现没特别好用的,或者说满足我需求的,就只好在别人的基础上改了下,也就有了这样的自定义控件了,以此来实现微信群聊头像的效果,效果图如下所示: 主要实现: 一.自定义viewGroup,以此来实现主要的代码逻辑 public class NineGridImageView<T> extends ViewGroup{ private int mRowCount; //行数 private int mColumnCount; //列数 private int m

  • Android仿微信文章悬浮窗效果的实现代码

    序言 前些日子跟朋友聊天,朋友Z果粉,前些天更新了微信,说微信出了个好方便的功能啊,我问是啥功能啊,看看我大Android有没有,他说现在阅读公众号文章如果有人给你发微信你可以把这篇文章当作悬浮窗悬浮起来,方便你聊完天不用找继续阅读,听完是不是觉得这叫啥啊,我大Android微信版不是早就有这个功能了吗,我看文章的时候看到过有这个悬浮按钮,但是我一直没有使用过,试了一下还是挺方便的,就想着自己实现一下这个功能,下面看图,大家都习惯了无图言X 原理 看完动图我们来分析一下,如何在每个页面上都存在一

  • Android仿微信页面底部导航效果代码实现

    大家在参考本地代码的时候要根据需要适当的修改,里面有冗余代码小编没有删除.好了,废话不多说了,一切让代码说话吧! 关键代码如下所示: .java里面的主要代码 public class MainActivity extends BaseActivity implements TabChangeListener { private Fragment[] fragments; private FragZaiXianYuYue fragZaiXianYuYue; private FragDaoLuJi

  • Android仿微信长按菜单效果

    本文实例为大家分享了Android仿微信长按菜单展示的具体代码,供大家参考,具体内容如下 FloatMenu A menu style pop-up window that mimics WeChat.仿微信的长按菜单. 效果如下 引入方法: Github地址:https://github.com/JavaNoober/FloatMenu dependencies { .... compile 'com.noober.floatmenu:common:1.0.2' } 使用说明 使用方法1: A

  • Android 仿微信底部渐变Tab效果

    先来看一下效果图 除了第三个的发现Tab有所差别外,其他的基本还原了微信的底部Tab渐变效果 每个Tab都是一个自定义View,根据ImageView的tint属性来实现颜色渐变效果,tint属性的使用可以看我的上一篇文章 我将自定义View命名为ShadeView,包含四个自定义属性 意思分别为图标.背景色.底部文本.底部文本大小 <declare-styleable name="ShadeView"> <attr name="icon" for

  • Android仿微信通讯录列表侧边栏效果

    先看Android仿微信通讯录列表侧边栏效果图 这是比较常见的效果了吧 列表根据首字符的拼音字母来排序,且可以通过侧边栏的字母索引来进行定位. 实现这样一个效果并不难,只要自定义一个索引View,然后引入一个可以对汉字进行拼音解析的jar包--pinyin4j-2.5.0即可 首先,先来定义侧边栏控件View,只要直接画出来即可. 字母选中项会变为红色,且滑动时背景会变色,此时SideBar并不包含居中的提示文本 public class SideBar extends View { priva

  • Android仿微信activity滑动关闭效果

    Android仿微信activity滑动关闭功能 1.利用具体利用v4包下的slidingPaneLayout实现透明的activity,代码如下: BaseActivity: public class BaseSlideCloseActivity extends AppCompatActivity implements SlidingPaneLayout.PanelSlideListener { @Override protected void onCreate(Bundle savedIns

  • Android仿QQ讨论组头像效果

    本文实例为大家分享了Android仿QQ讨论组头像展示的具体代码,供大家参考,具体内容如下 一.效果图 二.实现 基本实现过程: 1.将原图片读取为bitmap 2.在Canvas画布上计算出图片位置,并绘制新的图片. (ps:计算位置对我来说是难点,花了好长时间): 三.源码 1.布局文件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http:/

  • Android仿微信顶/底部菜单栏效果

    本文要实现仿微信微信底部菜单栏+顶部菜单栏,采用ViewPage来做,每一个page对应一个XML,当手指在ViewPage左右滑动时,就相应显示不同的page(其实就是xml)并且同时改变底部菜单按钮的图片变暗或变亮,同时如果点击底部菜单按钮,左右滑动page(其实就是xml)并且改变相应按钮的亮度. 一.布局 1.顶部菜单布局,命名为top_layout.xml <?xml version="1.0" encoding="utf-8"?> <R

随机推荐