轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://www.aiuxian.com/article/p-1982467.html
接下來(lái)就是如何實(shí)現(xiàn)的了。啥也不說(shuō)了,先上圖:
首先是原圖:
接下來(lái)就是效果圖了:
怎么樣?是不是比什么都不弄直接src進(jìn)去的要好呢?根據(jù)該方法大家可以實(shí)現(xiàn)最新版QQ的消息列表界面:
說(shuō)了那么多了,還沒(méi)給你們講講是怎么樣的一個(gè)原理呢!接下來(lái)就給大家講解一下實(shí)現(xiàn)該功能的原理:
其實(shí)主要是靠畫(huà)筆paint中的一個(gè)方法:paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));來(lái)實(shí)現(xiàn)的。
下面簡(jiǎn)單的介紹下Xfermode和PorterDuffXfermode:
該Mode是設(shè)置兩張圖片相交時(shí)的模式。
在正常的情況下,在已有的圖像上繪圖將會(huì)在其上面添加一層新的形狀。如果新的Paint是完全不透明的, 那么它將完全遮擋住下面的Paint;如果它是部分透明的,那么它將會(huì)被染上下面的顏色。
而setXfermode就可以來(lái)解決這個(gè)問(wèn)題 .
1Canvas canvas =newCanvas(dstBitmap);
2paint.setXfermode(newPorterDuffXfermode(Mode.SRC_IN));
3canvas.drawBitmap(srcBitmap, 0f, 0f, paint);
canvas原有的圖片可以理解為背景,就是dst;
新畫(huà)上去的圖片可以理解為前景,就是src。
下圖可以讓大家更好的理解PorterDuffXfermode的Mode:
從上面我們可以看到PorterDuff.Mode為枚舉類(lèi),一共有16個(gè)枚舉值:
1.PorterDuff.Mode.CLEAR
所繪制不會(huì)提交到畫(huà)布上。
2.PorterDuff.Mode.SRC
顯示上層繪制圖片
3.PorterDuff.Mode.DST
顯示下層繪制圖片
4.PorterDuff.Mode.SRC_OVER
正常繪制顯示,上下層繪制疊蓋。
5.PorterDuff.Mode.DST_OVER
上下層都顯示。下層居上顯示。
6.PorterDuff.Mode.SRC_IN
取兩層繪制交集。顯示上層。
7.PorterDuff.Mode.DST_IN
取兩層繪制交集。顯示下層。
8.PorterDuff.Mode.SRC_OUT
取上層繪制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下層繪制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下層非交集部分與上層交集部分
11.PorterDuff.Mode.DST_ATOP
取上層非交集部分與下層交集部分
12.PorterDuff.Mode.XOR
異或:去除兩圖層交集部分
13.PorterDuff.Mode.DARKEN
取兩圖層全部區(qū)域,交集部分顏色加深
14.PorterDuff.Mode.LIGHTEN
取兩圖層全部,點(diǎn)亮交集部分顏色
15.PorterDuff.Mode.MULTIPLY
取兩圖層交集部分疊加后顏色
16.PorterDuff.Mode.SCREEN
取兩圖層全部區(qū)域,交集部分變?yōu)橥该魃?/p>
有沒(méi)有心動(dòng)了?好了。接下來(lái)就是看看如何實(shí)現(xiàn)的了。
新建一個(gè)名為ShapeViewDemo的項(xiàng)目。目錄如下:
在res的文件夾下新建一個(gè)名為attrs.xml文件用來(lái)定義自定義屬性。
1
2
3
4
5
6
7
8
9
接下來(lái)新建一個(gè)ShapeImageView.java
001packagecom.example.shapeimageviewdemo;
002
003importandroid.content.Context;
004importandroid.content.res.TypedArray;
005importandroid.graphics.Bitmap;
006importandroid.graphics.Canvas;
007importandroid.graphics.Paint;
008importandroid.graphics.Path;
009importandroid.graphics.PorterDuff;
010importandroid.graphics.PorterDuffXfermode;
011importandroid.graphics.Bitmap.Config;
012importandroid.graphics.drawable.BitmapDrawable;
013importandroid.graphics.drawable.Drawable;
014importandroid.graphics.drawable.NinePatchDrawable;
015importandroid.util.AttributeSet;
016importandroid.widget.ImageView;
017
018/**
019*
020* @author Joker_Ya
021*
022*/
023publicclassShapeImageViewextendsImageView {
024
025privateContext mContext;
026
027privateintborder_size =0;// 邊框厚度
028privateintin_border_color =0;// 內(nèi)圓邊框顏色
029privateintout_border_color =0;// 外圓邊框顏色
030privateintdefColor =0xFFFFFFFF;// 默認(rèn)顏色
031
032privateintwidth =0;// 控件的寬度
033privateintheight =0;// 控件的高度
034
035privateString shape_type;// 形狀的類(lèi)型
036
037publicShapeImageView(Context context) {
038super(context);
039// TODO Auto-generated constructor stub
040this.mContext = context;
041}
042
043publicShapeImageView(Context context, AttributeSet attrs) {
044super(context, attrs);
045// TODO Auto-generated constructor stub
046this.mContext = context;
047setAttributes(attrs);
048}
049
050publicShapeImageView(Context context, AttributeSet attrs,intdefStyle) {
051super(context, attrs, defStyle);
052// TODO Auto-generated constructor stub
053this.mContext = context;
054setAttributes(attrs);
055}
056
057/**
058* 獲得自定義屬性
059*
060* @param attrs
061*/
062privatevoidsetAttributes(AttributeSet attrs) {
063// TODO Auto-generated method stub
064TypedArray mArray = mContext.obtainStyledAttributes(attrs,
065R.styleable.shapeimageview);
066// 得到邊框厚度,否則返回0
067border_size = mArray.getDimensionPixelSize(
068R.styleable.shapeimageview_border_size,0);
069// 得到內(nèi)邊框顏色,否則返回默認(rèn)顏色
070in_border_color = mArray.getColor(
071R.styleable.shapeimageview_in_border_color, defColor);
072// 得到外邊框顏色,否則返回默認(rèn)顏色
073out_border_color = mArray.getColor(
074R.styleable.shapeimageview_out_border_color, defColor);
075// 得到形狀的類(lèi)型
076shape_type = mArray.getString(R.styleable.shapeimageview_shape_type);
077
078mArray.recycle();// 回收mArray
079}
080
081@Override
082protectedvoidonDraw(Canvas canvas) {
083// TODO Auto-generated method stub
084// super.onDraw(canvas); 必須去掉該行或注釋掉,否則會(huì)出現(xiàn)兩張圖片
085// 得到傳入的圖片
086Drawable drawable = getDrawable();
087if(drawable ==null) {
088return;
089}
090if(getWidth() ==0|| getHeight() ==0) {
091return;
092}
093this.measure(0,0);
094if(drawable.getClass() == NinePatchDrawable.class) {// 如果該傳入圖片是.9格式的圖片
095return;
096}
097
098// 將圖片轉(zhuǎn)為位圖
099Bitmap mBitmap = ((BitmapDrawable) drawable).getBitmap();
100
101Bitmap cpBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888,true);
102// 得到畫(huà)布寬高
103width = getWidth();
104height = getHeight();
105
106intradius =0;//
107// 判斷是否是圓形
108if("round".equals(shape_type)) {
109// 如果內(nèi)圓邊框和外圓邊框的顏色不等于默認(rèn)顏色,則說(shuō)明該圓有兩個(gè)邊框
110if(in_border_color != defColor && out_border_color != defColor) {
111// 計(jì)算出半徑
112radius = (width < height ? width : height) /2-2
113* border_size;
114// 畫(huà)內(nèi)圓邊框
115drawCircleBorder(canvas, radius + border_size /2,
116in_border_color);
117// 畫(huà)外圓邊框
118drawCircleBorder(canvas,
119radius + border_size + border_size /2,
120out_border_color);
121}// 如果內(nèi)圓邊框顏色不等于默認(rèn)顏色,則說(shuō)明該圓有一個(gè)邊框
122elseif(in_border_color != defColor
123&& out_border_color == defColor) {
124radius = (width < height ? width : height) /2- border_size;
125
126drawCircleBorder(canvas, radius + border_size /2,
127in_border_color);
128}// 如果外圓邊框顏色不等于默認(rèn)顏色,則說(shuō)明該圓有一個(gè)邊框
129elseif(in_border_color == defColor
130&& out_border_color != defColor) {
131radius = (width < height ? width : height) /2- border_size;
132
133drawCircleBorder(canvas, radius + border_size /2,
134out_border_color);
135}else{// 沒(méi)有邊框
136radius = (width < height ? width : height) /2;
137}
138}else{
139radius = (width < height ? width : height) /2;
140}
141
142Bitmap shapeBitmap = drawShapeBitmap(cpBitmap, radius);
143canvas.drawBitmap(shapeBitmap, width /2- radius, height /2- radius,
144null);
145}
146
147/**
148* 畫(huà)出指定形狀的圖片
149*
150* @param cpBitmap
151* @param radius
152* @return
153*/
154privateBitmap drawShapeBitmap(Bitmap bmp,intradius) {
155// TODO Auto-generated method stub
156Bitmap squareBitmap;// 根據(jù)傳入的位圖截取合適的正方形位圖
157Bitmap scaledBitmap;// 根據(jù)diameter對(duì)截取的正方形位圖進(jìn)行縮放
158intdiameter = radius *2;
159// 傳入位圖的寬高
160intw = bmp.getWidth();
161inth = bmp.getHeight();
162// 為了防止寬高不相等,造成圓形圖片變形,因此截取長(zhǎng)方形中處于中間位置最大的正方形圖片
163intsquarewidth =0, squareheight =0;// 矩形的寬高
164intx =0, y =0;
165if(h > w) {// 如果高>寬
166squarewidth = squareheight = w;
167x =0;
168y = (h - w) /2;
169// 截取正方形圖片
170squareBitmap = Bitmap.createBitmap(bmp, x, y, squarewidth,
171squareheight);
172}elseif(h < w) {// 如果寬>高
173squarewidth = squareheight = h;
174x = (w - h) /2;
175y =0;
176squareBitmap = Bitmap.createBitmap(bmp, x, y, squarewidth,
177squareheight);
178}else{
179squareBitmap = bmp;
180}
181// 對(duì)squareBitmap進(jìn)行縮放為diameter邊長(zhǎng)的正方形位圖
182if(squareBitmap.getWidth() != diameter
183|| squareBitmap.getHeight() != diameter) {
184scaledBitmap = Bitmap.createScaledBitmap(squareBitmap, diameter,
185diameter,true);
186}else{
187scaledBitmap = squareBitmap;
188}
189
190Bitmap outputbmp = Bitmap.createBitmap(scaledBitmap.getWidth(),
191scaledBitmap.getHeight(), Config.ARGB_8888);
192Canvas canvas =newCanvas(outputbmp);// 創(chuàng)建一個(gè)相同大小的畫(huà)布
193Paint paint =newPaint();// 定義畫(huà)筆
194paint.setAntiAlias(true);// 設(shè)置抗鋸齒
195paint.setFilterBitmap(true);
196paint.setDither(true);
197canvas.drawARGB(0,0,0,0);
198
199if("star".equals(shape_type)) {// 如果繪制的形狀為五角星形
200Path path =newPath();
201floatradian = degree2Radian(36);// 36為五角星的角度
202floatradius_in = (float) (radius * Math.sin(radian /2) / Math
203.cos(radian));// 中間五邊形的半徑
204
205path.moveTo((float) (radius * Math.cos(radian /2)),0);// 此點(diǎn)為多邊形的起點(diǎn)
206path.lineTo((float) (radius * Math.cos(radian /2) + radius_in
207* Math.sin(radian)),
208(float) (radius - radius * Math.sin(radian /2)));
209path.lineTo((float) (radius * Math.cos(radian /2) *2),
210(float) (radius - radius * Math.sin(radian /2)));
211path.lineTo((float) (radius * Math.cos(radian /2) + radius_in
212* Math.cos(radian /2)),
213(float) (radius + radius_in * Math.sin(radian /2)));
214path.lineTo(
215(float) (radius * Math.cos(radian /2) + radius
216* Math.sin(radian)), (float) (radius + radius
217* Math.cos(radian)));
218path.lineTo((float) (radius * Math.cos(radian /2)),
219(float) (radius + radius_in));
220path.lineTo(
221(float) (radius * Math.cos(radian /2) - radius
222* Math.sin(radian)), (float) (radius + radius
223* Math.cos(radian)));
224path.lineTo((float) (radius * Math.cos(radian /2) - radius_in
225* Math.cos(radian /2)),
226(float) (radius + radius_in * Math.sin(radian /2)));
227path.lineTo(0, (float) (radius - radius * Math.sin(radian /2)));
228path.lineTo((float) (radius * Math.cos(radian /2) - radius_in
229* Math.sin(radian)),
230(float) (radius - radius * Math.sin(radian /2)));
231
232path.close();// 使這些點(diǎn)構(gòu)成封閉的多邊形
233canvas.drawPath(path, paint);
234}elseif("triangle".equals(shape_type)) {// 如果繪制的形狀為三角形
235Path path =newPath();
236
237path.moveTo(0,0);
238path.lineTo(diameter /2, diameter);
239path.lineTo(diameter,0);
240
241path.close();
242canvas.drawPath(path, paint);
243}elseif("heart".equals(shape_type)) {// 如果繪制的形狀為心形
244Path path =newPath();
245
246path.moveTo(diameter /2, diameter /5);
247path.quadTo(diameter,0, diameter /2, diameter /1.0f);
248path.quadTo(0,0, diameter /2, diameter /5);
249
250path.close();
251canvas.drawPath(path, paint);
252}else{// 這是默認(rèn)形狀,圓形
253// 繪制圓形
254canvas.drawCircle(scaledBitmap.getWidth() /2,
255scaledBitmap.getHeight() /2, scaledBitmap.getWidth() /2,
256paint);
257}
258// 設(shè)置Xfermode的Mode
259paint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC_IN));
260canvas.drawBitmap(scaledBitmap,0,0, paint);
261
262bmp =null;
263squareBitmap =null;
264scaledBitmap =null;
265returnoutputbmp;
266
267}
268
269/**
270* 角度轉(zhuǎn)弧度公式
271*
272* @param degree
273* @return
274*/
275privatefloatdegree2Radian(intdegree) {
276// TODO Auto-generated method stub
277return(float) (Math.PI * degree /180);
278}
279
280/**
281* 如果圖片為圓形,這該方法為畫(huà)出圓形圖片的有色邊框
282*
283* @param canvas
284* @param radius 邊框半徑
285* @param color 邊框顏色
286*/
287privatevoiddrawCircleBorder(Canvas canvas,intradius,intcolor) {
288// TODO Auto-generated method stub
289Paint paint =newPaint();
290
291paint.setAntiAlias(true);// 抗鋸齒
292paint.setFilterBitmap(true);
293paint.setDither(true);
294paint.setColor(color);// 設(shè)置畫(huà)筆顏色
295paint.setStyle(Paint.Style.STROKE);// 設(shè)置畫(huà)筆的style為STROKE:空心
296paint.setStrokeWidth(border_size);// 設(shè)置畫(huà)筆的寬度
297// 畫(huà)出空心圓,也就是邊框
298canvas.drawCircle(width /2, height /2, radius, paint);
299}
300
301}
好了,ShapeImageView.java寫(xiě)完了,有沒(méi)有發(fā)現(xiàn)其原理很簡(jiǎn)單呢?在此過(guò)程中有一點(diǎn)大家要注意一下,那就是我們重寫(xiě)Ondraw(Canvas canvas)方法時(shí)一定要把super.onDraw(canvas);注釋掉或去掉,否則會(huì)出現(xiàn)兩張圖片疊在一起。不要問(wèn)我為什么。
最后附上Activity_main.xml
01http://schemas.android.com/apk/res/android"
02xmlns:myview="http://schemas.android.com/apk/res-auto"
03xmlns:tools="http://schemas.android.com/tools"
04android:layout_width="match_parent"
05android:layout_height="match_parent"
06android:paddingBottom="@dimen/activity_vertical_margin"
07android:paddingLeft="@dimen/activity_horizontal_margin"
08android:paddingRight="@dimen/activity_horizontal_margin"
09android:paddingTop="@dimen/activity_vertical_margin"
10android:orientation="vertical"
11tools:context=".MainActivity">
12
13
14android:layout_width="60dip"
15android:layout_height="60dip"
16android:src="@drawable/girl"
17/>
18
19
20android:layout_width="80dip"
21android:layout_height="80dip"
22android:layout_marginTop="10dip"
23android:src="@drawable/girl"
24myview:shape_type="triangle"
25/>
26
27
28android:layout_width="100dip"
29android:layout_height="100dip"
30android:layout_marginTop="10dip"
31android:src="@drawable/girl"
32myview:shape_type="star"
33/>
34
35
36android:layout_width="100dip"
37android:layout_height="100dip"
38android:layout_marginTop="10dip"
39android:src="@drawable/girl"
40myview:border_size="2dip"
41myview:in_border_color="#EE0000"
42myview:out_border_color="#00EEEE"
43myview:shape_type="round"
44/>
45
46
47android:layout_width="100dip"
48android:layout_height="100dip"
49android:layout_marginTop="10dip"
50android:src="@drawable/girl"
51myview:shape_type="heart"
52/>
53
由于用到了自定義屬性,因此要在主layout里加上x(chóng)mlns:myview="http://schemas.android.com/apk/res-auto",否則會(huì)報(bào)錯(cuò)。
至此,如何將一張圖片弄成三角,五角,圓形或心形的圖片的全部技術(shù)就給大家講解了。希望對(duì)大家有所幫助,也希望大家能理解。當(dāng)然不僅僅是三角,五角,圓形或心形的形狀。只要你想的到的都能弄出來(lái)(特殊形狀的圖片除外),就看你敢不敢了。
由于本人是第一次寫(xiě)博客,如果文中有什么地方出現(xiàn)錯(cuò)誤或不理解的可以在下面回復(fù)中指出來(lái)。謝謝
下面是源碼下載地址:
ShapeImageViewDemo轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://www.aiuxian.com/article/p-1982467.html
好吧,寫(xiě)之前扯扯。如果是大神的話(huà),可以忽略此文檔。有興趣的話(huà)也可以看看。這是本人的第一篇技術(shù)博客吧(話(huà)說(shuō)也談不上是什么特別的技術(shù)
)!因?yàn)橹霸趯?xiě)一個(gè)項(xiàng)目需要用到圖片。但是把一張圖片原封不動(dòng)的src入ImageView里面去,看起來(lái)怪別扭的。因此不想走平民路線(xiàn),于是就冒出來(lái)想把圖片弄成三角形的,五角星或圓形的想法。說(shuō)干就干,所以趕緊上網(wǎng)查了查怎么實(shí)現(xiàn)該想法。在此過(guò)程中也發(fā)現(xiàn)了很多問(wèn)題,所以今天寫(xiě)出來(lái)和大家分享一下。本文是根據(jù)大牛鴻洋和alan_biao的博客編寫(xiě)粗來(lái)的。原理都和他們的一樣,只是在圖形上改了改,改成能畫(huà)出三角形,五角星,心形的形狀。大家可以去看看他們得博客,寫(xiě)的都很不錯(cuò)的。鴻洋的博客:鏈接地址alan_biao的博客:鏈接地址好吧就扯到這里吧!!寫(xiě)這篇博客的目的一個(gè)是為了和大家分享,另一個(gè)就是記錄自己的收獲和成長(zhǎng)。
接下來(lái)就是如何實(shí)現(xiàn)的了。啥也不說(shuō)了,先上圖:
首先是原圖:
接下來(lái)就是效果圖了:
怎么樣?是不是比什么都不弄直接src進(jìn)去的要好呢?根據(jù)該方法大家可以實(shí)現(xiàn)最新版QQ的消息列表界面:
說(shuō)了那么多了,還沒(méi)給你們講講是怎么樣的一個(gè)原理呢!接下來(lái)就給大家講解一下實(shí)現(xiàn)該功能的原理:
其實(shí)主要是靠畫(huà)筆paint中的一個(gè)方法:paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));來(lái)實(shí)現(xiàn)的。
下面簡(jiǎn)單的介紹下Xfermode和PorterDuffXfermode:
該Mode是設(shè)置兩張圖片相交時(shí)的模式。
在正常的情況下,在已有的圖像上繪圖將會(huì)在其上面添加一層新的形狀。如果新的Paint是完全不透明的, 那么它將完全遮擋住下面的Paint;如果它是部分透明的,那么它將會(huì)被染上下面的顏色。
而setXfermode就可以來(lái)解決這個(gè)問(wèn)題 .
1Canvas canvas =newCanvas(dstBitmap);
2paint.setXfermode(newPorterDuffXfermode(Mode.SRC_IN));
3canvas.drawBitmap(srcBitmap, 0f, 0f, paint);
canvas原有的圖片可以理解為背景,就是dst;
新畫(huà)上去的圖片可以理解為前景,就是src。
下圖可以讓大家更好的理解PorterDuffXfermode的Mode:
從上面我們可以看到PorterDuff.Mode為枚舉類(lèi),一共有16個(gè)枚舉值:
1.PorterDuff.Mode.CLEAR
所繪制不會(huì)提交到畫(huà)布上。
2.PorterDuff.Mode.SRC
顯示上層繪制圖片
3.PorterDuff.Mode.DST
顯示下層繪制圖片
4.PorterDuff.Mode.SRC_OVER
正常繪制顯示,上下層繪制疊蓋。
5.PorterDuff.Mode.DST_OVER
上下層都顯示。下層居上顯示。
6.PorterDuff.Mode.SRC_IN
取兩層繪制交集。顯示上層。
7.PorterDuff.Mode.DST_IN
取兩層繪制交集。顯示下層。
8.PorterDuff.Mode.SRC_OUT
取上層繪制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下層繪制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下層非交集部分與上層交集部分
11.PorterDuff.Mode.DST_ATOP
取上層非交集部分與下層交集部分
12.PorterDuff.Mode.XOR
異或:去除兩圖層交集部分
13.PorterDuff.Mode.DARKEN
取兩圖層全部區(qū)域,交集部分顏色加深
14.PorterDuff.Mode.LIGHTEN
取兩圖層全部,點(diǎn)亮交集部分顏色
15.PorterDuff.Mode.MULTIPLY
取兩圖層交集部分疊加后顏色
16.PorterDuff.Mode.SCREEN
取兩圖層全部區(qū)域,交集部分變?yōu)橥该魃?/p>
有沒(méi)有心動(dòng)了?好了。接下來(lái)就是看看如何實(shí)現(xiàn)的了。
新建一個(gè)名為ShapeViewDemo的項(xiàng)目。目錄如下:
在res的文件夾下新建一個(gè)名為attrs.xml文件用來(lái)定義自定義屬性。
1
2
3
4
5
6
7
8
9
接下來(lái)新建一個(gè)ShapeImageView.java
001packagecom.example.shapeimageviewdemo;
002
003importandroid.content.Context;
004importandroid.content.res.TypedArray;
005importandroid.graphics.Bitmap;
006importandroid.graphics.Canvas;
007importandroid.graphics.Paint;
008importandroid.graphics.Path;
009importandroid.graphics.PorterDuff;
010importandroid.graphics.PorterDuffXfermode;
011importandroid.graphics.Bitmap.Config;
012importandroid.graphics.drawable.BitmapDrawable;
013importandroid.graphics.drawable.Drawable;
014importandroid.graphics.drawable.NinePatchDrawable;
015importandroid.util.AttributeSet;
016importandroid.widget.ImageView;
017
018/**
019*
020* @author Joker_Ya
021*
022*/
023publicclassShapeImageViewextendsImageView {
024
025privateContext mContext;
026
027privateintborder_size =0;// 邊框厚度
028privateintin_border_color =0;// 內(nèi)圓邊框顏色
029privateintout_border_color =0;// 外圓邊框顏色
030privateintdefColor =0xFFFFFFFF;// 默認(rèn)顏色
031
032privateintwidth =0;// 控件的寬度
033privateintheight =0;// 控件的高度
034
035privateString shape_type;// 形狀的類(lèi)型
036
037publicShapeImageView(Context context) {
038super(context);
039// TODO Auto-generated constructor stub
040this.mContext = context;
041}
042
043publicShapeImageView(Context context, AttributeSet attrs) {
044super(context, attrs);
045// TODO Auto-generated constructor stub
046this.mContext = context;
047setAttributes(attrs);
048}
049
050publicShapeImageView(Context context, AttributeSet attrs,intdefStyle) {
051super(context, attrs, defStyle);
052// TODO Auto-generated constructor stub
053this.mContext = context;
054setAttributes(attrs);
055}
056
057/**
058* 獲得自定義屬性
059*
060* @param attrs
061*/
062privatevoidsetAttributes(AttributeSet attrs) {
063// TODO Auto-generated method stub
064TypedArray mArray = mContext.obtainStyledAttributes(attrs,
065R.styleable.shapeimageview);
066// 得到邊框厚度,否則返回0
067border_size = mArray.getDimensionPixelSize(
068R.styleable.shapeimageview_border_size,0);
069// 得到內(nèi)邊框顏色,否則返回默認(rèn)顏色
070in_border_color = mArray.getColor(
071R.styleable.shapeimageview_in_border_color, defColor);
072// 得到外邊框顏色,否則返回默認(rèn)顏色
073out_border_color = mArray.getColor(
074R.styleable.shapeimageview_out_border_color, defColor);
075// 得到形狀的類(lèi)型
076shape_type = mArray.getString(R.styleable.shapeimageview_shape_type);
077
078mArray.recycle();// 回收mArray
079}
080
081@Override
082protectedvoidonDraw(Canvas canvas) {
083// TODO Auto-generated method stub
084// super.onDraw(canvas); 必須去掉該行或注釋掉,否則會(huì)出現(xiàn)兩張圖片
085// 得到傳入的圖片
086Drawable drawable = getDrawable();
087if(drawable ==null) {
088return;
089}
090if(getWidth() ==0|| getHeight() ==0) {
091return;
092}
093this.measure(0,0);
094if(drawable.getClass() == NinePatchDrawable.class) {// 如果該傳入圖片是.9格式的圖片
095return;
096}
097
098// 將圖片轉(zhuǎn)為位圖
099Bitmap mBitmap = ((BitmapDrawable) drawable).getBitmap();
100
101Bitmap cpBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888,true);
102// 得到畫(huà)布寬高
103width = getWidth();
104height = getHeight();
105
106intradius =0;//
107// 判斷是否是圓形
108if("round".equals(shape_type)) {
109// 如果內(nèi)圓邊框和外圓邊框的顏色不等于默認(rèn)顏色,則說(shuō)明該圓有兩個(gè)邊框
110if(in_border_color != defColor && out_border_color != defColor) {
111// 計(jì)算出半徑
112radius = (width < height ? width : height) /2-2
113* border_size;
114// 畫(huà)內(nèi)圓邊框
115drawCircleBorder(canvas, radius + border_size /2,
116in_border_color);
117// 畫(huà)外圓邊框
118drawCircleBorder(canvas,
119radius + border_size + border_size /2,
120out_border_color);
121}// 如果內(nèi)圓邊框顏色不等于默認(rèn)顏色,則說(shuō)明該圓有一個(gè)邊框
122elseif(in_border_color != defColor
123&& out_border_color == defColor) {
124radius = (width < height ? width : height) /2- border_size;
125
126drawCircleBorder(canvas, radius + border_size /2,
127in_border_color);
128}// 如果外圓邊框顏色不等于默認(rèn)顏色,則說(shuō)明該圓有一個(gè)邊框
129elseif(in_border_color == defColor
130&& out_border_color != defColor) {
131radius = (width < height ? width : height) /2- border_size;
132
133drawCircleBorder(canvas, radius + border_size /2,
134out_border_color);
135}else{// 沒(méi)有邊框
136radius = (width < height ? width : height) /2;
137}
138}else{
139radius = (width < height ? width : height) /2;
140}
141
142Bitmap shapeBitmap = drawShapeBitmap(cpBitmap, radius);
143canvas.drawBitmap(shapeBitmap, width /2- radius, height /2- radius,
144null);
145}
146
147/**
148* 畫(huà)出指定形狀的圖片
149*
150* @param cpBitmap
151* @param radius
152* @return
153*/
154privateBitmap drawShapeBitmap(Bitmap bmp,intradius) {
155// TODO Auto-generated method stub
156Bitmap squareBitmap;// 根據(jù)傳入的位圖截取合適的正方形位圖
157Bitmap scaledBitmap;// 根據(jù)diameter對(duì)截取的正方形位圖進(jìn)行縮放
158intdiameter = radius *2;
159// 傳入位圖的寬高
160intw = bmp.getWidth();
161inth = bmp.getHeight();
162// 為了防止寬高不相等,造成圓形圖片變形,因此截取長(zhǎng)方形中處于中間位置最大的正方形圖片
163intsquarewidth =0, squareheight =0;// 矩形的寬高
164intx =0, y =0;
165if(h > w) {// 如果高>寬
166squarewidth = squareheight = w;
167x =0;
168y = (h - w) /2;
169// 截取正方形圖片
170squareBitmap = Bitmap.createBitmap(bmp, x, y, squarewidth,
171squareheight);
172}elseif(h < w) {// 如果寬>高
173squarewidth = squareheight = h;
174x = (w - h) /2;
175y =0;
176squareBitmap = Bitmap.createBitmap(bmp, x, y, squarewidth,
177squareheight);
178}else{
179squareBitmap = bmp;
180}
181// 對(duì)squareBitmap進(jìn)行縮放為diameter邊長(zhǎng)的正方形位圖
182if(squareBitmap.getWidth() != diameter
183|| squareBitmap.getHeight() != diameter) {
184scaledBitmap = Bitmap.createScaledBitmap(squareBitmap, diameter,
185diameter,true);
186}else{
187scaledBitmap = squareBitmap;
188}
189
190Bitmap outputbmp = Bitmap.createBitmap(scaledBitmap.getWidth(),
191scaledBitmap.getHeight(), Config.ARGB_8888);
192Canvas canvas =newCanvas(outputbmp);// 創(chuàng)建一個(gè)相同大小的畫(huà)布
193Paint paint =newPaint();// 定義畫(huà)筆
194paint.setAntiAlias(true);// 設(shè)置抗鋸齒
195paint.setFilterBitmap(true);
196paint.setDither(true);
197canvas.drawARGB(0,0,0,0);
198
199if("star".equals(shape_type)) {// 如果繪制的形狀為五角星形
200Path path =newPath();
201floatradian = degree2Radian(36);// 36為五角星的角度
202floatradius_in = (float) (radius * Math.sin(radian /2) / Math
203.cos(radian));// 中間五邊形的半徑
204
205path.moveTo((float) (radius * Math.cos(radian /2)),0);// 此點(diǎn)為多邊形的起點(diǎn)
206path.lineTo((float) (radius * Math.cos(radian /2) + radius_in
207* Math.sin(radian)),
208(float) (radius - radius * Math.sin(radian /2)));
209path.lineTo((float) (radius * Math.cos(radian /2) *2),
210(float) (radius - radius * Math.sin(radian /2)));
211path.lineTo((float) (radius * Math.cos(radian /2) + radius_in
212* Math.cos(radian /2)),
213(float) (radius + radius_in * Math.sin(radian /2)));
214path.lineTo(
215(float) (radius * Math.cos(radian /2) + radius
216* Math.sin(radian)), (float) (radius + radius
217* Math.cos(radian)));
218path.lineTo((float) (radius * Math.cos(radian /2)),
219(float) (radius + radius_in));
220path.lineTo(
221(float) (radius * Math.cos(radian /2) - radius
222* Math.sin(radian)), (float) (radius + radius
223* Math.cos(radian)));
224path.lineTo((float) (radius * Math.cos(radian /2) - radius_in
225* Math.cos(radian /2)),
226(float) (radius + radius_in * Math.sin(radian /2)));
227path.lineTo(0, (float) (radius - radius * Math.sin(radian /2)));
228path.lineTo((float) (radius * Math.cos(radian /2) - radius_in
229* Math.sin(radian)),
230(float) (radius - radius * Math.sin(radian /2)));
231
232path.close();// 使這些點(diǎn)構(gòu)成封閉的多邊形
233canvas.drawPath(path, paint);
234}elseif("triangle".equals(shape_type)) {// 如果繪制的形狀為三角形
235Path path =newPath();
236
237path.moveTo(0,0);
238path.lineTo(diameter /2, diameter);
239path.lineTo(diameter,0);
240
241path.close();
242canvas.drawPath(path, paint);
243}elseif("heart".equals(shape_type)) {// 如果繪制的形狀為心形
244Path path =newPath();
245
246path.moveTo(diameter /2, diameter /5);
247path.quadTo(diameter,0, diameter /2, diameter /1.0f);
248path.quadTo(0,0, diameter /2, diameter /5);
249
250path.close();
251canvas.drawPath(path, paint);
252}else{// 這是默認(rèn)形狀,圓形
253// 繪制圓形
254canvas.drawCircle(scaledBitmap.getWidth() /2,
255scaledBitmap.getHeight() /2, scaledBitmap.getWidth() /2,
256paint);
257}
258// 設(shè)置Xfermode的Mode
259paint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC_IN));
260canvas.drawBitmap(scaledBitmap,0,0, paint);
261
262bmp =null;
263squareBitmap =null;
264scaledBitmap =null;
265returnoutputbmp;
266
267}
268
269/**
270* 角度轉(zhuǎn)弧度公式
271*
272* @param degree
273* @return
274*/
275privatefloatdegree2Radian(intdegree) {
276// TODO Auto-generated method stub
277return(float) (Math.PI * degree /180);
278}
279
280/**
281* 如果圖片為圓形,這該方法為畫(huà)出圓形圖片的有色邊框
282*
283* @param canvas
284* @param radius 邊框半徑
285* @param color 邊框顏色
286*/
287privatevoiddrawCircleBorder(Canvas canvas,intradius,intcolor) {
288// TODO Auto-generated method stub
289Paint paint =newPaint();
290
291paint.setAntiAlias(true);// 抗鋸齒
292paint.setFilterBitmap(true);
293paint.setDither(true);
294paint.setColor(color);// 設(shè)置畫(huà)筆顏色
295paint.setStyle(Paint.Style.STROKE);// 設(shè)置畫(huà)筆的style為STROKE:空心
296paint.setStrokeWidth(border_size);// 設(shè)置畫(huà)筆的寬度
297// 畫(huà)出空心圓,也就是邊框
298canvas.drawCircle(width /2, height /2, radius, paint);
299}
300
301}
好了,ShapeImageView.java寫(xiě)完了,有沒(méi)有發(fā)現(xiàn)其原理很簡(jiǎn)單呢?在此過(guò)程中有一點(diǎn)大家要注意一下,那就是我們重寫(xiě)Ondraw(Canvas canvas)方法時(shí)一定要把super.onDraw(canvas);注釋掉或去掉,否則會(huì)出現(xiàn)兩張圖片疊在一起。不要問(wèn)我為什么。
最后附上Activity_main.xml
01http://schemas.android.com/apk/res/android"
02xmlns:myview="http://schemas.android.com/apk/res-auto"
03xmlns:tools="http://schemas.android.com/tools"
04android:layout_width="match_parent"
05android:layout_height="match_parent"
06android:paddingBottom="@dimen/activity_vertical_margin"
07android:paddingLeft="@dimen/activity_horizontal_margin"
08android:paddingRight="@dimen/activity_horizontal_margin"
09android:paddingTop="@dimen/activity_vertical_margin"
10android:orientation="vertical"
11tools:context=".MainActivity">
12
13
14android:layout_width="60dip"
15android:layout_height="60dip"
16android:src="@drawable/girl"
17/>
18
19
20android:layout_width="80dip"
21android:layout_height="80dip"
22android:layout_marginTop="10dip"
23android:src="@drawable/girl"
24myview:shape_type="triangle"
25/>
26
27
28android:layout_width="100dip"
29android:layout_height="100dip"
30android:layout_marginTop="10dip"
31android:src="@drawable/girl"
32myview:shape_type="star"
33/>
34
35
36android:layout_width="100dip"
37android:layout_height="100dip"
38android:layout_marginTop="10dip"
39android:src="@drawable/girl"
40myview:border_size="2dip"
41myview:in_border_color="#EE0000"
42myview:out_border_color="#00EEEE"
43myview:shape_type="round"
44/>
45
46
47android:layout_width="100dip"
48android:layout_height="100dip"
49android:layout_marginTop="10dip"
50android:src="@drawable/girl"
51myview:shape_type="heart"
52/>
53
由于用到了自定義屬性,因此要在主layout里加上x(chóng)mlns:myview="http://schemas.android.com/apk/res-auto",否則會(huì)報(bào)錯(cuò)。
至此,如何將一張圖片弄成三角,五角,圓形或心形的圖片的全部技術(shù)就給大家講解了。希望對(duì)大家有所幫助,也希望大家能理解。當(dāng)然不僅僅是三角,五角,圓形或心形的形狀。只要你想的到的都能弄出來(lái)(特殊形狀的圖片除外),就看你敢不敢了。
由于本人是第一次寫(xiě)博客,如果文中有什么地方出現(xiàn)錯(cuò)誤或不理解的可以在下面回復(fù)中指出來(lái)。謝謝
下面是源碼下載地址: