效果截圖
image.png
實(shí)現(xiàn)原理
對(duì)于圓形頭像的實(shí)現(xiàn)撑帖,其實(shí)就是對(duì)方形圖像做某些處理,以達(dá)到圓形頭像的效果。一般我們會(huì)通過(guò)Canvas和Paint結(jié)合來(lái)實(shí)現(xiàn)這種效果镶苞。
自定義View來(lái)實(shí)現(xiàn)
因?yàn)閳A形頭像是視覺(jué)方面的需求陕靠,一般我們會(huì)考慮能否從自定義View的角度來(lái)解決問(wèn)題迂尝。自定義的核心有兩點(diǎn):視覺(jué)和交互。視覺(jué)由onMeasure
剪芥、onLayout
垄开、onDraw
這三個(gè)方法來(lái)完成,而交互則是由dispatchTouchEvent
税肪、onInterceptTouchEvent
溉躲、onTouchEvent
等這幾個(gè)方法來(lái)控制榜田,只要處理好這幾個(gè)方法,就能實(shí)現(xiàn)形態(tài)各異的自定義View了锻梳。
方式一 BitmapShader
package com.yds.myapplication;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatImageView;
/**
* Created by yds
* on 2020/3/10.
*/
public class CircleImageView extends AppCompatImageView {
private int mSize;
private Paint mPaint;
public CircleImageView(Context context) {
this(context,null);
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CircleImageView(Context context,AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
mPaint = new Paint();
mPaint.setDither(true);
mPaint.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
mSize = Math.min(width,height); //取寬高的最小值
setMeasuredDimension(mSize,mSize); //設(shè)置CircleImageView為等寬高
}
@Override
protected void onDraw(Canvas canvas) {
//獲取sourceBitmap箭券,即通過(guò)xml或者java設(shè)置進(jìn)來(lái)的圖片
Drawable drawable = getDrawable();
if (drawable == null) return;
Bitmap sourceBitmap = ((BitmapDrawable)getDrawable()).getBitmap();
if (sourceBitmap != null){
//對(duì)圖片進(jìn)行縮放,以適應(yīng)控件的大小
Bitmap bitmap = resizeBitmap(sourceBitmap,getWidth(),getHeight());
drawCircleBitmapByShader(canvas,bitmap); //利用BitmapShader實(shí)現(xiàn)
}
}
private Bitmap resizeBitmap(Bitmap sourceBitmap,int dstWidth,int dstHeight){
int width = sourceBitmap.getWidth();
int height = sourceBitmap.getHeight();
float widthScale = ((float)dstWidth) / width;
float heightScale = ((float)dstHeight) / height;
//取最大縮放比
float scale = Math.max(widthScale,heightScale);
Matrix matrix = new Matrix();
matrix.postScale(scale,scale);
return Bitmap.createBitmap(sourceBitmap,0,0,width,height,matrix,true);
}
private void drawCircleBitmapByShader(Canvas canvas,Bitmap bitmap){
BitmapShader shader = new BitmapShader(bitmap,BitmapShader.TileMode.CLAMP,BitmapShader.TileMode.CLAMP);
mPaint.setShader(shader);
canvas.drawCircle(mSize / 2,mSize /2 ,mSize / 2,mPaint);
}
}
方式二 PorterDuffXfermode
package com.yds.myapplication;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatImageView;
/**
* Created by yds
* on 2020/3/10.
*/
public class CircleImageViewPD extends AppCompatImageView {
private int mWidth;
private int mHeight;
private Paint mPaint;
private Bitmap CircleBitmap;
public CircleImageViewPD(Context context) {
super(context);
}
public CircleImageViewPD(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleImageViewPD(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void ImgCircle(){
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setColor(Color.GRAY);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.FILL);
CircleBitmap = Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(CircleBitmap);
canvas.drawCircle(mWidth/2,mHeight/2,mWidth/2,paint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setFilterBitmap(true);
ImgCircle();
}
@Override
protected void onDraw(Canvas canvas) {
int count = canvas.saveLayerAlpha(0, 0, mWidth, mHeight, 250, Canvas.ALL_SAVE_FLAG);
super.onDraw(canvas);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(CircleBitmap,0,0, mPaint);
canvas.restoreToCount(count);
}
}
方式三 繼承自Drawable
package com.yds.myapplication;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
/**
* Created by yds
* on 2020/3/10.
*/
public class CircleImageViewDrawable extends Drawable {
private Paint mPaint;
private BitmapShader mBitmapShader;
private int mSize;
private int mRadius;
public CircleImageViewDrawable(Bitmap bitmap){
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
mPaint.setShader(mBitmapShader);
mSize = Math.min(bitmap.getWidth(),bitmap.getHeight());
mRadius = mSize/2;
}
@Override
public void draw(Canvas canvas) {
canvas.drawCircle(mRadius,mRadius,mRadius,mPaint);
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public int getIntrinsicHeight() {
return mSize;
}
@Override
public int getIntrinsicWidth() {
return mSize;
}
}
使用
public class MainActivity extends AppCompatActivity {
private ImageView mImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = findViewById(R.id.img);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.img);
Drawable drawable = new CircleImageViewDrawable(bitmap);
mImageView.setImageDrawable(drawable);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<ImageView
android:id="@+id/img"
android:layout_width="120dp"
android:layout_height="120dp" />
<com.yds.myapplication.CircleImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@drawable/img"/>
<com.yds.myapplication.CircleImageViewPD
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@drawable/img"/>
</LinearLayout>