Android中使用SVG矢量圖打造多邊形圖形框架#
最后要實現(xiàn)的最終效果如下圖:
1.準備工作
(1) 因為項目中需要用到SVG矢量圖,所以我們就需要一個將SVG圖像轉換為Bitmap的工具類:
如果下載的jar包直接在項目中引用就行,如果是源碼只需要將源碼放在項目中的包下即可,看看我AndroidStudio項目中源碼文件:
(2) 準備SVG矢量圖片,不清楚SVG圖片的童鞋可以到W3CSchool上面去了解下; 如果找不到SVG矢量圖的素材可以在 SVG在線編輯 上自己編輯一個SVG圖片。###
準備好的SVG圖片可以放在 res/raw
中(沒有就手動創(chuàng)建),也可以放在項目的asset中(沒有手動創(chuàng)建)
目錄 |
對應獲取SVG圖片的方法 |
raw |
SVGParser.getSVGFromInputStream() |
asset |
SVGParser.getSVGFromAsset() |
2.SVG加載到Android中
現(xiàn)在開始正式擼代碼 首先在項目中創(chuàng)建一個工具類:SvgBitmapUtils
在類中創(chuàng)建靜態(tài)方法getSvgBitmap
/**
* 主要是用來加載SVG矢量圖片,最后轉換成我們屬性的Bitmap格式
* @param context
* @param width SVG圖片的寬
* @param height SVG圖片的高
* @param resId SVG圖片的ID
* @return Bitmap
*/
public static Bitmap getSvgBitmap(Context context , int width,int height ,int resId){
//1.創(chuàng)建一個空的圖片
Bitmap bitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
//2.拿到空圖片的畫布:目前來講相當于一張白紙
Canvas canvas = new Canvas(bitmap);
//創(chuàng)建一直畫筆
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setDither(true);//防止畫筆抖動
paint.setColor(Color.BLACK);//畫筆顏色為黑色'
//當傳入的id是一個正常的ID
if (resId>0){
// 3.通過SVGParser來加載一個SVG圖片
// 加載raw目錄下的SVG文件
SVG svg = SVGParser.getSVGFromInputStream(context.getResources().openRawResource(resId),width,height);
// 4.將通過svg對象的getPicture()方法得到一個Picture對象,然后將Picture畫在畫布上
canvas.drawPicture(svg.getPicture());
}else {
//如果沒有找到SVG圖片就畫一個矩形
canvas.drawRect(new Rect(0,0,width,height),paint);
}
return bitmap;
}
接下來是Svg圖片與妹子的合并,所以首先準備一張妹子圖,因為我們合并和得到一張正方形的合并圖片,所以要先根據(jù)給定的妹子圖得到合并后圖片的寬(size),很明顯就是妹子圖片的寬或高中最小的一邊的長度:
int size = Math.min(fg.getWidth(),fg.getHeight());
然后根據(jù)這個寬(size)從妹子的原圖中切出一張正方形圖片,從原圖中切出一個正方形圖片需要知道切圖的起始位置(<font color="#ff3456">相對與圖片的左上角的位置:x,y</font>)
//2.確定截取正方形左上角的坐標
int x = (fg.getWidth()-size)/2;
int y = (fg.getHeight()-size)/2;
有了開始的Svg矢量圖和現(xiàn)在切出來的妹子圖;就可以開始合并圖片,可是要怎么樣才能合并出上面的那樣的效果;
先來看看官方給出圖片合并模式 來自ApiDemos/Graphics/XferModes):
從上圖可以看到PorterDuff.Mode為枚舉類,一共有16個枚舉值:
枚舉值 |
對應效果 |
1.PorterDuff.Mode.CLEAR |
所繪制不會提交到畫布上。 |
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 |
取兩圖層全部,點亮交集部分顏色。 |
15.PorterDuff.Mode.MULTIPLY |
取兩圖層交集部分疊加后顏色。 |
16.PorterDuff.Mode.SCREEN |
取兩圖層全部區(qū)域,交集部分變?yōu)橥该魃?/td>
|
根據(jù)我們的效果需要,很明顯選擇:
[10.PorterDuff.Mode.SRC_ATOP ] 取下層非交集部分與上層交集部分。;
現(xiàn)在我只需要把SVG圖片放下面,然后把妹子放上面,就能得到最終效果!
SVG跟妹子合并方法,也是我們最后在界面中使用的方法getSvgShapBitmap()
/**
* SVG跟妹子圖片進行合并
* @param context
* @param fg 原圖
* @param resId 矢量圖的(SVG)ID
* @return Bitmap
*/
public static Bitmap getSvgShapBitmap(Context context,Bitmap fg,int resId){
//1.確定截取原圖正方形的邊長 (以原圖中寬高最小的為邊長)
int size = Math.min(fg.getWidth(),fg.getHeight());
//2.確定截取正方形左上角的坐標
int x = (fg.getWidth()-size)/2;
int y = (fg.getHeight()-size)/2;
//裁剪妹子圖片
Bitmap girl = Bitmap.createBitmap(fg,x,y,size,size);
//3.獲得和正方形同樣大小的SVG圖片
Bitmap svg = getSvgBitmap(context,fg.getWidth(),fg.getHeight(),resId);
//創(chuàng)建畫筆
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setDither(true);//防止抖動
//4.SVG做底部圖片,妹子放上面,采用SRC_ATOP模式重疊
Bitmap bitmap = Bitmap.createBitmap(size,size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(svg,new Matrix(),paint);
//設置圖片重合模式
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
canvas.drawBitmap(girl,new Matrix(),paint);
return bitmap;
}
3.界面使用,直接顯示到ImageView##
MainActivity中的代碼:
public class MainActivity extends AppCompatActivity {
private Bitmap bitmap;
private ImageView ivImage;
private Button btnImage;
////加載多邊形SVG
private static int[] resIds = new int[]{
R.raw.ba,
R.raw.fengye,
R.raw.linxin,
R.raw.liu,
R.raw.meihua,
R.raw.pingguo,
R.raw.qi,
R.raw.qizi,
R.raw.tuzi,
R.raw.wujiaoxing,
R.raw.yezi,
};
int flag = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ivImage = (ImageView) this.findViewById(R.id.iv_image);
btnImage = (Button) this.findViewById(R.id.btn_image);
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.girl);//
//為了效果先顯示原圖
ivImage.setImageBitmap(bitmap);
btnImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
flag = flag % (resIds.length);
//得到合并后的圖片
Bitmap svgShapBitmap = SvgBitmapUtils.getSvgShapBitmap(MainActivity.this, bitmap, resIds[flag]);
ivImage.setImageBitmap(svgShapBitmap);
flag++;
}
});
}
代碼簡單,就不多說了,下面還是貼上XML代碼吧
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
android:layout_width="match_parent" android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:background="@color/colorAccent"
tools:context="zhengliang.com.svg_polygon_frame.MainActivity">
<ImageView
android:layout_width="250dp"
android:layout_height="250dp"
android:scaleType="centerCrop"
android:layout_centerInParent="true"
android:id="@+id/iv_image"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:id="@+id/btn_image"
android:background="#22FFFFFF"
android:text="加載妹子"/>
</RelativeLayout>
大工告成,最后小提示(SVG圖片的path路徑盡量使用封閉路徑,不然會出現(xiàn)奇葩效果!!)