前言:再重復一遍我很喜歡的一句話,送給大家:迷茫,本就是青春該有的樣子 ,但不要讓未來的你,討厭現在的自己
系列文章:
Android自定義控件三部曲文章索引:http://blog.csdn.net/harvic880925/article/details/50995268
上篇給大家講解了如何控件添加陰影效果,但是在為Bitmap圖片添加陰影時,卻沒辦法添加具有指定顏色的陰影,這篇我們就來使用自定義的控件及自定義屬性來初步封裝下控件。前方高能預警——本篇內容涉及內容較多,難度較大,需要多加思考。
###一、使用BlurMaskFilter為圖片構造定色陰影效果
上面我們講了通過setShadowLayer為圖片添加陰影效果,但是圖片的的陰影是用原圖形的副本加上邊緣發(fā)光效果組成的。我們怎么能給圖片添加一個灰色的陰影呢?
我們來分析一下setShadowLayer的陰影形成過程(假定陰影畫筆是灰色),對于文字和圖形,它首先產生一個跟原型一樣的灰色副本。然后對這個灰色副本應用BlurMaskFilter,使其內外發(fā)光;這樣就形成了所謂的陰影!當然最后再偏移一段距離。
所以,我們要給圖片添加灰色陰影效果,所以我們能不能仿一下這個過程:先繪制一個跟圖片一樣大小的灰色圖形,然后給這個灰色圖形應用BlurMaskFilter使其內外發(fā)光,然后偏移原圖形繪制出來,不就可以了么
所以,這里涉及到三個點:
- 繪制出一個一樣大小的灰色圖形
- 對灰色圖形應用BlurMaskFilter使其內外發(fā)光
- 偏移原圖形一段距離繪制出來
下面我們就通過例子來一步步看是怎么實現出來的吧
####1、繪制出一個一樣大小的灰色圖像
首先,我們來看怎么能繪出一個指定Bitmap所對應的灰色圖像。我們知道canvas.drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)中的paint的畫筆顏色對畫出來的bitmap是沒有任何影響的,因為原來Bitmap長什么樣,無論你畫筆是什么顏色,畫出來的圖片還是跟原圖片長的一樣。所以如果我們需要畫一張對應的灰色圖像,我們需要新建一個一樣大小的空白圖,但是新圖片的透明度要與原圖片保持一致。所以如何從原圖片中抽出Alpha值成為了關鍵。即我們只需要創(chuàng)建一個與原圖片一樣大小且Alpha相同的圖片即可。
其實Bitmap中已經存在抽取出只具有Alpha值圖片的函數:
public Bitmap
extractAlpha();
extraAlpha()函數的功能是:新建一張空白圖片,圖片具有與原圖片一樣的Alpha值,這個新建的Bitmap做為結果返回。這個空白圖片中每個像素都具有與原圖片一樣的Alpha值,而且具體的顏色時,只有在使用canvas.drawBitmap繪制時,由傳入的paint的顏色指定。
所以總結來講:
- extractAlpha()新建一張僅具有Alpha值的空白圖像
- 這張圖像的顏色,是由canvas.drawBitmap時的畫筆指定的。
(1)、extractAlpha()使用示例
下面,我們就用個例子先來看下extractAlpha()函數的用法
我們拿一張圖片來做試驗,下面這張PNG圖片中,一只小貓和一只小狗,其余地方都是透明色。
下面我們分別利用extractAlpha()畫出它對應的紅色和綠色的陰影圖
對應的代碼為:
public class ExtractAlphaView extends View {private Paint mPaint
;private Bitmap mBitmap
,mAlphaBmp
;public ExtractAlphaView(Context context
) {super(context
);init();}public ExtractAlphaView(Context context
, AttributeSet attrs
) {super(context
, attrs
);init();}public ExtractAlphaView(Context context
, AttributeSet attrs
, int defStyle
) {super(context
, attrs
, defStyle
);init();}private void init(){setLayerType(LAYER_TYPE_SOFTWARE
,null
);mPaint
= new Paint();mBitmap
= BitmapFactory
.decodeResource(getResources(),R
.drawable
.blog12
);mAlphaBmp
= mBitmap
.extractAlpha();}@Overrideprotected void onDraw(Canvas canvas
) {super.onDraw(canvas
);int width
= 200;int height
= width
* mAlphaBmp
.getHeight()/mAlphaBmp
.getWidth();mPaint
.setColor(Color
.RED
);canvas
.drawBitmap(mAlphaBmp
,null
,new Rect(0,0,width
,height
),mPaint
);mPaint
.setColor(Color
.GREEN
);canvas
.drawBitmap(mAlphaBmp
,null
,new Rect(0,height
,width
,2*height
),mPaint
);}
}
首先看init函數:
private void init(){setLayerType(LAYER_TYPE_SOFTWARE
,null
);mPaint
= new Paint();mBitmap
= BitmapFactory
.decodeResource(getResources(),R
.drawable
.blog12
);mAlphaBmp
= mBitmap
.extractAlpha();
}
首先是禁用硬件加速,這基本上是我們做自定義控件的標配!為了防止功能不好用,記得每次都加上這個函數!然后是利用extratAlpha()來生成僅具有透明度的空白圖像。
最后看OnDraw函數:
protected void onDraw(Canvas canvas
) {super.onDraw(canvas
);int width
= 200;int height
= width
* mAlphaBmp
.getHeight()/mAlphaBmp
.getWidth();mPaint
.setColor(Color
.RED
);canvas
.drawBitmap(mAlphaBmp
,null
,new Rect(0,0,width
,height
),mPaint
);mPaint
.setColor(Color
.GREEN
);canvas
.drawBitmap(mAlphaBmp
,null
,new Rect(0,height
,width
,2*height
),mPaint
);
}
這里分別將畫筆的顏色設置為紅色和綠色,然后兩次把mAlphaBmp畫出來。上面我們已經提到,在畫僅具有透明度的空白圖像時,圖像的顏色是由畫筆顏色指定的。所以從效果圖中也可以看出畫出來的圖像分別紅色的綠色的。
這就是Bitmpa.extraAlpha()的用法!
####2、對灰色圖形應用BlurMaskFilter使其內外發(fā)光
在第一步完成了之后,我們進行第二步,將陰影添加內外發(fā)光效果。就形成了陰影的模樣。
代碼很簡單,只需要使用Paint.setMaskFilter函數添加發(fā)光效果即可,代碼如下:
protected void onDraw(Canvas canvas
) {super.onDraw(canvas
);int width
= 200;int height
= width
* mAlphaBmp
.getHeight()/mAlphaBmp
.getWidth();mPaint
.setColor(Color
.RED
);mPaint
.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter
.Blur
.NORMAL
));canvas
.drawBitmap(mAlphaBmp
,null
,new Rect(0,0,width
,height
),mPaint
);mPaint
.setColor(Color
.GREEN
);canvas
.drawBitmap(mAlphaBmp
,null
,new Rect(0,height
,width
,2*height
),mPaint
);
}
明顯可以看出這里只添加了一行代碼:mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL));就是添加內外發(fā)光效果,難度不大,不再細講。
####3、偏移原圖形一段距離繪制出來
這段比較簡單了,只需要先把陰影畫出來,然后再把原圖像蓋上去,但需要注意的是,陰影需要相對原圖像偏移一段距離。完整代碼如下:
public class ExtractAlphaView extends View {private Paint mPaint
;private Bitmap mBitmap
,mAlphaBmp
;public ExtractAlphaView(Context context
) {super(context
);init();}public ExtractAlphaView(Context context
, AttributeSet attrs
) {super(context
, attrs
);init();}public ExtractAlphaView(Context context
, AttributeSet attrs
, int defStyle
) {super(context
, attrs
, defStyle
);init();}private void init(){setLayerType(LAYER_TYPE_SOFTWARE
,null
);mPaint
= new Paint();mBitmap
= BitmapFactory
.decodeResource(getResources(),R
.drawable
.blog12
);mAlphaBmp
= mBitmap
.extractAlpha();}@Overrideprotected void onDraw(Canvas canvas
) {super.onDraw(canvas
);int width
= 200;int height
= width
* mAlphaBmp
.getHeight()/mAlphaBmp
.getWidth();mPaint
.setColor(Color
.RED
);mPaint
.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter
.Blur
.NORMAL
));canvas
.drawBitmap(mAlphaBmp
,null
,new Rect(10,10,width
,height
),mPaint
);mPaint
.setColor(Color
.GREEN
);canvas
.drawBitmap(mAlphaBmp
,null
,new Rect(10,height
+10,width
,2*height
),mPaint
);mPaint
.setMaskFilter(null
);canvas
.drawBitmap(mBitmap
,null
,new Rect(0,0,width
,height
),mPaint
);canvas
.drawBitmap(mBitmap
,null
,new Rect(0,height
,width
,2*height
),mPaint
);}
}
關鍵部分在onDraw函數中,先畫出來陰影,然后再畫出來原圖像,需要注意的是在畫原圖像時,需要利用mPaint.setMaskFilter(null);將發(fā)光效果去掉。只有陰影需要發(fā)光效果,原圖像是不需要發(fā)光效果的。另一點注意的是,陰影要偏移一點位置,這里是偏移了10個像素。
效果圖如下:
###二、封裝控件
上面我們初步實現了圖片的陰影效果,但這只是本篇內容的一小部分,最最重要的,如何將它封裝成一個控件,具有如下功能:
- 讓用戶定義圖片內容
- 讓用戶定義偏移距離
- 讓用戶定義陰影顏色和陰影模糊程度
- 可以使用wrap_content屬性自適應大小
####1、自定義控件屬性
有關自定義控件屬性,大家首先需要看下這篇文章《PullScrollView詳解(一)——自定義控件屬性》,在這篇文章中講解了自定義控件屬性的方法與提取方法。下面將會直接用到自定義屬性的內容,下面涉及到的時候就自認為大家已經學會了自定義控件屬性的方法了。
在這里,我們需要自定義四個屬性,分別對應: 自定義圖片內容、自定義偏移距離、自定義陰影顏色、自定義陰影模糊程度 這四個需求,所以我們先利用declare-styleable標簽來定義這些屬性
attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="BitmapShadowView"><attr name="src" format="reference" /><attr name="shadowDx" format="integer" /><attr name="shadowDy" format="integer" /><attr name="shadowColor" format="color"/><attr name="shadowRadius" format="float"/></declare-styleable>
</resources>
這里定義了五個xml屬性,src來引用圖片資源,仿照setShadowLayer另外定義shadowDx、shadowDy、shadowColor、shadowRadius來定義陰影的邊距、顏色和模糊半徑。
然后在布局中使用:(main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res/com.harvic.BlogBitmapShadow"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><com.harvic.BlogBitmapShadow.BitmapShadowViewandroid:layout_width="200dp"android:layout_height="200dp"android:layout_gravity="center_horizontal"app:src="@drawable/blog12"app:shadowDx="10"app:shadowDy="10"app:shadowRadius="10.0"app:shadowColor="@android:color/holo_red_dark"/>
</LinearLayout>
在布局中使用很簡單,直接定義控件所使用的圖片資源、陰影相關參數就可以了,難度不大就不再講了,下面我們來看如何在代碼中中提取用戶傳入的這些屬性。
BitmapShadowView中提取屬性值并繪陰影
先列出完整代碼,然后再細講:
public class BitmapShadowView extends View {private Paint mPaint
;private Bitmap mBmp
,mShadowBmp
;private int mDx
= 10,mDy
= 10;private float mRadius
= 0;private int mShadowColor
;public BitmapShadowView(Context context
, AttributeSet attrs
) throws Exception
{super(context
, attrs
);init(context
,attrs
);}public BitmapShadowView(Context context
, AttributeSet attrs
, int defStyle
) throws Exception
{super(context
, attrs
, defStyle
);init(context
,attrs
);}private void init(Context context
,AttributeSet attrs
) throws Exception
{setLayerType(LAYER_TYPE_SOFTWARE
,null
);TypedArray typedArray
= context
.obtainStyledAttributes(attrs
,R
.styleable
.BitmapShadowView
);int BitmapID
= typedArray
.getResourceId(R
.styleable
.BitmapShadowView_src
,-1);if (BitmapID
== -1){throw new Exception("BitmapShadowView 需要定義Src屬性,而且必須是圖像");}mBmp
= BitmapFactory
.decodeResource(getResources(),BitmapID
);mDx
= typedArray
.getInt(R
.styleable
.BitmapShadowView_shadowDx
,0);mDy
= typedArray
.getInt(R
.styleable
.BitmapShadowView_shadowDy
,0);mRadius
= typedArray
.getFloat(R
.styleable
.BitmapShadowView_shadowRadius
,0);mShadowColor
= typedArray
.getColor(R
.styleable
.BitmapShadowView_shadowColor
,Color
.BLACK
);typedArray
.recycle();mPaint
= new Paint();mShadowBmp
= mBmp
.extractAlpha();}@Overrideprotected void onDraw(Canvas canvas
) {super.onDraw(canvas
);int width
= getWidth()-mDx
;int height
= width
* mBmp
.getHeight()/mBmp
.getWidth();mPaint
.setColor(mShadowColor
);mPaint
.setMaskFilter(new BlurMaskFilter(mRadius
, BlurMaskFilter
.Blur
.NORMAL
));canvas
.drawBitmap(mShadowBmp
,null
,new Rect(mDx
,mDy
,width
,height
),mPaint
);mPaint
.setMaskFilter(null
);canvas
.drawBitmap(mBmp
,null
,new Rect(0,0,width
,height
),mPaint
);}
}
在這段代碼中分兩部分,首先根據屬性來初始化各變量,然后再利用這些變量畫出bitmap與陰影。
首先看初始化部分:
private void init(Context context
,AttributeSet attrs
) throws Exception
{setLayerType(LAYER_TYPE_SOFTWARE
,null
);TypedArray typedArray
= context
.obtainStyledAttributes(attrs
,R
.styleable
.BitmapShadowView
);int BitmapID
= typedArray
.getResourceId(R
.styleable
.BitmapShadowView_src
,-1);if (BitmapID
== -1){throw new Exception("BitmapShadowView 需要定義Src屬性,而且必須是圖像");}mBmp
= BitmapFactory
.decodeResource(getResources(),BitmapID
);mDx
= typedArray
.getInt(R
.styleable
.BitmapShadowView_shadowDx
,0);mDy
= typedArray
.getInt(R
.styleable
.BitmapShadowView_shadowDy
,0);mRadius
= typedArray
.getFloat(R
.styleable
.BitmapShadowView_shadowRadius
,0);mShadowColor
= typedArray
.getColor(R
.styleable
.BitmapShadowView_shadowColor
,Color
.BLACK
);typedArray
.recycle();mPaint
= new Paint();mShadowBmp
= mBmp
.extractAlpha();
}
初始化的時候,首先是利用TypedArray來初始化各項參數,由于我們是做圖片的陰影,所以圖片資源必須賦值,所以我們在提取圖片資源時,對其添加容錯:
int BitmapID
= typedArray
.getResourceId(R
.styleable
.BitmapShadowView_src
,-1);
if (BitmapID
== -1){throw new Exception("BitmapShadowView 需要定義Src屬性,而且必須是圖像");
}
當提取失敗時,拋出異常,終止程序,這樣用戶在寫代碼時就可以及時發(fā)現問題,而不必等上線以后才發(fā)現沒有bitmap;
有關其它屬性值的提取,這里就不再細講了。
在提取完屬性以后,就是定義畫筆paint和根據源圖像利用extractAlpha()來生成陰影圖像;
在初始化以后就是利用這些屬性來進行繪圖了:
protected void onDraw(Canvas canvas
) {super.onDraw(canvas
);int width
= getWidth()-mDx
;int height
= width
* mBmp
.getHeight()/mBmp
.getWidth();mPaint
.setColor(mShadowColor
);mPaint
.setMaskFilter(new BlurMaskFilter(mRadius
, BlurMaskFilter
.Blur
.NORMAL
));canvas
.drawBitmap(mShadowBmp
,null
,new Rect(mDx
,mDy
,width
,height
),mPaint
);mPaint
.setMaskFilter(null
);canvas
.drawBitmap(mBmp
,null
,new Rect(0,0,width
,height
),mPaint
);
}
首先,圖片寬度與控件寬度操持一致(但需要把陰影的位置空出來),所以寬度為:int width = getWidth()-mDx
根據圖片的寬高比換算出圖片的高度:int height = width * mBmp.getHeight()/mBmp.getWidth()
我們依控件左上角(0,0)顯示原圖像,陰影在(mDx,mDy)處顯示;
到這里自定義屬性的定義與提取就結束了,最終效果圖為:
從效果圖中可以明顯看出,明顯給原圖片添加了紅色的陰影效果。
目前,我們初步實現了可以讓用戶自定義控件屬性的功能,但我們在使用這個控件時,必須強制設置指定的寬高或者fill_parent來強制平屏,這樣明顯是不可取的,我們需要它能夠讓用戶使用wrap_conetent時,自己計算寬高;
####2、wrap_content自適應寬高
在自適應寬高時,需要了解onMeasure()、onLayout()與onDraw()的知識,以前在寫FlowLayout時,已經單獨寫過一篇:《FlowLayout詳解(一)——onMeasure()與onLayout()》,這里就不再細講onMeasure()的原理了,如果不理解onMeasure用法的同學需要提前把這篇文章看完再回來;在第三篇中我還會重新講解一遍onMeasure()、onLayout()與onDraw(),這里涉及內容不多,看完上一篇然后再理解以下內容應該不會有問題
在看完上面的文章,大家就應該知道,對于View控件的自適應寬高,只需要在上面的代碼中重寫onMeasure()方法就可以了:
protected void onMeasure(int widthMeasureSpec
, int heightMeasureSpec
) {super.onMeasure(widthMeasureSpec
, heightMeasureSpec
);int measureWidth
= MeasureSpec
.getSize(widthMeasureSpec
);int measureHeight
= MeasureSpec
.getSize(heightMeasureSpec
);int measureWidthMode
= MeasureSpec
.getMode(widthMeasureSpec
);int measureHeightMode
= MeasureSpec
.getMode(heightMeasureSpec
);int width
= mBmp
.getWidth();int height
= mBmp
.getHeight();setMeasuredDimension((measureWidthMode
== MeasureSpec
.EXACTLY
) ? measureWidth
: width
, (measureHeightMode
== MeasureSpec
.EXACTLY
) ? measureHeight
: height
);
}
在onMeasure方法中,當用戶指定屬性是wrap_content時,就使用圖片的寬高做為控件的寬高。
此時整個自定義控件的完整代碼為:
public class BitmapShadowView extends View {private Paint mPaint
;private Bitmap mBmp
,mShadowBmp
;private int mDx
= 10,mDy
= 10;private float mRadius
= 0;private int mShadowColor
;public BitmapShadowView(Context context
, AttributeSet attrs
) throws Exception
{super(context
, attrs
);init(context
,attrs
);}public BitmapShadowView(Context context
, AttributeSet attrs
, int defStyle
) throws Exception
{super(context
, attrs
, defStyle
);init(context
,attrs
);}private void init(Context context
,AttributeSet attrs
) throws Exception
{setLayerType(LAYER_TYPE_SOFTWARE
,null
);TypedArray typedArray
= context
.obtainStyledAttributes(attrs
,R
.styleable
.BitmapShadowView
);int BitmapID
= typedArray
.getResourceId(R
.styleable
.BitmapShadowView_src
,-1);if (BitmapID
== -1){throw new Exception("BitmapShadowView 需要定義Src屬性,而且必須是圖像");}mBmp
= BitmapFactory
.decodeResource(getResources(),BitmapID
);mDx
= typedArray
.getInt(R
.styleable
.BitmapShadowView_shadowDx
,0);mDy
= typedArray
.getInt(R
.styleable
.BitmapShadowView_shadowDy
,0);mRadius
= typedArray
.getFloat(R
.styleable
.BitmapShadowView_shadowRadius
,0);mShadowColor
= typedArray
.getColor(R
.styleable
.BitmapShadowView_shadowColor
,Color
.BLACK
);typedArray
.recycle();mPaint
= new Paint();mShadowBmp
= mBmp
.extractAlpha();}@Overrideprotected void onMeasure(int widthMeasureSpec
, int heightMeasureSpec
) {super.onMeasure(widthMeasureSpec
, heightMeasureSpec
);int measureWidth
= MeasureSpec
.getSize(widthMeasureSpec
);int measureHeight
= MeasureSpec
.getSize(heightMeasureSpec
);int measureWidthMode
= MeasureSpec
.getMode(widthMeasureSpec
);int measureHeightMode
= MeasureSpec
.getMode(heightMeasureSpec
);int width
= mBmp
.getWidth();int height
= mBmp
.getHeight();setMeasuredDimension((measureWidthMode
== MeasureSpec
.EXACTLY
) ? measureWidth
: width
, (measureHeightMode
== MeasureSpec
.EXACTLY
) ? measureHeight
: height
);}@Overrideprotected void onDraw(Canvas canvas
) {super.onDraw(canvas
);int width
= getWidth()-mDx
;int height
= width
* mBmp
.getHeight()/mBmp
.getWidth();mPaint
.setColor(mShadowColor
);mPaint
.setMaskFilter(new BlurMaskFilter(mRadius
, BlurMaskFilter
.Blur
.NORMAL
));canvas
.drawBitmap(mShadowBmp
,null
,new Rect(mDx
,mDy
,width
,height
),mPaint
);mPaint
.setMaskFilter(null
);canvas
.drawBitmap(mBmp
,null
,new Rect(0,0,width
,height
),mPaint
);}
}
所以當我們對這個自定義的控件使用如下布局(使用wrap_content):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res/com.harvic.BlogBitmapShadow"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><com.harvic.BlogBitmapShadow.BitmapShadowViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"app:src="@drawable/blog12"app:shadowDx="10"app:shadowDy="10"app:shadowRadius="10.0"app:shadowColor="@android:color/holo_red_dark"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="test BTN"/>
</LinearLayout>
效果圖如下:
所以,這時候如果我們需要產生灰色陰影,只需要把xml中的app:shadowColor的值改一下即可:(為了方便看陰影,我把Activiy背景改成了白色)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res/com.harvic.BlogBitmapShadow"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="@android:color/white"><com.harvic.BlogBitmapShadow.BitmapShadowViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"app:src="@drawable/blog12"app:shadowDx="10"app:shadowDy="10"app:shadowRadius="10.0"app:shadowColor="@android:color/darker_gray"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="test BTN"/>
</LinearLayout>
效果圖如下:
到這里,整個控件的封裝就結束了,但細心的同學可以發(fā)現,BitmapShadowView的構造函數默認有三個,而我這里只寫了兩個具有AttributeSet attrs參數的,而下面這個構造函數卻是沒有實現的:
public BitmapShadowView(Context context
){super(context
);
}
因為當從XML中生成控件時,都會調用具有AttributeSet attrs參數的方法,而從代碼中生成控件則會調用上面僅具有context函數的方法,所以如果需要從代碼中生成需要添加上這個方法,并且需要在代碼中提供接口供外部設置各種屬性才好,我這里就略去了這部分內容了,大家可以自己來填充這個控件,使其更完整。
好了,整篇文章到這里就結束了,源碼在文章底部給出。
如果本文有幫到你,記得加關注哦
源碼下載地址:http://download.csdn.net/detail/harvic880925/9573981
轉載請標明出處,http://blog.csdn.net/harvic880925/article/details/51889104謝謝
如果你喜歡我的文章,你可能更喜歡我的公眾號
總結
以上是生活随笔為你收集整理的自定义控件三部曲之绘图篇(十七)——为Bitmap添加阴影并封装控件的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。