天天看點

自定義圓角和園邊的實作源碼點選下載下傳

本來想在網上找個圓角的例子看一看,不盡人意啊,基本都是官方的demo的那張原理圖,稍後會貼出。于是自己自定義了個view,實作圖檔的圓角以及圓形效果。效果圖:

自定義圓角和園邊的實作源碼點選下載下傳

第一個是原圖,第二個是圓形效果,第三第四設定了不同的圓角大小。

準備改變一個部落格的風格,首先給大家講一下原理,讓大家明白了,然後再貼代碼,不然可以直接看那麼長的代碼也比較痛苦,核心代碼其實就那麼幾行:

核心代碼分析:

自定義圓角和園邊的實作源碼點選下載下傳

/** 

     * 根據原圖和變長繪制圓形圖檔 

     *  

     * @param source 

     * @param min 

     * @return 

     */  

    private bitmap createcircleimage(bitmap source, int min)  

    {  

        final paint paint = new paint();  

        paint.setantialias(true);  

        bitmap target = bitmap.createbitmap(min, min, config.argb_8888);  

        /** 

         * 産生一個同樣大小的畫布 

         */  

        canvas canvas = new canvas(target);  

         * 首先繪制圓形 

        canvas.drawcircle(min / 2, min / 2, min / 2, paint);  

         * 使用src_in 

        paint.setxfermode(new porterduffxfermode(porterduff.mode.src_in));  

         * 繪制圖檔 

        canvas.drawbitmap(source, 0, 0, paint);  

        return target;  

    }  

其實主要靠:paint.setxfermode(new porterduffxfermode(porterduff.mode.src_in));這行代碼,為什麼呢,我給大家解釋下,src_in這種模式,兩個繪制的效果疊加後取交集展現後圖,怎麼說呢,咱們第一個繪制的是個圓形,第二個繪制的是個bitmap,于是交集為圓形,展現的是bitmap,就實作了圓形圖檔效果。圓角,其實就是先繪制圓角矩形,是不是很簡單,以後别人再說實作圓角,你就把這一行代碼給他就行了。

從android的示例中,給大家證明一下:

下面有一張porterduff.mode的16中效果圖,咱們的隻是其一:

自定義圓角和園邊的實作源碼點選下載下傳

源碼咱們隻關心誰先誰後繪制的:

自定義圓角和園邊的實作源碼點選下載下傳

canvas.translate(x, y);  

              canvas.drawbitmap(mdstb, 0, 0, paint);  

              paint.setxfermode(smodes[i]);  

              canvas.drawbitmap(msrcb, 0, 0, paint);  

              paint.setxfermode(null);  

              canvas.restoretocount(sc);  

可以看出先繪制的dst,再繪制的src,最後的展示是srcin那個圖:顯示的區域是二者交集,展示的是src(後者)。和咱們前面結論一緻。效果16種,大家可以自由組合展示不同的效果。

好了,原理和核心代碼解釋完成。下面開始寫自定義view。

1、自定義屬性:

自定義圓角和園邊的實作源碼點選下載下傳

<?xml version="1.0" encoding="utf-8"?>  

<resources>  

    <attr name="borderradius" format="dimension" />  

    <attr name="type">  

        <enum name="circle" value="0" />  

        <enum name="round" value="1" />  

    </attr>  

    <attr name="src" format="reference"></attr>  

    <declare-styleable name="customimageview">  

        <attr name="borderradius" />  

        <attr name="type" />  

        <attr name="src" />  

    </declare-styleable>  

</resources>  

2、構造中擷取自定義的屬性:

自定義圓角和園邊的實作源碼點選下載下傳

 * type_circle / type_round 

 */  

private int type;  

private static final int type_circle = 0;  

private static final int type_round = 1;  

 * 圖檔 

private bitmap msrc;  

 * 圓角的大小 

private int mradius;  

 * 控件的寬度 

private int mwidth;  

 * 控件的高度 

private int mheight;  

public customimageview(context context, attributeset attrs)  

{  

    this(context, attrs, 0);  

}  

public customimageview(context context)  

    this(context, null);  

 * 初始化一些自定義的參數 

 *  

 * @param context 

 * @param attrs 

 * @param defstyle 

public customimageview(context context, attributeset attrs, int defstyle)  

    super(context, attrs, defstyle);  

    typedarray a = context.gettheme().obtainstyledattributes(attrs, r.styleable.customimageview, defstyle, 0);  

    int n = a.getindexcount();  

    for (int i = 0; i < n; i++)  

        int attr = a.getindex(i);  

        switch (attr)  

        {  

        case r.styleable.customimageview_src:  

            msrc = bitmapfactory.decoderesource(getresources(), a.getresourceid(attr, 0));  

            break;  

        case r.styleable.customimageview_type:  

            type = a.getint(attr, 0);// 預設為circle  

        case r.styleable.customimageview_borderradius:  

            type = a.getdimensionpixelsize(attr, (int) typedvalue.applydimension(typedvalue.complex_unit_dip, 10f,  

                    getresources().getdisplaymetrics()));// 預設為10dp  

        }  

    a.recycle();  

3、onmeasure中擷取控件寬高:

自定義圓角和園邊的實作源碼點選下載下傳

     * 計算控件的高度和寬度 

    @override  

    protected void onmeasure(int widthmeasurespec, int heightmeasurespec)  

        // super.onmeasure(widthmeasurespec, heightmeasurespec);  

         * 設定寬度 

        int specmode = measurespec.getmode(widthmeasurespec);  

        int specsize = measurespec.getsize(widthmeasurespec);  

        if (specmode == measurespec.exactly)// match_parent , accurate  

            mwidth = specsize;  

        } else  

            // 由圖檔決定的寬  

            int desirebyimg = getpaddingleft() + getpaddingright() + msrc.getwidth();  

            if (specmode == measurespec.at_most)// wrap_content  

            {  

                mwidth = math.min(desirebyimg, specsize);  

            }  

        /*** 

         * 設定高度 

        specmode = measurespec.getmode(heightmeasurespec);  

        specsize = measurespec.getsize(heightmeasurespec);  

            mheight = specsize;  

            int desire = getpaddingtop() + getpaddingbottom() + msrc.getheight();  

                mheight = math.min(desire, specsize);  

        setmeasureddimension(mwidth, mheight);  

4、根據type繪制:

自定義圓角和園邊的實作源碼點選下載下傳

     * 繪制 

    protected void ondraw(canvas canvas)  

        switch (type)  

        // 如果是type_circle繪制圓形  

        case type_circle:  

            int min = math.min(mwidth, mheight);  

            /** 

             * 長度如果不一緻,按小的值進行壓縮 

             */  

            msrc = bitmap.createscaledbitmap(msrc, min, min, false);  

            canvas.drawbitmap(createcircleimage(msrc, min), 0, 0, null);  

        case type_round:  

            canvas.drawbitmap(createroundconerimage(msrc), 0, 0, null);  

    /** 

         * 使用src_in,參考上面的說明 

     * 根據原圖添加圓角 

    private bitmap createroundconerimage(bitmap source)  

        bitmap target = bitmap.createbitmap(mwidth, mheight, config.argb_8888);  

        rectf rect = new rectf(0, 0, source.getwidth(), source.getheight());  

        canvas.drawroundrect(rect, 50f, 50f, paint);  

好了,我就不解析代碼了,自定義view這是第五篇了,,,,寫得好惡心,,,,

各位贊一個或者留個言,算是對我的支援~

繼續閱讀