圓形圖片的製作

近期又在啃《Android開發藝術探索》這本書,最近看到了第六章節—Android中的Drawable。我寫博客的風格不喜歡一味的介紹理論知識,更喜歡從實戰的角度去學習,在敲代碼的過程中去補充理論知識,根據實際情況做出分析,最後實現想要的效果。本文就從製作圓形頭像的角度,來學習Android中的Drawable的那些事。

一.準備工作
Drawable有很多種,表示的是一種可以在Canvas上進行繪製的抽象的概念,它的種類有很多種,最常見的顏色和圖片都可以是一個Drawable。它是所有Drawable對象的基類,每個具體的Drawable都是它的子類。比如下文提到的BitmapDrawable。

BitmapDrawable是一種最簡單的Drawable,它表示的就是一張圖片,在實際開發中應用也是最廣泛的,我們可以直接引用原始圖片即可獲取。

回到需求上,我們要製作一個圓形頭像,首先需要一張圖片,最終以圓形的方式展現出來。

這是我在網上找的一張圖片:

這裏寫圖片描述

製作圓形圖片,最理想的效果是原始圖片能夠是正方形的,這樣圖片裁剪成圓形以後纔會顯得對稱。而提供給我們的原始圖片很有可能不是正方形的,比如上圖,所以我們首先要加工這張圖片,使成爲正方形圖片。

佈局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_third"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="org.tyk.android.artstudy.ThirdActivity">


    <ImageView
        android:id="@+id/my_circle_img"
        android:layout_width="100dp"
        android:layout_height="150dp"
        android:layout_marginTop="10dp"
        android:src="@drawable/k" />


    <ImageView
        android:id="@+id/second_img"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginTop="10dp" />

    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="縮放" />

</LinearLayout>

佈局文件中,上面是我們的原始圖片,下面是我們處理以後的圖片,看看點擊事件做了什麼:

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {


                Bitmap bitmap = ((BitmapDrawable) myCircleImageView.getDrawable()).getBitmap();
                Matrix matrix = new Matrix();
                float size = Math.min(bitmap.getWidth(), bitmap.getHeight());
                //x縮放比例
                float x = size / bitmap.getWidth();
                //y縮放比例
                float y = size / bitmap.getHeight();
                matrix.setScale(x, y);
                Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
                img.setImageBitmap(newBitmap);
            }
        });

首先獲取當前ImageView的Bitmap,關於ImageView轉換爲Bitmap,大家可以參考這篇博客:

Android 怎麼把imageview 轉爲Bitmap

然後構造一個矩陣Matrix,計算並設置好縮放比例,然後調用

createBitmap(Bitmap source, int x, int y, int width, int height,
Matrix m, boolean filter)

方法生成新的Bitmap。看看這個方法具體幹了什麼:

這裏寫圖片描述

這是官方文檔解釋,source代表原始圖片的Bitmap;x,y代表X,Y方向上的起始位置;width,height代表X,Y方向需要處理的寬度與高度;m代表圖片處理的矩陣;,filter參數爲true表示進行濾波處理,有助於改善新圖像質量,flase代表不做過濾處理。

看看處理後的效果:

這裏寫圖片描述

OK,圖片的前期準備工作已經做好了,現在開始製作圓形頭像了。

二.XferMode方法制作圓形圖片
Xfermode有三個子類 :
AvoidXfermode ,PixelXorXfermode,PorterDuffXfermode,其中前兩個類在API 16被遺棄了 。PorterDuffXfermode類主要用於計算圖形合成時的圖像過渡模式 ,一共有16條規則。然後調用 paint.setXfermode(XferMode)方法設置圖像的過渡模式,這樣就可以完成一些複雜的效果。先看看有哪些模式:

這裏寫圖片描述

每種模式代表的含義如下:
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
取兩圖層全部區域,交集部分顏色加深
14.PorterDuff.Mode.LIGHTEN
取兩圖層全部,點亮交集部分顏色
15.PorterDuff.Mode.MULTIPLY
取兩圖層交集部分疊加後顏色
16.PorterDuff.Mode.SCREEN
取兩圖層全部區域,交集部分變爲透明色

大家也可以參考這篇文章:

各個擊破搞明白PorterDuff.Mode

這裏我們結合圓形圖像的例子看看怎麼使用:

                //縮放以後的bitmap
                Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
                int width = newBitmap.getWidth();
                int height = newBitmap.getHeight();
                //圓形bitmap
                Bitmap circleBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(circleBitmap);
                Paint paint = new Paint();
                paint.setAntiAlias(true);
                paint.setColor(Color.BLACK);
                canvas.drawCircle(width / 2, height / 2, width / 2, paint);
                PorterDuffXfermode porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
                paint.setXfermode(porterDuffXfermode);
                canvas.drawBitmap(newBitmap, 0, 0, paint);
                circleImg.setImageBitmap(circleBitmap);

得到縮放以後的Bitmap以後,創建一個Canvas對象,首先繪製了一個黑色實心圓,然後設置Xfermode爲PorterDuff.Mode.SRC_IN,最後繪製縮放以後的Bitmap。根據這種模式的定義:取兩層繪製交集並顯示上層,可以得到我們的圓形頭像。最後實現的效果如下:

這裏寫圖片描述

三.BitmapShader方法制作圓形圖片

BitmapShader是Shader的子類,可以通過Paint.setShader(Shader shader)進行設置,BitmapShader的構造方法如下:

mBitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);

參數1:bitmap
參數2,參數3:TileMode;
TileMode的取值有三種:
CLAMP 拉伸 拉伸的是圖片最後的那一個像素;橫向的最後一個橫行像素,不斷的重複,縱項的那一列像素,不斷的重複
REPEAT 重複 就是橫向、縱向不斷重複這個bitmap
MIRROR 鏡像 橫向不斷翻轉重複,縱向不斷翻轉重複

關於BitmapShader可參考:
自定義控件其實很簡單1/3

這裏我們結合圓形圖像的例子看看怎麼使用:

                //縮放以後的bitmap
                Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
                int width = newBitmap.getWidth();
                int height = newBitmap.getHeight();

                //圓形bitmap
                Bitmap circleBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(circleBitmap);
                Paint paint = new Paint();
                paint.setAntiAlias(true);
                paint.setColor(Color.BLACK);
                /**第一種方式**/
//                canvas.drawCircle(width / 2, height / 2, width / 2, paint);
//                PorterDuffXfermode porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
//                paint.setXfermode(porterDuffXfermode);
//                canvas.drawBitmap(newBitmap, 0, 0, paint);
                /**第二種方式**/
                BitmapShader bitmapShader = new BitmapShader(newBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
                paint.setShader(bitmapShader);
                canvas.drawCircle(width / 2, height / 2, width / 2, paint);
                circleImg.setImageBitmap(circleBitmap);

得到縮放以後的Bitmap以後,創建一個Canvas對象,初始化BitmapShader,畫筆設置Shader,最後在canvas裏面進行畫圓就行了。效果與第一種方式實現的一樣,就不重複貼圖了。

四.ClipPath方法制作圓形圖片

使用clipPath的方法進行切割,來實現圓角圖片,具體可參考:

Path圖形與邏輯運算

這裏我們結合圓形圖像的例子看看怎麼使用:

                //縮放以後的bitmap
                Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
                int width = newBitmap.getWidth();
                int height = newBitmap.getHeight();

                //圓形bitmap
                Bitmap circleBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(circleBitmap);
                Paint paint = new Paint();
                paint.setAntiAlias(true);
                paint.setColor(Color.BLACK);
                /**第一種方式**/
//                canvas.drawCircle(width / 2, height / 2, width / 2, paint);
//                PorterDuffXfermode porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
//                paint.setXfermode(porterDuffXfermode);
//                canvas.drawBitmap(newBitmap, 0, 0, paint);
                /**第二種方式**/
//                BitmapShader bitmapShader = new BitmapShader(newBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//                paint.setShader(bitmapShader);
//                canvas.drawCircle(width / 2, height / 2, width / 2, paint);
//                circleImg.setImageBitmap(circleBitmap);
                /**第三種方式**/
                Path path = new Path();
                //按照順時針方向添加一個圓
                path.addCircle(width / 2, height / 2, width / 2, Path.Direction.CW);
                canvas.save();
                //設置爲在圓形區域內繪製
                canvas.clipPath(path);
                canvas.drawBitmap(newBitmap, 0, 0, paint);
                canvas.restore();
                circleImg.setImageBitmap(circleBitmap);

得到縮放以後的Bitmap以後,創建一個Canvas對象,設置爲在圓形區域內繪製,最後在canvas裏面繪製Bitmap。效果與第一種方式實現的一樣,就不重複貼圖了。

當然,要實現其他形狀圖片,其實很簡單,每種方法稍微改變一下就行,只要先繪製出不同的形狀,原理還是和這個一樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章