android 通用圓角控件

koda8144 9年前發布 | 13K 次閱讀 Android開發 移動開發

圓角控件就是對 View的Canvas進行改變輪廓的處理 

改變輪廓兩種方式: 
1.剪切(clip()) 
剪切clip是對畫布進行剪切,只對剪切后的繪制起效果。 
ps:Canvas的圖形變換平移、放縮、旋轉、錯切、裁剪都是只對后面的繪制起效果, 
對應Matrix中preXXX,Matrix變換分為preXXX,postXXX,setXXX;preXXX將新的變換操作插到隊列 前,postXXX將新的變換操作插到隊列后,setXXX是先reset()清除前面的變換操作并設置新的變換操作,且都是只對后面的繪制起效果。 
Canvas的save,restore對變換操作進行保存,和還原,帶參的restoreToCount(save()),可以指定還原到第幾次保存的狀態。 


2.遮罩(PorterDuffXfermode) 
安卓提供多種遮罩模式選擇 
android 通用圓角控件 
遮罩是設置在Paint上的只對 當前繪制的操作有效 

下面利用這兩種方式實現圓角控件


onDraw 
onDrawForeground 
dispatchDraw 
這三個回調函數都是可以操作View的Canvas;onDraw,onDrawForeground這兩個是在View繪制背景,自身內容和前景時回調 的 只有設置了背景、自身內容、前景時才會配回調,并且對這兩個函數的參數Canvas上的操作,只對背景、自身內容、前景有效。 
dispatchDraw是繪制子控件時的回調,參數Canvas可以對子控件的畫布進行處理。 

通用圓角控件必須對子控件的對應位置也是原價所以我門選擇在dispatchDraw中進行圓角處理。

剪切(clip())

    @Override
    protected void dispatchDraw(Canvas canvas) {        int width = getWidth();        int height = getHeight();
        Path path = new Path();
        path.moveTo(0, topLeftRadius);
        path.arcTo(new RectF(0, 0, topLeftRadius * 2, topLeftRadius * 2), -180, 90);
        path.lineTo(width - topRightRadius, 0);
        path.arcTo(new RectF(width - 2 * topRightRadius, 0, width, topRightRadius * 2), -90, 90);
        path.lineTo(width, height - bottomRightRadius);
        path.arcTo(new RectF(width - 2 * bottomRightRadius, height - 2 * bottomRightRadius, width, height), 0, 90);
        path.lineTo(bottomLeftRadius, height);
        path.arcTo(new RectF(0, height - 2 * bottomLeftRadius, bottomLeftRadius * 2, height), 90, 90);
        path.close();
        canvas.clipPath(path);        super.dispatchDraw(canvas);
    }12345678910111213141516171234567891011121314151617

效果圖: 
android 通用圓角控件

 

上圖能看到明顯的鋸齒 因為 安卓雖提供了抗鋸齒功能但是是在Paint上操作的 clip過程沒有用到Paint 無法達到抗鋸齒目的;

遮罩(PorterDuffXfermode)

寫法一

 @Override
    protected void dispatchDraw(Canvas canvas) {        super.dispatchDraw(canvas);
        drawTopLeft(canvas);//用PorterDuffXfermode
        drawTopRight(canvas);//用PorterDuffXfermode
        drawBottomLeft(canvas);//用PorterDuffXfermode
        drawBottomRight(canvas);//用PorterDuffXfermode
    }1234567812345678

效果圖: 
android 通用圓角控件

上圖有黑色底色,view的Canvas底層畫布的BItmap是 RGB_565的所以怎么畫都有一個黑色底色。

我們可以new Canvas一個底層畫布的BItmap是 ARGB_8888的繪制完后 再把這個底層畫布的BItmap 繪制到View 的Canvas上

寫法二

    @Override
    protected void dispatchDraw(Canvas canvas) {
        Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas newCanvas = new Canvas(bitmap);        super.dispatchDraw(newCanvas);
        drawTopLeft(newCanvas);
        drawTopRight(newCanvas);
        drawBottomLeft(newCanvas);
        drawBottomRight(newCanvas);
        canvas.drawBitmap(bitmap,0,0,imagePaint);//        invalidate();
    }123456789101112123456789101112

效果圖: 
android 通用圓角控件

實現了,但是這種映射方式實現的 如果子控件中存在滑動控件,滑動時無法實時刷新,用Glide加載image到ImageView中時,WebView load時 都無法實時刷新,出現無法加載的效果,雖然可以加上invalidate通知刷新 但是掉幀明顯掉幀

我們只能用回寫法一 但是要解決黑色背景的問題 
只要加上一句代碼 就能解決 默認黑色背景的問題

canvas.saveLayer(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), imagePaint,Canvas.ALL_SAVE_FLAG);11
 @Override
    protected void dispatchDraw(Canvas canvas) {
canvas.saveLayer(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), imagePaint,Canvas.ALL_SAVE_FLAG);        super.dispatchDraw(canvas);
        drawTopLeft(canvas);//用PorterDuffXfermode
        drawTopRight(canvas);//用PorterDuffXfermode
        drawBottomLeft(canvas);//用PorterDuffXfermode
        drawBottomRight(canvas);//用PorterDuffXfermode
        canvas.restore();
    }1234567891012345678910

效果圖: 
android 通用圓角控件

因為view的Canvas底層畫布的BItmap是 RGB_565 
我們只要在保存為圖層就行了。用過Photoshop的都知道默認底層畫布是不透明的,要先解鎖,而這里解鎖就是保存為圖層。

 本文由用戶 koda8144 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!