自定義圓形頭像CircleImageView

  圓形頭像很常用功能,於是想自己寫個自定義的圓形的view。搜索了一下,android中可以通過BitmapShader實現這個效果。

這裏寫圖片描述

  BitmapShader是Shader的子類,可以通過Paint.setShader(Shader shader)進行設置、

  這裏我們只關注BitmapShader,構造方法:

  bitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);

  參數1:bitmap

  參數2,參數3:TileMode;

  TileMode的取值有三種:

  CLAMP 拉伸

  REPEAT 重複

  MIRROR 鏡像

  如果大家給電腦屏幕設置屏保的時候,如果圖片太小,可以選擇重複、拉伸、鏡像;

  重複:就是橫向、縱向不斷重複這個bitmap

  鏡像:橫向不斷翻轉重複,縱向不斷翻轉重複;

  拉伸:這個和電腦屏保的模式應該有些不同,這個拉伸的是圖片最後的那一個像素;橫向的最後一個橫行像素,不斷的重複,縱項的那一列像素,不斷的重複;

首先現在values下新建attrs.xml,自定義屬性。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CircleImageView">
        <attr name="mborder_color" format="color"></attr>
        <attr name="mborder_width" format="dimension"></attr>
        <attr name="msrc" format="reference"></attr>
    </declare-styleable>
</resources>

CircleImageView.java

package com.sy.callme.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;

import com.sy.callme.R;

/**
 * Created by SY on 2016/5/16.
 */
public class CircleImageView extends View {
    private Bitmap bitmap;
    private int borderWidth;
    private Drawable drawable;
    private int borderColor;
    private int width;
    private int height;
    private Bitmap src;
    private BitmapShader shader;
    private Paint paint;
    private int radius;
    private int circleX;
    private int circleY;
    private Paint borderPaint;


    public CircleImageView(Context context) {
        super(context);
    }

    public CircleImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //獲取自定義屬性
        TypedArray type = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
        borderColor = type.getColor(R.styleable.CircleImageView_mborder_color, 0);
        borderWidth = type.getDimensionPixelSize(R.styleable.CircleImageView_mborder_width, 2);
        drawable = type.getDrawable(R.styleable.CircleImageView_msrc);
        //轉換爲bitmap
        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
        bitmap = bitmapDrawable.getBitmap();

    }

    private int measureHeight(int heightMeasureSpec) {
        int size = MeasureSpec.getSize(heightMeasureSpec);
        int sizeMode = MeasureSpec.getMode(heightMeasureSpec);
        int result = 0;
        if (sizeMode == MeasureSpec.EXACTLY) {
            //如果是精確尺寸就直接返回結果
            result = size;
        } else {
            //不是就尺寸設置最大爲200
            result = 200;
            if (sizeMode == MeasureSpec.AT_MOST) {
                //如果是最大尺寸就返回實際尺寸和最大尺寸之中較小的
                result = Math.min(result, size);
            }
        }
        return result;
    }

    private int measureWidth(int widthMeasureSpec) {
        int size = MeasureSpec.getSize(widthMeasureSpec);
        int sizeMode = MeasureSpec.getMode(widthMeasureSpec);
        int result = 0;
        if (sizeMode == MeasureSpec.EXACTLY) {
            //如果是精確尺寸就直接返回結果
            result = size;
        } else {
            //如果是精確尺寸就直接返回結果
            result = 200;
            if (sizeMode == MeasureSpec.AT_MOST) {
                //如果是最大尺寸就返回實際尺寸和最大尺寸之中較小的
                result = Math.min(result, size);
            }
        }
        return result;
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = measureWidth(widthMeasureSpec);
        height = measureHeight(heightMeasureSpec);
        width = height = Math.min(width, height);
        initView();//初始化畫筆參數
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(circleX, circleY, radius, paint);
        canvas.drawCircle(circleX, circleY, radius, borderPaint);
    }

    private void initView() {

        src = Bitmap.createScaledBitmap(bitmap, width, height, true);
        shader = new BitmapShader(src, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        paint = new Paint();
        paint.setShader(shader);//設置shader
        radius = (width - borderWidth * 2) / 2;
        circleX = (width) / 2;
        circleY = (height) / 2;

        borderPaint = new Paint();
        borderPaint.setStyle(Paint.Style.STROKE);
        borderPaint.setStrokeWidth(borderWidth);
        borderPaint.setColor(borderColor);
        borderPaint.setStrokeJoin(Paint.Join.ROUND);//接合處的圓滑
        borderPaint.setStrokeCap(Paint.Cap.ROUND);//圓角的筆觸
    }

    public void setImageResoure(Drawable drawable) {
        //轉換爲bitmap
        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
        bitmap = bitmapDrawable.getBitmap();
        shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        paint = new Paint();
        paint.setShader(shader);
        requestLayout();
        invalidate();
    }
}

  首先獲取自定義屬性的值,然後在onMeasure方法裏獲得控件寬高,initView方法裏設置畫筆的參數,創建BitmapShader並給paint設置shader。最後在onDraw方法裏繪製就可以了。具體使用:
  

<com.sy.callme.view.CircleImageView
        android:id="@+id/c_image"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_marginTop="20dp"
        android:layout_gravity="center_horizontal"
        app:mborder_color="#ff7700"
        app:mborder_width="3dp"
        app:msrc="@mipmap/touxiang" />

記得使用自定義view的自定義屬性需要在佈局文件中引入xmlns:app="http://schemas.android.com/apk/res-auto"

參考資料:Android自定義屬性時TypedArray的使用方法
     Android學習筆記進階15之Shader渲染
      Android學習筆記進階16之BitmapShader
      詳解Paint的各種set方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章