前回android5.0のライブラリを導入したので、画面も5.0らしくモダンな画面に変更していきます。
今回はありがちなImageViewでのユーザーアイコンの表示を円形に表示させます。
変更前
変更後
この機能はandroid5.0でなくても導入可能なので、ぜひ導入してみてください。
環境
- android:minSdkVersion="14"
- android:targetSdkVersion="21"
- andoid studio 0.8.9
ImageViewを継承したBezelImageViewというコードを作成します。googleのコードを参考にしてます。
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* An {@link android.widget.ImageView} that draws its contents inside a mask and draws a border
* drawable on top. This is useful for applying a beveled look to image contents, but is also
* flexible enough for use with other desired aesthetics.
*/
public class BezelImageView extends ImageView {
private Paint mBlackPaint;
private Paint mMaskedPaint;
private Rect mBounds;
private RectF mBoundsF;
private Drawable mBorderDrawable;
private Drawable mMaskDrawable;
private ColorMatrixColorFilter mDesaturateColorFilter;
private boolean mDesaturateOnPress = false;
private boolean mCacheValid = false;
private Bitmap mCacheBitmap;
private int mCachedWidth;
private int mCachedHeight;
public BezelImageView(Context context) {
this(context, null);
}
public BezelImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BezelImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// Attribute initialization
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BezelImageView,
defStyle, 0);
mMaskDrawable = a.getDrawable(R.styleable.BezelImageView_maskDrawable);
if (mMaskDrawable != null) {
mMaskDrawable.setCallback(this);
}
mBorderDrawable = a.getDrawable(R.styleable.BezelImageView_borderDrawable);
if (mBorderDrawable != null) {
mBorderDrawable.setCallback(this);
}
mDesaturateOnPress = a.getBoolean(R.styleable.BezelImageView_desaturateOnPress,
mDesaturateOnPress);
a.recycle();
// Other initialization
mBlackPaint = new Paint();
mBlackPaint.setColor(0xff000000);
mMaskedPaint = new Paint();
mMaskedPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
// Always want a cache allocated.
mCacheBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
if (mDesaturateOnPress) {
// Create a desaturate color filter for pressed state.
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
mDesaturateColorFilter = new ColorMatrixColorFilter(cm);
}
}
@Override
protected boolean setFrame(int l, int t, int r, int b) {
final boolean changed = super.setFrame(l, t, r, b);
mBounds = new Rect(0, 0, r - l, b - t);
mBoundsF = new RectF(mBounds);
if (mBorderDrawable != null) {
mBorderDrawable.setBounds(mBounds);
}
if (mMaskDrawable != null) {
mMaskDrawable.setBounds(mBounds);
}
if (changed) {
mCacheValid = false;
}
return changed;
}
@Override
protected void onDraw(Canvas canvas) {
if (mBounds == null) {
return;
}
int width = mBounds.width();
int height = mBounds.height();
if (width == 0 || height == 0) {
return;
}
if (!mCacheValid || width != mCachedWidth || height != mCachedHeight) {
// Need to redraw the cache
if (width == mCachedWidth && height == mCachedHeight) {
// Have a correct-sized bitmap cache already allocated. Just erase it.
mCacheBitmap.eraseColor(0);
} else {
// Allocate a new bitmap with the correct dimensions.
mCacheBitmap.recycle();
//noinspection AndroidLintDrawAllocation
mCacheBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCachedWidth = width;
mCachedHeight = height;
}
Canvas cacheCanvas = new Canvas(mCacheBitmap);
if (mMaskDrawable != null) {
int sc = cacheCanvas.save();
mMaskDrawable.draw(cacheCanvas);
mMaskedPaint.setColorFilter((mDesaturateOnPress && isPressed())
? mDesaturateColorFilter : null);
cacheCanvas.saveLayer(mBoundsF, mMaskedPaint,
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG);
super.onDraw(cacheCanvas);
cacheCanvas.restoreToCount(sc);
} else if (mDesaturateOnPress && isPressed()) {
int sc = cacheCanvas.save();
cacheCanvas.drawRect(0, 0, mCachedWidth, mCachedHeight, mBlackPaint);
mMaskedPaint.setColorFilter(mDesaturateColorFilter);
cacheCanvas.saveLayer(mBoundsF, mMaskedPaint,
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG);
super.onDraw(cacheCanvas);
cacheCanvas.restoreToCount(sc);
} else {
super.onDraw(cacheCanvas);
}
if (mBorderDrawable != null) {
mBorderDrawable.draw(cacheCanvas);
}
}
// Draw from cache
canvas.drawBitmap(mCacheBitmap, mBounds.left, mBounds.top, null);
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if (mBorderDrawable != null && mBorderDrawable.isStateful()) {
mBorderDrawable.setState(getDrawableState());
}
if (mMaskDrawable != null && mMaskDrawable.isStateful()) {
mMaskDrawable.setState(getDrawableState());
}
if (isDuplicateParentStateEnabled()) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
@Override
public void invalidateDrawable(Drawable who) {
if (who == mBorderDrawable || who == mMaskDrawable) {
invalidate();
} else {
super.invalidateDrawable(who);
}
}
@Override
protected boolean verifyDrawable(Drawable who) {
return who == mBorderDrawable || who == mMaskDrawable || super.verifyDrawable(who);
}
}
attrs.xml
<resources>
<declare-styleable name="BezelImageView">
<attr name="maskDrawable" format="reference" />
<attr name="borderDrawable" format="reference" />
<attr name="desaturateOnPress" format="boolean" />
</declare-styleable>
</resources>
dimens.xml
<dimen name="expert_icon_size">60dp</dimen>
circle_mask.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#000" />
</shape>
上記で完成。あとはlayoutのxmlに記載するだけです。
<com.tset.testapp.ui.widget.BezelImageView
android:id="@+id/image"
app:maskDrawable="@drawable/circle_mask"
android:layout_width="@dimen/expert_icon_size"
android:layout_height="@dimen/expert_icon_size"
android:scaleType="centerCrop"
android:layout_marginRight="10dp" />
あとはコンパイルして表示すれば上記の画像のように円形の画像が表示されます。
参考サイト
この記事がお役にたちましたらシェアをお願いします