1. 程式人生 > >開發懸浮球SDK之自定義view 下篇 — 裁剪圓形(以及其他形狀)背景圖片並設定文字

開發懸浮球SDK之自定義view 下篇 — 裁剪圓形(以及其他形狀)背景圖片並設定文字

本文主要是講自定義view中剪下圓形背景圖並設定文字的實現過程和其中遇到的問題及相關技術介紹。是應領導要求在上一懸浮球介面(水波紋效果:點選開啟連結)之後更改的圓形背景圖:

 剪下後 ->   

起初只是簡單的背景圖片,但用於沒有美工,自己學習PS後P出的圖片又不太理想,所以只能自己來裁剪出圓形圖片。

主要流程是:

1.讀取本地圖片為bitmap,關鍵方法:BitmapDrawable drawable = (BitmapDrawable) ContextCompat.getDrawable(context, R.drawable.background);

Bitmap bmp =  drawable.getBitmap().copy(Bitmap.Config.ARGB_8888,true);。

2.將圖片裁剪成正方形,並且在圖片中間裁剪    方法: Bitmap.createBitmap(bitmap,裁剪的橫座標初始位置,裁剪的縱座標初始位置,原始正方形邊長,原始正方形邊長);。

3.將裁剪後的正方形圖片拉伸,將其拉伸為想要的正方形邊長長度。

4.將最終的正方形圖片裁剪為圓形,通過paint.setXfermode();方法,至於引數設定可以參考水波紋效果那篇文章下方的連結,您可以學習這個方法的作用及相關引數的作用。


程式碼實現:

public class View4 extends View {
    private static final String TAG = "FlowBallView";
    private String TEXT = "loading...";

    public int width = 150;
    public int height = 150;
    private Context context;
    private Paint paint;
    private Paint paint1;
    private int radius;
    private  int i = 0;
    public View4(Context context) {
        this(context, null);
    }
    public View4(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public View4(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
    }
    private void init() {
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);
      //  paint.setTypeface(Typeface.DEFAULT_BOLD);//文字加粗
        Log.d("view", "onDraw: 執行0");
        paint1 = new Paint();
        paint1.setAntiAlias(true);
        paint1.setColor(Color.RED);
       // paint1.setTypeface(Typeface.DEFAULT_BOLD);
        radius = width / 2;
    }
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        init();
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        this.measure(0, 0);
        BitmapDrawable drawable = (BitmapDrawable) ContextCompat.getDrawable(context, R.drawable.background);
        Bitmap bmp =  drawable.getBitmap().copy(Bitmap.Config.ARGB_8888,true);
        Bitmap roundBitmap = getRoundBitmap(bmp, radius);// 擷取後的圓形圖片
        canvas.drawBitmap(roundBitmap,0, 0,null);
        paint.setTextSize(width/8);
        paint1.setTextSize(width/6);
        String text = "剩餘流量";
        float textWidth = paint.measureText(text); // 這裡是需要關注的,文字寬度和高度的測量
        Paint.FontMetrics metrics = paint.getFontMetrics(); // 這個類是文字高度測量必須使用的類,因為文字的高度不單單是其自身高,類似拼音的四線普
        float baseLine = height / 2-(metrics.ascent + metrics.descent) - height/5; // 這裡baseLine是基線,我之所以設定 (height/2- height/5)就是為了讓文字根據圓形背景圖高度而放置到其相應位置 
        float textWidth1 = paint1.measureText(TEXT);
        Paint.FontMetrics metrics1 = paint1.getFontMetrics();
        float baseLine1 = height / 2-(metrics1.ascent + metrics1.descent) ;
        canvas.drawText(text,width / 2-textWidth/2,baseLine,paint);
        canvas.drawText(TEXT,width / 2-textWidth1/2,baseLine1,paint1);
    }
    /**
     * 獲取裁剪後的圓形圖片
     * @param radius 半徑
     */
    public Bitmap getRoundBitmap(Bitmap bmp, int radius) {
        Bitmap bitmap ;
        Bitmap circleBitmap ;

        int circle = radius*2;//繪製圓形直徑長的正方形;
        int scaler;//正方形邊長
        int x = 0,y = 0;
        int circleWidth = bmp.getWidth();
        int circleHeight = bmp.getHeight();
        //先裁決出正方形圖片
        if(circleWidth>circleHeight){
            scaler = circleHeight;
            x = (circleWidth - circleHeight) / 2;// Bitmap.createBitmap 是用來裁剪圖片的方法, /2 是為了保證裁剪的位置是圖片中央
            circleBitmap = Bitmap.createBitmap(bmp,x,y,scaler,scaler);
        }else if (circleWidth<circleHeight){
            scaler = circleWidth;
            y =( circleHeight - circleWidth ) / 2;
            circleBitmap = Bitmap.createBitmap(bmp,x,y,scaler,scaler);
        }else{
            circleBitmap = bmp;
        }
        if(circle!=circleBitmap.getWidth()||circle!=circleBitmap.getHeight()){
            //設定正方形邊長
            bitmap = Bitmap.createScaledBitmap(circleBitmap,circle,circle,true);//Bitma.createScaledBitmap是拉伸圖片的方法,引數2,3 是寬和長,true 是保證圖片不失真
        }else{
            bitmap = circleBitmap;
        }
       Bitmap outPut  = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);//設定格式
        //接下來開始畫圓
        Log.d("view", "圓");

        Paint paint = new Paint();

        paint.setDither(true);//圖片不抖動
        paint.setAntiAlias(true);//抗鋸齒

        paint.setARGB(255,255,255,255);//
        //這步可以不寫,但您如果呼叫了setARGB方法,那麼您就必須將第一個引數設定為255或者呼叫下一步接著aint.setColor()方法以此來保證圖片的透明度為"不透明",能清晰看到;當然您要是想要背景圖片透明那麼就可以設定此方法第一個引數
       
        Rect rect = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
        Canvas canvas = new Canvas(outPut);
        canvas.drawCircle(bitmap.getWidth() / 2,bitmap.getHeight() / 2,bitmap.getWidth()/2,paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap,rect,rect,paint);
        return outPut;
    }
}

有關Paint.FontMetrics和text文字的位置設定,這裡有詳細介紹,您點選連結就行: 文字測量詳解

paint.setARGB(0,0,0,0); 

這塊可以這麼寫,也可以將其去掉  原因是 paint.setARGB()方法相當於paint.setAlpha(透明度方法)和paint.setColor(畫筆顏色設定)兩個方法結合  ,ARGB4個引數 ,引數1是透明度設定,234是顏色設定,檢視原始碼其內部呼叫了setColor方法。當您呼叫setARGB方法就需要將第一個引數傳值為255(這麼做相當於設定paint透明度為不透明,也就是保證畫筆畫出的圖片的透明度為不透明);

解釋:
paint.setARGB(a,r,g,b);  // 通過此方法您可以設定您的圖片或者您畫出的圖案的透明度,以此來達到您想要的效果;比如:背景圖片透明
a:透明度,取值範圍為0~255,數值越小越透明。
r:紅色的顏色值,取值範圍為0~255。
g:綠色的顏色值,取值範圍為0~255。
b:藍色的顏色值,取值範圍為0~255。

  下圖是對比效果:

這裡是paint.setARGB()方法的簡單介紹:http://book.51cto.com/art/201204/328260.htm


下面是繪製圓形的另一種方式,流程一樣,但是畫出圓的方式不同 : 

  Rect rect = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
        RectF rectF = new RectF(0,0,bitmap.getWidth(),bitmap.getHeight());
        //正方形圓角邊
        Canvas canvas = new Canvas(outPut);
        canvas.drawARGB(0,0,0,0);
        //canvas.drawCircle(bitmap.getWidth() / 2,bitmap.getHeight() / 2,bitmap.getWidth()/2,paint);// 這是之前畫圓的方式
       // canvas.drawRoundRect(rectF,20 ,20 ,paint);
        canvas.drawOval(rectF,paint);  // 這裡是另一種畫圓的方式通過傳入正方形,通過drawOval方法切出圓形
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap,rect,rect,paint);
        return outPut;

下面是圖片剪下的延伸,不只是剪出圓形圖,還可以是更多的圖形,但大致流程和原理都是類似的:

圓角正方形圖片(想要圓角矩形,那麼可以將剪下圓形的流程去掉正方形的剪下這步):


程式碼相對於圓形圖片的剪下只是更改了canvas剪下的圖形,想切什麼圖形那麼就設定什麼圖形。

下面是更改的程式碼,其餘未變

        Rect rect = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
        RectF rectF = new RectF(0,0,bitmap.getWidth(),bitmap.getHeight());   //圓形矩形必須設定的例項物件,RectF ,4個引數: 分別是這個矩形四個邊的位置
        //正方形圓角邊
        Canvas canvas = new Canvas(outPut);
        canvas.drawARGB(0,0,0,0);
        //canvas.drawCircle(bitmap.getWidth() / 2,bitmap.getHeight() / 2,bitmap.getWidth()/2,paint);   // 這裡是上方剪下圓形而設定的圓形圖。也就是通過canvas設定這個圖形樣式而實現的圖片的剪下
        canvas.drawRoundRect(rectF,20 ,20 ,paint);   // 將剪下圓形圖改為設定圓角矩形 4個引數: 1.矩形rectF 2.rx 圓角X方向半徑 3.圓角Y方向半徑 4.paint

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap,rect,rect,paint);
        return outPut;

以後您想要再裁剪出什麼圖形,只需按這種方式通過canvas繪製圖形結合paint的setXfermode()就可以裁剪出您想要的圖片樣式。