View之Canvas,Paint,Matrix,RectF等介紹

目錄介紹

  • 1.Paint畫筆介紹
    • 1.1 圖形繪製
    • 1.2 文本繪製
  • 2.Canvas畫布介紹
    • 2.1 設置屬性
    • 2.2 畫圖【重點】
    • 2.3 Canvas對象的獲取方式
    • 2.4 Canvas的做用
    • 2.5 Canvas繪製圓和橢圓
    • 2.6 Canvas繪製矩形、圓角矩形
    • 2.7 Canvas繪製文字
    • 2.8 Canvas繪製弧形、封閉弧形
    • 2.9 Canvas繪製Path路徑
  • 3.Matrix變換矩陣介紹
    • 3.1 translate平移
    • 3.2 rorate旋轉
    • 3.3 scale縮放
    • 3.4 skew扭曲
  • 4.RectF介紹
    • 4.1 Rect簡單屬性
    • 4.2 Rect父類的實現
    • 4.3 Rect經常使用的一些方法
  • 5.關於使用到這幾個屬性的自定義View
    • 5.0 知道了這幾個,須要練手寫下案例
    • 5.1 自定義輪播圖圓點
    • 5.2 自定義圓環百分比進度條

好消息

1.Paint畫筆介紹

  • Paint即畫筆,在繪圖過程當中起到了極其重要的做用,畫筆主要保存了顏色, 樣式等繪製信息,指定了如何繪製文本和圖形,畫筆對象有不少設置方法,大致上能夠分爲兩類,一類與圖形繪製相關,一類與文本繪製相關。

1.1 圖形繪製

  • 經常使用的方法有這些
    * setARGB(int a,int r,int g,int b); 
    設置繪製的顏色,a表明透明度,r,g,b表明顏色值。 
    * setAlpha(int a); 
    設置繪製圖形的透明度。
    * setColor(int color); 
    設置繪製的顏色,使用顏色值來表示,該顏色值包括透明度和RGB顏色。 
    * setAntiAlias(boolean aa);
    設置是否使用抗鋸齒功能,會消耗較大資源,繪製圖形速度會變慢。 
    * setDither(boolean dither); 
    設定是否使用圖像抖動處理,會使繪製出來的圖片顏色更加平滑和飽滿,圖像更加清晰 
    * setFilterBitmap(boolean filter); 
    若是該項設置爲true,則圖像在動畫進行中會濾掉對Bitmap圖像的優化操做,加快顯示速度,本設置項依賴於dither和xfermode的設置 
    * setMaskFilter(MaskFilter maskfilter); 
    設置MaskFilter,能夠用不一樣的MaskFilter實現濾鏡的效果,如濾化,立體等 
    * setColorFilter(ColorFilter colorfilter); 
    設置顏色過濾器,能夠在繪製顏色時實現不用顏色的變換效果 
    * setPathEffect(PathEffect effect); 
    設置繪製路徑的效果,如點畫線等 
    * setShader(Shader shader); 
    設置圖像效果,使用Shader能夠繪製出各類漸變效果 
    * setShadowLayer(float radius ,float dx,float dy,int color); 
    在圖形下面設置陰影層,產生陰影效果,radius爲陰影的角度,dx和dy爲陰影在x軸和y軸上的距離,color爲陰影的顏色 
    * setStyle(Paint.Style style); 
    設置畫筆的樣式,爲FILL,FILL_AND_STROKE,或STROKE 
    * setStrokeCap(Paint.Cap cap); 
    當畫筆樣式爲STROKE或FILL_AND_STROKE時,設置筆刷的圖形樣式,如圓形樣式  Cap.ROUND,或方形樣式Cap.SQUARE 
    * setSrokeJoin(Paint.Join join); 
    設置繪製時各圖形的結合方式,如平滑效果等 
    * setStrokeWidth(float width); 
    當畫筆樣式爲STROKE或FILL_AND_STROKE時,設置筆刷的粗細度 
    * setXfermode(Xfermode xfermode); 
    設置圖形重疊時的處理方式,如合併,取交集或並集,常常用來製做橡皮的擦除效果

1.2 文本繪製

  • 經常使用的方法有這些
    * setFakeBoldText(boolean fakeBoldText); 
    模擬實現粗體文字,設置在小字體上效果會很是差 
    * setSubpixelText(boolean subpixelText); 
    設置該項爲true,將有助於文本在LCD屏幕上的顯示效果 
    * setTextAlign(Paint.Align align); 
    設置繪製文字的對齊方向 
    * setTextScaleX(float scaleX); 
    設置繪製文字x軸的縮放比例,能夠實現文字的拉伸的效果 
    * setTextSize(float textSize); 
    設置繪製文字的字號大小 
    * setTextSkewX(float skewX); 
    設置斜體文字,skewX爲傾斜弧度 
    * setTypeface(Typeface typeface); 
    設置Typeface對象,即字體風格,包括粗體,斜體以及襯線體,非襯線體等 
    * setUnderlineText(boolean underlineText); 
    設置帶有下劃線的文字效果 
    * setStrikeThruText(boolean strikeThruText); 
    設置帶有刪除線的效果

2.Canvas畫布介紹

  • 當咱們調整好畫筆以後,如今須要繪製到畫布上,這就得用Canvas類了。在android中既然把Canvas當作畫布,那麼就能夠在畫布上繪製咱們想要的任何東西。除了在畫布上繪製以外,還須要設置一些關於畫布的屬性,好比,畫布的顏色、尺寸等。

2.1 設置屬性

  • 通常屬性有:
    * Canvas(Bitmap bitmap): 以bitmap對象建立一個畫布,則將內容都繪製在bitmap上,所以bitmap不得爲null。
    * Canvas(GL gl): 在繪製3D效果時使用,與OpenGL相關。
    * isOpaque(boolean isOpaque):檢測是否支持透明。
    * setViewport(int left, int top, int right, int bottom, int clipflag):  設置畫布中顯示窗口。
    * drawColor(int color): 設置Canvas的背景顏色。
    * setBitmap(Bitmap mBitmap):  設置具體畫布,畫的內容,保存爲一個Bitmap。
    * clipRect(float left, float top, float right, float bottom): 設置顯示區域,即設置裁剪區。
    * translate(float x, float  y): 平移畫布。
    * rotate(float degree, float px, float py):  旋轉畫布 。
    * skew(float sx, float sy):  設置偏移量。 
    * save(): 將Canvas當前狀態保存在堆棧,save以後能夠調用Canvas的平移、旋轉、錯切、剪裁等操做。
    * restore(): 恢復爲以前堆棧保存的Canvas狀態,防止save後對Canvas執行的操做對後續的繪製有影響。restore和save要配對使用,restore能夠比save少,但不能比save多,不然會引起error。save和restore之間,每每夾雜的是對Canvas的特殊操做。
    * save(int num):將Canvas當前狀態保存在堆棧,並予以編號int
    * restoreToCount(int num):恢復爲以前堆棧保存的編號爲int的Canvas狀態
    * concat(Matrix matrix):畫布關聯矩陣,畫出來的內容按矩陣改變,而不是畫布改變。
    * Drawable.draw(Canvas canvas):將Drawable畫到Canvas中
    注:這種方式畫Drawable怎麼設置透明度呢?((BitmapDrawable)Drawable).getPaint().setAlpha(mBgAlpha);

2.2 畫圖【重點】

  • 畫圖部分
    *  canvas.drawPaint(Paint paint)
    將畫筆設置的顏色和透明度鋪滿畫布
    * drawRect(RectF rect, Paint paint) 
    繪製矩形,參數一爲RectF一個區域 
    * drawRect(float left, float top, float right, float bottom, Paint paint)
    繪製矩形,left:矩形left的x座標,top:矩形top的y座標,right:矩形right的x座標,bottom:矩形bottom的y座標
    * drawRoundRect(RectF rect, float rx, float ry, Paint paint)
    繪製圓角矩形, rx:x方向的圓角半徑,ry:y方向的圓角半徑
    * drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint)        
    * drawPath(Path path, Paint paint) 
    繪製一個路徑,參數一爲Path路徑對象
    * drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)  
    貼圖,參數一就是咱們常規的Bitmap對象,參數二是源區域(這裏是bitmap),參數三是目標區域(應該在canvas的位置和大小),參數四是Paint畫刷對象,由於用到了縮放和拉伸的可能,當原始Rect不等於目標Rect時性能將會有大幅損失。
    * drawBitmap (Bitmap bitmap, float left, float top, Paint paint)
    * drawLine(float startX, float startY, float stopX, float stopY, Paintpaint)
    畫線,參數一塊兒始點的x軸位置,參數二起始點的y軸位置,參數三終點的x軸水平位置,參數四y軸垂直位置,最後一個參數爲Paint 畫刷對象。 
    * drawPoint(float x, float y, Paint paint) 
    畫點,參數一水平x軸,參數二垂直y軸,第三個參數爲Paint對象。
    * drawText(String text, float x, floaty, Paint paint)  
    渲染文本,Canvas類除了上面的還能夠描繪文字,參數一是String類型的文本,參數二文字左側到x軸距離,參數三文字BaseLine到y軸距離,參數四是Paint對象。
    * drawOval(RectF oval, Paint paint)
    繪製橢圓,參數一是掃描區域,參數二爲paint對象
    * drawOval(float left, float top, float right, float bottom, Paint paint)
    * drawCircle(float cx, float cy, float radius,Paint paint)
    繪製圓,參數一是中心點的x軸,參數二是中心點的y軸,參數三是半徑,參數四是paint對象;
    * drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
    畫弧,參數一是RectF對象,指定圓弧的外輪廓矩形區域,參數二是起始角(度)在電弧的開始,參數三掃描角(度)開始順時針測量的,參數四是若是這是真的話,包括橢圓中心的電弧,並關閉它,若是它是假這將是一個弧線,參數五是Paint對象;

2.3 Canvas對象的獲取方式

  • 2.3.1 Canvas對象的獲取方式有兩種:
    • 第一種經過重寫View.onDraw方法,View中的Canvas對象會被當作參數傳遞過來,操做這個Canvas,效果會直接反應在View中。
    • 第二種經過new建立一個Canvas對象
    • 代碼以下所示
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
    
    Canvas canvas = new Canvas();

2.4 Canvas的做用

  • Canvas能夠繪製的對象有:弧線(arcs)、填充顏色(argb和color)、Bitmap、圓(circle和oval)、點(point)、線(line)、矩形(Rect)、圖片(Picture)、圓角矩形(RoundRect)、文本(text)、頂點(Vertices)、路徑(path)。

2.5 Canvas繪製圓和橢圓

  • 繪製圓
    private Paint paint = new Paint();
    
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setAntiAlias(true);
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(200,200,100 , paint);
    }

2.6 Canvas繪製矩形、圓角矩形

  • 以下所示
  • image
    private Paint paint = new Paint();
    
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawRect(100, 100, 200, 200, paint);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            canvas.drawRoundRect(400, 100, 600, 300, 30, 30, paint);
        }
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(20);
        canvas.drawRect(100, 400, 300, 600, paint);
    }

2.7 Canvas繪製文字

  • Canvas繪製文字
  • image
    private Paint paint = new Paint();
    
    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);
        paint.setTextSize(100);
        canvas.drawText("瀟湘劍雨", 100, 100, paint);
    }

2.8 Canvas繪製弧形、封閉弧形

  • 繪製弧形、封閉弧形
  • image
    private Paint paint = new Paint();
    
    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);
        RectF rel = new RectF(50, 50, 150, 150);
        //實心圓弧
        canvas.drawArc(rel, 0, 135, false, paint);
        //實心圓弧 將圓心包含在內
        RectF rel2 = new RectF(50, 200, 150, 300);
        canvas.drawArc(rel2, 0, 135, true, paint);
        //設置空心Style
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(20);
        RectF rel3 = new RectF(50, 350, 150, 450);
        canvas.drawArc(rel3, 0, 270, false, paint);
        RectF rel4 = new RectF(50, 250, 150, 600);
        canvas.drawArc(rel4, 0, 270, true, paint);
    }

2.9 Canvas繪製Path路徑

  • Canvas繪製Path路徑
  • image
    private Paint paint = new Paint();
    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Path angle = new Path();
        angle.moveTo(250, 0);
        angle.lineTo(0, 500);
        angle.lineTo(100, 300);
        angle.lineTo(200, 350);
        angle.lineTo(500, 500);
        angle.close();
        canvas.drawPath(angle, paint);
    }

3.Matrix變換矩陣介紹【Canvas位置轉換】

  • 思考:若是要畫一個儀表盤(數字圍繞顯示在一個圓圈中),或者相似鐘錶指針樣的控件,如何實現?
  • Android還提供了一些對Canvas位置轉換的方法:rorate、scale、translate、skew(扭曲)等,並且它容許你經過得到它的轉換矩陣對象(getMatrix方法)直接操做它。這些操做就像是雖然你的筆仍是原來的地方畫,可是畫紙旋轉或者移動了,因此你畫的東西的方位就產生變化。爲了方便一些轉換操做,Canvas還提供了保存和回滾屬性的方法(save和restore),好比你能夠先保存目前畫紙的位置(save),而後旋轉90度,向下移動100像素後畫一些圖形,畫完後調用restore方法返回到剛纔保存的位置。

3.1 translate平移

3.2 rorate旋轉

  • rorate旋轉
  • image
    private Paint mPaint = new Paint();
    
    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.BLUE);
        mPaint.setColor(Color.RED);
        canvas.drawRect(new Rect(0, 0, 800, 800), mPaint);
        canvas.save();
        mPaint.setColor(Color.GREEN);
        canvas.rotate(45,400,400);
        canvas.drawRect(new Rect(0, 0, 800, 800), mPaint);
        canvas.restore();
    }
  • 源代碼有兩個可使用的方法:
    /**  
     * Preconcat the current matrix with the specified rotation.  
     * @param degrees The amount to rotate, in degrees  
     */  
    public native void rotate(float degrees);    
    /**  
     * Preconcat the current matrix with the specified rotation.   
     * @param degrees The amount to rotate, in degrees  
     * @param px The x-coord for the pivot point (unchanged by the rotation)  
     * @param py The y-coord for the pivot point (unchanged by the rotation)  
     */  
    public final void rotate(float degrees, float px, float py) {  
        translate(px, py);  
        rotate(degrees);  
        translate(-px, -py);  
    }

3.3 scale縮放

  • scale縮放
  • image
    private Paint mPaint = new Paint();
    
    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.YELLOW);
        mPaint.setColor(Color.RED);
        canvas.drawRect(new Rect(0, 0, 800, 800), mPaint);
        // 保存畫布狀態
        canvas.save();
        canvas.scale(0.5f, 0.5f);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(new Rect(0, 0, 800, 800), mPaint);
        // 畫布狀態回滾
        canvas.restore();
        canvas.scale(0.5f, 0.5f, 400, 400);
        mPaint.setColor(Color.BLUE);
        canvas.drawRect(new Rect(0, 0, 800, 800), mPaint);
    }
  • 源碼以下所示
    /**  
     * Preconcat the current matrix with the specified scale.   
     * @param sx The amount to scale in X  
     * @param sy The amount to scale in Y  
     */  
    public native void scale(float sx, float sy);  
    
    /**  
     * Preconcat the current matrix with the specified scale.  
     * @param sx The amount to scale in X  
     * @param sy The amount to scale in Y  
     * @param px The x-coord for the pivot point (unchanged by the scale)  
     * @param py The y-coord for the pivot point (unchanged by the scale)  
     */  
    public final void scale(float sx, float sy, float px, float py) {  
        translate(px, py);  
        scale(sx, sy);  
        translate(-px, -py);  
    }

3.4 skew扭曲

4.RectF介紹

4.1 Rect簡單屬性

  • 這是一個咱們經常使用的一個「繪畫相關的工具類」,經常使用語描述長方形/正方形,他只有4個屬性
    public int left;
    public int top;
    public int right;
    public int bottom;
  • 其中經常使用的構造方法以下所示
    public Rect(int left, int top, int right, int bottom) {
        this.left = left;
        this.top = top;
        this.right = right;
        this.bottom = bottom;
    }
    
    public Rect(Rect r) {
        if (r == null) {
            left = top = right = bottom = 0;
        } else {
            left = r.left;
            top = r.top;
            right = r.right;
            bottom = r.bottom;
        }
    }
  • 這4個屬性描述着這一個「方塊」,可是這有一個知識點須要理清楚,先看這張圖
    • image

4.2 Rect父類的實現

  • 實現了Parcelable 因此須要實現一堆Object的方法,諸如equals,toString等等,來簡單看一看
    • 對於equals方法,首先先對傳來的對象進行判空,類型判斷,再強轉成Rect對象,最後仍是一個個去比對那4個屬性。
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
    
        Rect r = (Rect) o;
        return left == r.left && top == r.top && right == r.right && bottom == r.bottom;
    }
    
    @Override
    public int hashCode() {
        int result = left;
        result = 31 * result + top;
        result = 31 * result + right;
        result = 31 * result + bottom;
        return result;
    }
    
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(32);
        sb.append("Rect("); sb.append(left); sb.append(", ");
        sb.append(top); sb.append(" - "); sb.append(right);
        sb.append(", "); sb.append(bottom); sb.append(")");
        return sb.toString();
    }

4.3 Rect經常使用的一些方法

  • 獲取「寬」
    //文章開頭說的公式在這裏獲得了應驗
    public final int width() {
        return right - left;
    }
  • 獲取「高」
    public final int height() {
        return bottom - top;
    }
  • 有效性的判斷
    //由於left是最左側,right比left還小不就不成形了麼?寬高同是如此
    public final boolean isEmpty() {
        return left >= right || top >= bottom;
    }
  • 所有置0操做
    public void setEmpty() {
        left = right = top = bottom = 0;
    }
  • 設置參數方法,和構造函數的區別僅在於不會建立新對象
    public void set(int left, int top, int right, int bottom) {
        this.left = left;
        this.top = top;
        this.right = right;
        this.bottom = bottom;
    }

5.關於使用到這幾個屬性的自定義View

  • 上面比較詳細介紹了Canvas,Paint,Matrix,RectF等等的屬性,做用,經常使用方法,接下來就須要結合具體業務需求練手寫一下小案例自定義控件呢

5.1 自定義輪播圖圓點

  • 5.1.1 需求介紹
    • 繪製圓環,一個實心中心圓,還有一個外圓環
    • 此控件能夠設置寬度和高度,能夠設置顏色
  • 5.1.2 思路介紹
    • 3.2.1 既然是繪製圓形,能夠寫一個繼承View的自定義view
    • 3.2.2 重寫onDraw方法,獲取控件寬高,而後比較寬高值,取小值的一半做爲圓的半徑
    • 3.2.3 而後分別繪製選中狀態和未選中狀態的圓
    • 3.2.4 建立畫筆Paint,而且設置相關屬性,好比畫筆顏色,類型等
    • 3.2.5 利用canvas繪製圓,而後再又用相同方法繪製外邊緣
    • 3.2.6 自定義一個是否選中狀態的方法,傳入布爾值是否選中,而後調用view中invalidate方法
  • 5.1.3 代碼介紹
    • 具體代碼以下所示:
    /**
     * <pre>
     *     @author yangchong
     *     blog  : https://github.com/yangchong211
     *     time  : 2016/5/18
     *     desc  : 紅點自定義控件
     *     revise: 建議設置紅點寬高同樣,不然是橢圓
     * </pre>
     */
    public class DotView extends View {
    
        private boolean isInit = false;
        private boolean isSelected = false;
        private float mViewHeight;
        private float mViewWidth;
        private float mRadius;
        private Paint mPaintBg = new Paint();
        private int mBgUnselectedColor = Color.parseColor("#1A000000");
        private int mBgSelectedColor = Color.parseColor("#FDE26E");
        private static final float mArcWidth = 2.0f;
    
        public DotView(Context context) {
            super(context);
        }
    
        public DotView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public DotView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (!isInit) {
                isInit = true;
                mViewHeight = getHeight();
                mViewWidth = getWidth();
                if (mViewHeight >= mViewWidth) {
                    mRadius = mViewWidth / 2.f;
                } else {
                    mRadius = mViewHeight / 2.f;
                }
            }
    
            //是否選中
            if (isSelected){
                drawSelectedDot(canvas);
            } else{
                drawUnSelectedDot(canvas);
            }
        }
    
        /**
         * 繪製選中指示器紅點
         * @param canvas                    canvas
         */
        private void drawSelectedDot(Canvas canvas) {
            //設置paint相關屬性
            mPaintBg.setAntiAlias(true);
            mPaintBg.setColor(mBgSelectedColor);
            mPaintBg.setStyle(Style.FILL);
    
            //繪製圓
            canvas.drawCircle(mViewWidth / 2.f, mViewHeight / 2.f, mRadius - 8.f, mPaintBg);
    
            mPaintBg.setStyle(Style.STROKE);
            float offset = 1.f + mArcWidth;
            RectF oval = new RectF(mViewWidth / 2.f - mRadius + offset, mViewHeight / 2.f - mRadius + offset,
                    mViewWidth / 2.f + mRadius - offset, mViewHeight / 2.f + mRadius - offset);
    
            //繪製指定的弧線,該弧線將被縮放以適應指定的橢圓形。
            canvas.drawArc(oval, 0.f, 360.f, false, mPaintBg);
        }
    
        /**
         * 繪製未選中指示器紅點
         * @param canvas                    canvas
         */
        private void drawUnSelectedDot(Canvas canvas) {
            mPaintBg.setAntiAlias(true);
            mPaintBg.setColor(mBgUnselectedColor);
            mPaintBg.setStyle(Style.FILL);
            canvas.drawCircle(mViewWidth / 2.f, mViewHeight / 2.f, mRadius - 8.f, mPaintBg);
        }
    
    
        /**
         * 設置是否選中
         * @param isSelected                isSelected
         */
        public void setIsSelected(boolean isSelected) {
            this.isSelected = isSelected;
            //使整個視圖無效。若是視圖是可見的,則{@link#onDraw(android.Graphics.Canvas)}將在未來的某個時候被調用。
            //調用該方法,會進行從新繪製,也就是調用onDraw方法
            this.invalidate();
        }
    }

5.2 自定義圓環百分比進度條

  • 5.2.1 需求分析php

    • 1.業務需求:能夠設置圓角,能夠設置圓形,若是是圓角則必須設置半徑,默認圓角半徑爲10dp
    • 2.若是設置了圓形,則即便設置圓角也無效;若是設置非圓形,則圓角生效,同時須要判斷圓角半徑是否大於控件寬高,處理邊界邏輯
    • 3.當設置圓形的時候,即便設置寬高不同,那麼取寬高中的最小值的一半爲圓形半徑
  • 5.2.2 代碼介紹android

    • 代碼以下所示
    public class ARoundImageView extends AppCompatImageView {
    
        /*
         *   Paint:畫筆
         *   Canvas:畫布
         *   Matrix:變換矩陣
         *
         *   業務需求:能夠設置圓角,能夠設置圓形,若是是圓角則必須設置半徑,默認圓角半徑爲10dp
         */
        /**
         * 圓形模式
         */
        private static final int MODE_CIRCLE = 1;
        /**
         * 普通模式
         */
        private static final int MODE_NONE = 0;
        /**
         * 圓角模式
         */
        private static final int MODE_ROUND = 2;
        /**
         * 圓角半徑
         */
        private int currRound = dp2px(10);
        /**
         * 畫筆
         */
        private Paint mPaint;
        /**
         * 默認是普通模式
         */
        private int currMode = 0;
    
        public ARoundImageView(Context context) {
            this(context,null);
        }
    
        public ARoundImageView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public ARoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            obtainStyledAttrs(context, attrs, defStyleAttr);
            initViews();
        }
    
        private void obtainStyledAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ARoundImageView, defStyleAttr, 0);
            currMode = a.hasValue(R.styleable.ARoundImageView_type) ? a.getInt(R.styleable.ARoundImageView_type, MODE_NONE) : MODE_NONE;
            currRound = a.hasValue(R.styleable.ARoundImageView_radius) ? a.getDimensionPixelSize(R.styleable.ARoundImageView_radius, currRound) : currRound;
            a.recycle();
        }
    
        private void initViews() {
            //ANTI_ALIAS_FLAG 用於繪製時抗鋸齒
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        }
    
    
        /**
         * 當模式爲圓形模式的時候,咱們強制讓寬高一致
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            if (currMode == MODE_CIRCLE) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                int result = Math.min(getMeasuredHeight(), getMeasuredWidth());
                // 此方法必須由{@link#onMeasure(int,int)}調用,以存儲已測量的寬度和測量的高度。
                // 若是不這樣作,將在測量時觸發異常。
                setMeasuredDimension(result, result);
            } else {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            }
        }
    
        @SuppressLint("DrawAllocation")
        @Override
        protected void onDraw(Canvas canvas) {
            //獲取ImageView圖片資源
            Drawable mDrawable = getDrawable();
            //獲取Matrix對象
            Matrix mDrawMatrix = getImageMatrix();
            if (mDrawable == null) {
                return;
            }
            if (mDrawable.getIntrinsicWidth() == 0 || mDrawable.getIntrinsicHeight() == 0) {
                return;
            }
            if (mDrawMatrix == null && getPaddingTop() == 0 && getPaddingLeft() == 0) {
                mDrawable.draw(canvas);
            } else {
                final int saveCount = canvas.getSaveCount();
                canvas.save();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    if (getCropToPadding()) {
                        final int scrollX = getScrollX();
                        final int scrollY = getScrollY();
                        canvas.clipRect(scrollX + getPaddingLeft(), scrollY + getPaddingTop(),
                                scrollX + getRight() - getLeft() - getPaddingRight(),
                                scrollY + getBottom() - getTop() - getPaddingBottom());
                    }
                }
                canvas.translate(getPaddingLeft(), getPaddingTop());
                switch (currMode){
                    case MODE_CIRCLE:
                        Bitmap bitmap1 = drawable2Bitmap(mDrawable);
                        mPaint.setShader(new BitmapShader(bitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
                        canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, mPaint);
                        break;
                    case MODE_ROUND:
                        Bitmap bitmap2 = drawable2Bitmap(mDrawable);
                        mPaint.setShader(new BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
                        canvas.drawRoundRect(new RectF(getPaddingLeft(), getPaddingTop(),
                                        getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()),
                                currRound, currRound, mPaint);
                        break;
                    case MODE_NONE:
                    default:
                        if (mDrawMatrix != null) {
                            canvas.concat(mDrawMatrix);
                        }
                        mDrawable.draw(canvas);
                        break;
                }
                canvas.restoreToCount(saveCount);
            }
        }
    
        /**
         * drawable轉換成bitmap
         */
        private Bitmap drawable2Bitmap(Drawable drawable) {
            if (drawable == null) {
                return null;
            }
            Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            //根據傳遞的scaleType獲取matrix對象,設置給bitmap
            Matrix matrix = getImageMatrix();
            if (matrix != null) {
                canvas.concat(matrix);
            }
            drawable.draw(canvas);
            return bitmap;
        }
    
        private int dp2px(float value) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                    value, getResources().getDisplayMetrics());
        }
    }

關於其餘內容介紹

01.關於博客彙總連接

02.關於個人博客

相關文章
相關標籤/搜索