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就作为默认头像显示.

应该还有其他更好的方案,这里就提供这两种.测试了一下两种方案的性能,基本没有差别.推荐第二种方案,显示时比较清晰

最后看一下效果图吧

这里写图片描述


源码地址

源码下载

1 0
原创粉丝点击