Android默认头像那些事儿
Posted 冷不冷
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android默认头像那些事儿相关的知识,希望对你有一定的参考价值。
android应用市场中几乎所有APP中都会涉及用户体系.当然也就需要页面去处理用户信息的展示、用户头像的展示等.对于用户头像展示,有很多优秀的图片加载框架,平常写项目会经常使用到这些图片加载框架,使用起来也很方便,效率也比较高.但是面对不同的需求时,处理的方式可能就有些不同.下面分析几种需求.
文章使用Glide框架, 当然其他的图片加载框架处理方式应该相似,就不多做介绍.简单介绍下Glide的集成配置
首先配置一下Glide.在build.grade中添加对Gilde的引用及网络框架的引用
compile 'com.github.bumptech.glide:glide:3.7.0'
//OkHttp 3.x
compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'
compile 'com.squareup.okhttp3:okhttp:3.2.0’
然后配置一下权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE”/>
接着就可以使用Glide了.
分析
1) 第一种需求
设置一个默认的头像图片显示,这种需求是最常见,也是最容易处理的.
用Glide一句代码就可以实现,如下
Glide.with(Activity).load("头像地址URL").placeholder(R.mipmap.xxxx).dontAnimate().into(ImageView);
with中的参数可以是Activity,fragment,context.
placeholder中的参数就是项目中默认图片的资源.
dontAnimate方法是取消动画效果
into中的参数当然就是需要展示图像的ImageView
2) 第二种需求
设置一个圆形(圆角)的默认头像图片显示,这种需求也比较常见,唯一的问题就是圆形(圆角)的图片展示.对于圆形图片展示,因为用到Glide所以这里想到最简便的解决方法就是找一个继承自ImageView的自定义控件.有很多,文章选用CircleImageView来进行演示,有兴趣的童鞋可以深入看一下实现.
github地址https://github.com/hdodenhof/CircleImageView
那面对这种需求,就可以这样写
Glide.with(Activity).load("头像地址URL")
.placeholder(R.mipmap.xxxx).dontAn imate().into(CircleImageView);
into中参数为圆形自定义控件.
3) 第三种需求
设置一个带有随机背景颜色和文字的默认图片展示,这种需求往往出现在通讯录,好友等场景下,文字的目的是为了让用户更快的找到自己想找的目标(当然,我也是最近写项目,产品提的这种需求),随机背景颜色是为了更加美观(我认为的- -~).
好了,面对这种需求,得先考虑一下怎么去做,如果去适应Glide,那就看一下placeholder方法,可以看到Glide提供了两种方法,如下
/**
* @inheritDoc
*/
@Override
public DrawableRequestBuilder<ModelType> placeholder(int resourceId)
super.placeholder(resourceId);
return this;
/**
* @inheritDoc
*/
@Override
public DrawableRequestBuilder<ModelType> placeholder(Drawable drawable)
super.placeholder(drawable);
return this;
第一个方法是之前用到的,参数是一个默认的资源文件,第二个重载方法的参数是一个Drawable,显然文字是变化的,资源文件并不合适,只能在第二个重载方法上考虑一下.怎么做呢?其实很简单,可以通过安卓提供的方法创建一个带有文字和背景颜色的Drawable对象.贴一下完整代码,比较简单
package com.angent.defaultavatardemo.utils;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
/**
* Created by junweiliu on 17/1/18.
*/
public class MakeRandomPhoto
/**
* 默认字体大小
*/
private final int DEFAULT_FONT_SIZE = 20;
/**
* 默认字体大小
*/
private final int DEFAULT_FONT_COLOR = Color.WHITE;
/**
* 默认的图片宽
*/
private final int DEFAULT_WIDTH = 60;
/**
* 默认的图片高
*/
private final int DEFAULT_HEIGHT = 60;
/**
* 默认显示的文字数目
*/
private final int DEFAULT_SHOW_NUM = 2;
/**
* 默认的图片颜色
*/
private final int DEFAULT_COLOR = Color.BLUE;
/**
* 图片宽高
*/
private int width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT;
/**
* 图片颜色
*/
private int color = DEFAULT_COLOR;
/**
* 文字大小
*/
private int fontSize = DEFAULT_FONT_SIZE;
/**
* 文字颜色
*/
private int fontColor = DEFAULT_FONT_COLOR;
/**
* 默认显示的文字数
*/
private int showNum = DEFAULT_SHOW_NUM;
/**
* 画笔
*/
private Paint mPaint;
/**
* 画笔属性
*/
private Paint.FontMetrics fm;
/**
* 单例
*/
public static MakeRandomPhoto instance;
/**
* 获取单例
*
* @return
*/
public static MakeRandomPhoto getInstance()
if (instance == null)
synchronized (MakeRandomPhoto.class)
if (instance == null)
instance = new MakeRandomPhoto();
return instance;
/**
* 设置图片宽
*
* @return
*/
public MakeRandomPhoto setWidth(int width)
if (0 == width)
this.width = DEFAULT_WIDTH;
else
this.width = width;
return instance;
/**
* 设置图片背景颜色
*
* @return
*/
public MakeRandomPhoto setBackGroudColor(int color)
if (0 == color)
this.color = DEFAULT_COLOR;
else
this.color = color;
return this;
/**
* 设置图片高
*
* @return
*/
public MakeRandomPhoto setHeight(int height)
if (0 == height)
this.height = DEFAULT_HEIGHT;
else
this.height = height;
return this;
/**
* 设置文字颜色
*
* @return
*/
public MakeRandomPhoto setTxtColor(int fontcolor)
if (0 == fontcolor)
this.fontColor = DEFAULT_FONT_COLOR;
else
this.fontColor = fontcolor;
return this;
/**
* 设置文字大小
*
* @return
*/
public MakeRandomPhoto setTxtSize(int fontsize)
if (0 == fontsize)
this.fontSize = DEFAULT_FONT_SIZE;
else
this.fontSize = fontsize;
return this;
/**
* 设置显示文字个数
*
* @return
*/
public MakeRandomPhoto setShowNum(int showNum)
if (0 == showNum)
this.showNum = DEFAULT_SHOW_NUM;
else
this.showNum = showNum;
return this;
/**
* 创建随机图片
*
* @return
*/
public Bitmap makeRandomPhotoBp(String txt)
if (null == txt || "".equals(txt))
txt = " ";
// 处理展示的文字
if (txt.length() > showNum)
txt = txt.substring(txt.length() - showNum);
// 这里使用RGB_565,系统开销小一点
Bitmap bp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bp);
mPaint = new Paint();
mPaint.setColor(fontColor);
mPaint.setTextSize(fontSize);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setAntiAlias(true);
fm = mPaint.getFontMetrics();
// 设置背景颜色
c.drawColor(ColorUtils.getRandomColor(txt.hashCode()));
// 居中显示
c.drawText(txt, width / 2, height / 2 - fm.descent + (fm.descent - fm.ascent) / 2, mPaint);
c.save(Canvas.ALL_SAVE_FLAG);//保存
c.restore();//
return bp;
/**
* 创建随机图片(Drawable)
*
* @return
*/
public Drawable makeRandomPhotoDrawable(String txt)
Drawable db = new BitmapDrawable(makeRandomPhotoBp(txt));
return db;
/**
* 创建群组图像
*
* @param leftTopBp
* @param rightTopBp
* @param leftBottomBp
* @param rightBottomBp
* @return
*/
public Bitmap makeGroupPhotoBp(Bitmap leftTopBp, Bitmap rightTopBp, Bitmap leftBottomBp, Bitmap rightBottomBp)
Bitmap bp = Bitmap.createBitmap(width * 2, height * 2, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bp);
Paint mPaint = new Paint();
// 绘制左上角
c.drawBitmap(leftTopBp, 0, 0, mPaint);
// 绘制右上角
c.drawBitmap(rightTopBp, width, 0, mPaint);
// 绘制左下角
c.drawBitmap(leftBottomBp, 0, height, mPaint);
// 绘制右下角
c.drawBitmap(rightBottomBp, width, height, mPaint);
c.save(Canvas.ALL_SAVE_FLAG);//保存
c.restore();
return bp;
/**
* 创建群组图片(Drawable)
*
* @return
*/
public Drawable makeGroupPhotoDrawable(Bitmap leftTopBp, Bitmap rightTopBp, Bitmap leftBottomBp, Bitmap rightBottomBp)
Drawable db = new BitmapDrawable(makeGroupPhotoBp(leftTopBp, rightTopBp, leftBottomBp, rightBottomBp));
return db;
使用方法,例如在适配器中
@Override
public View getView(final int position, View convertView, ViewGroup parent)
viewHolder = null;
UserBean bean = mDatas.get(position);
if (convertView == null)
convertView = mInflater.from(mContext).inflate(R.layout.item_user, null);
viewHolder = new ViewHolder();
viewHolder.userNameTv = (TextView) convertView.findViewById(R.id.tv_user_name);
viewHolder.userPhotoIv = (ImageView) convertView.findViewById(R.id.ci_user_photo);
viewHolder.userPhotoTv = (TextView) convertView.findViewById(R.id.tv_user_photo);
convertView.setTag(viewHolder);
else
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.userNameTv.setText(bean.getUserName());
// Glide加载
Glide.with(mContext).load(bean.getUserPhoto())
.placeholder(MakeRandomPhoto.getInstance().setWidth(48).setHeight(48).setTxtSize(20).setTxtColor(Color.parseColor("#ffffff")).setShowNum(2).makeRandomPhotoDrawable(bean.getUserName())).dontAnimate().into(viewHolder.userPhotoIv);
return convertView;
封装了一个制作默认头像的工具类,提供方法设置相关属性,每个设置方法都会返回对象本身是为了方便连缀使用,看一下核心方法
/**
* 创建随机图片
*
* @return
*/
public Bitmap makeRandomPhotoBp(String txt)
if (null == txt || "".equals(txt))
txt = " ";
if (txt.length() > showNum)
txt = txt.substring(txt.length() - showNum);
// 这里使用RGB_565,系统开销小一点
Bitmap bp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bp);
mPaint = new Paint();
mPaint.setColor(fontColor);
mPaint.setTextSize(fontSize);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setAntiAlias(true);
fm = mPaint.getFontMetrics();
// 设置背景颜色
c.drawColor(ColorUtils.getRandomColor(txt.hashCode()));
// 居中显示
c.drawText(txt, width / 2, height / 2 - fm.descent + (fm.descent - fm.ascent) / 2, mPaint);
c.save(Canvas.ALL_SAVE_FLAG);//保存
c.restore();//
return bp;
首先对传入的文字进行处理,截取出需要显示的文字,默认显示字符串的最后两个字符,当然也可以自己设置.然后创建了一个Bitmap,这里使用RGB_565而不是ARGB_8888,是因为RGB_565的开销要小于ARGB_8888,一个背景色对画质的要求不是很高.最后就是创建画布,在画布中去完成背景色和文字的绘制.有一个ColorUtils,这个是封装的一个随机颜色工具,一起看一下.
package com.angent.defaultavatardemo.utils;
import android.graphics.Color;
import android.support.annotation.IntRange;
import com.angent.defaultavatardemo.R;
/**
* Created by junweiliu on 17/1/18.
*/
public class ColorUtils
/**
* 随机颜色起始
*/
private static final int RANDOM_COLOR_START_RANGE = 0;
/**
* 随机颜色终止
*/
private static final int RANDOM_COLOR_END_RANGE = 7;
/**
* 获取随机color名称
*
* @param colorPosition 唯一值,这里用string的hashcode
* @return
*/
public static String getRandomColorName(@IntRange(from = RANDOM_COLOR_START_RANGE, to = RANDOM_COLOR_END_RANGE)
int colorPosition)
colorPosition = Math.abs(colorPosition) % RANDOM_COLOR_END_RANGE;
return String.format("random_color_%d", colorPosition + 1);
/**
* 获取随机color颜色
*
* @param colorPosition 唯一值,这里用string的hashcode
* @return
*/
public static int getRandomColor(@IntRange(from = RANDOM_COLOR_START_RANGE, to = RANDOM_COLOR_END_RANGE)
int colorPosition)
String colorNmae = getRandomColorName(colorPosition);
int resId = Color.parseColor("#8a8a8a");
if (colorNmae.contains("1"))
resId = Color.parseColor("#8a8a8a");
else if (colorNmae.contains("2"))
resId = Color.parseColor("#f7b54e");
else if (colorNmae.contains("3"))
resId = Color.parseColor("#17c295");
else if (colorNmae.contains("4"))
resId = Color.parseColor("#4da9eb");
else if (colorNmae.contains("5"))
resId = Color.parseColor("#b38979");
else if (colorNmae.contains("6"))
resId = Color.parseColor("#568aad");
else if (colorNmae.contains("7"))
resId = Color.parseColor("#f2725e");
else
resId = Color.parseColor("#8a8a8a");
return resId;
/**
* 获取color资源
*
* @param colorPosition 唯一值,这里用string的hashcode
* @return
*/
public static int getCircleColorBgId(@IntRange(from = RANDOM_COLOR_START_RANGE, to = RANDOM_COLOR_END_RANGE)
int colorPosition)
String colorNmae = getRandomColorName(colorPosition);
int resId = R.mipmap.random_color_one;
if (colorNmae.contains("1"))
resId = R.mipmap.random_color_one;
else if (colorNmae.contains("2"))
resId = R.mipmap.random_color_two;
else if (colorNmae.contains("3"))
resId = R.mipmap.random_color_three;
else if (colorNmae.contains("4"))
resId = R.mipmap.random_color_four;
else if (colorNmae.contains("5"))
resId = R.mipmap.random_color_five;
else if (colorNmae.contains("6"))
resId = R.mipmap.random_color_six;
else if (colorNmae.contains("7"))
resId = R.mipmap.random_color_seven;
else
resId = R.mipmap.random_color_one;
return resId;
ColorUtils的主要作用就是通过字符串的hashcode值,来生成一个随机的颜色值,当然相同字符串的hashcode值是相同的,这样就保证了每个文字对应一个相同的随机颜色.
ColorUtils中还提供了一个获取随机背景图片的方法,这个方法是干嘛用的呢?
这个就是为了第二种方案写的,如果不依赖Glide,不使用placeholder方法.怎么实现这种随机背景颜色上带有文字的默认头像呢,看一下布局文件,可能就懂了.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_user_photo"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_centerVertical="true"
android:layout_marginBottom="10dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="20sp"
android:visibility="visible"
/>
<com.angent.defaultavatardemo.widget.CircleImageView
android:id="@+id/ci_user_photo"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_centerVertical="true"
android:layout_marginBottom="10dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="10dp"
android:visibility="visible"/>
<TextView
android:id="@+id/tv_user_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/ci_user_photo"
android:text="名字"
android:textColor="#333333"
android:textSize="16sp"/>
</RelativeLayout>
在CircleImageView下边有一个TextView,位置刚好和CircleImageView重合,并且在下层.再看一下代码中的写法
@Override
public View getView(final int position, View convertView, ViewGroup parent)
...
viewHolder.userNameTv.setText(bean.getUserName());
// 设置随机颜色背景
viewHolder.userPhotoTv.setBackgroundResource(ColorUtils.getCircleColorBgId(bean.getUserName().hashCode()));
// 设置文字
viewHolder.userPhotoTv.setText(bean.getUserName().substring(bean.getUserName().length() - 2));
// 加载图像
Glide.with(mContext).load(bean.getUserPhoto()).dontAnimate().into(viewHolder.userPhotoIv);
return convertView;
应该很简单,这种方案的思路就是,如果Glide加载图片成功了,就把地下的TextView遮住,如果没有加载成功,那么下层的TextView就作为默认头像显示.
应该还有其他更好的方案,这里就提供这两种.测试了一下两种方案的性能,基本没有差别.推荐第二种方案,显示时比较清晰
最后看一下效果图吧
源码地址
以上是关于Android默认头像那些事儿的主要内容,如果未能解决你的问题,请参考以下文章