Android默认头像那些事儿
来源:互联网 发布:软件生存周期模型 编辑:程序博客网 时间:2024/05/21 15:02
Android应用市场中几乎所有APP中都会涉及用户体系.当然也就需要页面去处理用户信息的展示、用户头像的展示等.对于用户头像展示,有很多优秀的图片加载框架,平常写项目会经常使用到这些图片加载框架,使用起来也很方便,效率也比较高.但是面对不同的需求时,处理的方式可能就有些不同.下面分析几种需求.
文章使用Glide框架, 当然其他的图片加载框架处理方式应该相似,就不多做介绍.简单介绍下Glide的集成配置
首先配置一下Glide.在build.grade中添加对Gilde的引用及网络框架的引用
compile 'com.github.bumptech.glide:glide:3.7.0'//OkHttp 3.xcompile '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} */@Overridepublic DrawableRequestBuilder<ModelType> placeholder(int resourceId) { super.placeholder(resourceId); return this;}/** * {@inheritDoc} */@Overridepublic 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默认头像那些事儿
- Android系统升级那些事儿
- Android混淆那些事儿
- Android那些事儿
- Android Camera那些事儿
- Android 面试那些事儿
- 关于Android那些事儿
- Android 混淆那些事儿
- Android 混淆那些事儿
- Android 混淆那些事儿
- Android SdkVersion那些事儿
- Android代码优化那些事儿
- Android四大组件那些事儿
- Android Home键那些事儿
- 说说Android通知那些事儿
- Android动态加载那些事儿
- Android中线程那些事儿
- Android Drawable的那些事儿
- 大项目微服务架构设计
- 微信小程序页面传值
- [code-design]TvServer 之CRunOnce
- web.xml中关于Servlet、Filter、Listener的配置
- 标准C的标记化结构初始化语法
- Android默认头像那些事儿
- Git之远程仓库
- ExtJs学习总结(2)
- 使用多路复用套接字I/O提升性能之——ForkingMixIn 《Python网络编程攻略》
- PHPer必知:高并发网站应该如何进行优化?
- Java中堆和栈的区别
- Spring官网 jar包下载
- eclipse使用插件Rinzo在XML文件中自动提示java类
- MySQL Access denied for user 'root'@'%' to database 'xxx'