项目中有用到圆形头像选择,我们看看google是怎样实现的吧!
左边是点击前,右边点击后会显示一个圆弧.
widget下有个 AvaterView
/**
* A simple view that wraps an avatar.
*/
public class AvatarView extends ImageView implements Checkable {
private boolean mChecked;
public AvatarView(Context context) {
this(context, null);
}
public AvatarView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AvatarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setChecked(boolean b) {
mChecked = b;
invalidate();
}
@Override
public boolean isChecked() {
return mChecked;
}
@Override
public void toggle() {
setChecked(!mChecked);
}
/**
* Set the image for this avatar. Will be used to create a round version of this avatar.
*
* @param resId The image's resource id.
*/
@SuppressLint("NewApi")
public void setAvatar(@DrawableRes int resId) {
if (ApiLevelHelper.isAtLeast(Build.VERSION_CODES.LOLLIPOP)) {
setClipToOutline(true);
setImageResource(resId);
} else {
setAvatarPreLollipop(resId);
}
}
private void setAvatarPreLollipop(@DrawableRes int resId) {
Drawable drawable = ResourcesCompat.getDrawable(getResources(), resId,
getContext().getTheme());
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
@SuppressWarnings("ConstantConditions")
RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(getResources(),
bitmapDrawable.getBitmap());
roundedDrawable.setCircular(true);
setImageDrawable(roundedDrawable);
}
@Override
protected void onDraw(@NonNull Canvas canvas) {
super.onDraw(canvas);
if (mChecked) {
Drawable border = ContextCompat.getDrawable(getContext(), R.drawable.selector_avatar);
border.setBounds(0, 0, getWidth(), getHeight());
border.draw(canvas);
}
}
@Override
@SuppressLint("NewApi")
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (ApiLevelHelper.isLowerThan(Build.VERSION_CODES.LOLLIPOP)) {
return;
}
if (w > 0 && h > 0) {
setOutlineProvider(new RoundOutlineProvider(Math.min(w, h)));
}
}
}
资源文件selecter_avatar.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<stroke
android:width="@dimen/stroke_width_avatar"
android:color="@color/topeka_primary" />
<solid android:color="@android:color/transparent" />
</shape>
分为:Lollipop和pre Lollipop这个是用一个小工具类实现api的:helper/ApiLevelHelper.java
/**
* Encapsulates checking api levels.
*/
public class ApiLevelHelper {
private ApiLevelHelper() {
//no instance
}
/**
* Checks if the current api level is at least the provided value.
*
* @param apiLevel One of the values within {@link Build.VERSION_CODES}.
* @return <code>true</code> if the calling version is at least <code>apiLevel</code>.
* Else <code>false</code> is returned.
*/
public static boolean isAtLeast(int apiLevel) {
return Build.VERSION.SDK_INT >= apiLevel;
}
/**
* Checks if the current api level is at lower than the provided value.
*
* @param apiLevel One of the values within {@link Build.VERSION_CODES}.
* @return <code>true</code> if the calling version is lower than <code>apiLevel</code>.
* Else <code>false</code> is returned.
*/
public static boolean isLowerThan(int apiLevel) {
return Build.VERSION.SDK_INT < apiLevel;
}
}
现在分析过程:
用isChecked();来标记是否画圆弧.
invalidate()
是用来刷新View的,必须是在UI线程中进行工作。比如在修改某个view的显示时,调用invalidate()才能看到重新绘制的界面。invalidate()的调用是把之前的旧的view从主UI线程队列中pop掉。
invalidate()后系统会自动调用view的 onDraw()方法,(为裁减好的图像装一个蓝色的外环)
这里用到 Android L的 Clipping Views(裁剪视图)和自定义图轮廓
只有几句代码:
setClipToOutline(true);
setImageResource(resId);
…
setOutlineProvider(new RoundOutlineProvider(Math.min(w, h)));
再跳到自定义widget/outlineprovider/RoundOutlineProvider.java
/**
* Creates round outlines for views.
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class RoundOutlineProvider extends ViewOutlineProvider {
private final int mSize;
public RoundOutlineProvider(int size) {
if (0 > size) {
throw new IllegalArgumentException("size needs to be > 0. Actually was " + size);
}
mSize = size;
}
@Override
public final void getOutline(View view, Outline outline) {
outline.setOval(0, 0, mSize, mSize);
}
}
典型的自定义视图轮廓:
在你的代码中自定义视图的轮廓:
1. 继承ViewOutlineProvider类
2. 重写getOutline() getOutline()方法
3. 使用View.setOutlineProvider()方法分配新的轮廓给你的视图
注意
- ContextCompat.getDrawable(getContext(), R.drawable.selector_avatar);
ResourcesCompat.getDrawable(getResources(), resId,
getContext().getTheme());
直接调用文件好么?根本不是什么构造函数的时候传context
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
BitmapDrawable是什么?
点击进源码:A Drawable that wraps a bitmap and can be tiled, stretched, or aligned. You can create a
BitmapDrawable from a file path, an input stream, through XML inflation, or from a object.
功能:显示缩略图,大小为40*40
//通过openRawResource获取一个inputStream对象
InputStream inputStream = getResources().openRawResource(R.drawable.test);
//通过一个InputStream创建一个BitmapDrawable对象
BitmapDrawable drawable = new BitmapDrawable(inputStream);
//通过BitmapDrawable对象获得Bitmap对象
Bitmap bitmap = drawable.getBitmap();
//利用Bitmap对象创建缩略图
bitmap = ThumbnailUtils.extractThumbnail(bitmap, 40, 40);
//imageView 显示缩略图的ImageView
imageView.setImageBitmap(bitmap);
//功能:image2从image1中截取120*120大小后显示,截取起始坐标为(x,y)
BitmapDrawable bitmapDrawable = (BitmapDrawable) image1.getDrawable();
//获取第一个图片显示框中的位图
Bitmap bitmap = bitmapDrawable.getBitmap();
//显示图片的指定区域
image2.setImageBitmap(Bitmap.createBitmap(bitmap, x, y, 120, 120));
image2.setAlpha(alpha);
- RoundedBitmapDrawable —实现圆角和圆形
但是在I/O大会之后,Google发布了新的Support lib,其中有一个是RoundedBitmapDrawable类,通过这个类可以很容易实现圆角和圆形图片。
1.首先需要添加support-v4依赖
在build.gralde的dependencies中添加下面代码:
dependencies {
//...其他依赖
compile 'com.android.support:support-v4:21.+'
compile 'com.android.support:appcompat-v7:21.+'
compile 'com.android.support:support-v4:21.+'
}
2.写代码
stackoverflow/how-to-use-roundedbitmapdrawable
关键用法:
圆形图:
RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(getResources(),
bitmapDrawable.getBitmap());
roundedDrawable.setCircular(true);
圆角图
RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(getResources(),
bitmapDrawable.getBitmap());
roundedDrawable.setCircular(true);