在Android開發中,圓形圖片是很常見的,例如淘寶的寶貝,QQ的聯繫人頭像等都是圓形的圖片,
但是Android原生的ImageView又不能顯示圓形的圖片,這就需要我們自己去實現一個圓形圖了
一、自定義View實現圓形圖
1.1繼承ImageView
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* Created by ChenFengYao on 16/3/15.
*/
public class RoundImageView extends ImageView {
private Paint paint;
public RoundImageView(Context context) {
super(context);
paint = new Paint();//初始化畫筆對象
}
public RoundImageView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();//初始化畫筆對象
}
public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint();//初始化畫筆對象
}
}
繼承ImageView複寫其中的構造方法,並在構造方法裏對畫筆對象進行初始化
1.2複寫onDraw方法
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (null != drawable) {
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
//核心代碼
Bitmap b = getCircleBitmap(bitmap);
paint.reset();
canvas.drawBitmap(b,0,0,paint);
} else {
super.onDraw(canvas);
}
}
onDraw方法即圖片繪製的時候系統所調用的方法,在該方法內部首先去判斷是否設置了圖片的src,如果能拿到改View設置的圖片,則將它轉換成圓形圖片,如果沒有設置的話,則不做任何操作,直接調用父類的onDraw方法
1.2getCircleBitmap
private Bitmap getCircleBitmap(Bitmap bitmap){
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
Rect rect = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getHeight() / 2, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);//將圖片畫出來
return output;
}
這是獲取圓形圖的方法,目的是將我們自定義的View中的圖片,轉化成圓形的Bitmap,這裏需要Canvas對象,首先畫一個圓形的底層,再在其上放上我們的圖片,通過設置畫筆的paint的Xfermode屬性,該屬性是用來設置前後圖層的顯示關係的,這是設置Mode.SRC_IN,的意思是輸出的範圍是底層圖形的範圍,而顯示的內容是上層的內容
1.2.1paint.setXfermode()
PorterDuff.Mode.CLEAR |
所繪製不會提交到畫布上。 |
PorterDuff.Mode.SRC |
顯示上層繪製圖片 |
PorterDuff.Mode.DST |
顯示下層繪製圖片 |
PorterDuff.Mode.SRC_OVER |
正常繪製顯示,上下層繪製疊蓋 |
PorterDuff.Mode.DST_OVER |
上下層都顯示。下層居上顯示 |
PorterDuff.Mode.SRC_IN |
取兩層繪製交集。顯示上層 |
PorterDuff.Mode.DST_IN |
取兩層繪製交集。顯示下層 |
PorterDuff.Mode.SRC_OUT |
取上層繪製非交集部分 |
PorterDuff.Mode.DST_OUT |
取下層繪製非交集部分 |
PorterDuff.Mode.SRC_ATOP |
取下層非交集部分與上層交集部分 |
PorterDuff.Mode.DST_ATOP |
取上層非交集部分與下層交集部分 |
PorterDuff.Mode.XOR |
取兩層繪製非交集。兩層繪製非交集 |
PorterDuff.Mode.DARKEN |
上下層都顯示。變暗 |
PorterDuff.Mode.LIGHTEN |
上下層都顯示。變亮 |
PorterDuff.Mode.MULTIPLY |
取兩層繪製交集 |
PorterDuff.Mode.SCREEN |
上下層都顯示 |
1.2.2Canvas
1.3測試
<com.lanou.chenfengyao.temproundimageview.RoundImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/test_img"/>
1.4 添加功能
<resources>
<declare-styleable name="RoundImageView">
<attr name="is_round" format="boolean" />
</declare-styleable>
</resources>
private boolean isRound;
然後在構造方法裏提取這條屬性,如果沒有提取到,默認值設置爲true,讓它默認就可以顯示圓角圖片public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint();//初始化畫筆對象
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
isRound = typedArray.getBoolean(R.styleable.RoundImageView_is_round, true);
}
爲了增加實用性 我們改造一下剩下的構造方法public RoundImageView(Context context) {
this(context, null);
}
public RoundImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (null != drawable && isRound) {
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
//核心代碼
Bitmap b = getCircleBitmap(bitmap);
paint.reset();
canvas.drawBitmap(b, 0, 0, paint);
b.recycle();
} else {
super.onDraw(canvas);
}
}
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">測試一下,我們將我們的組件的is_round屬性改成false看看效果</span>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.lanou.chenfengyao.temproundimageview.MainActivity">
<com.lanou.chenfengyao.temproundimageview.RoundImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/test_img"
app:is_round="false"/>
</RelativeLayout>
注意,我們自定義的屬性,命名空間不要忘記了public void setIsRound(boolean isRound) {
this.isRound = isRound;
invalidate();
}
現在我們在Activity裏放上一個按鈕,點擊它切換顯示模式,來測試一下可以看到 我們的圖片可以通過Java代碼來動態的切換正常模式和圓形圖片啦
二、使用Fresco顯示圓形圖片
compile 'com.facebook.fresco:fresco:0.9.0+'
另外Fresco在使用的時候需要對其進行初始化,可以在需要的Activity裏的onCreate方法裏添加Fresco.initialize(this);
建議將這行代碼添加到Application裏進行全局的初始化<com.facebook.drawee.view.SimpleDraweeView
fresco:roundAsCircle = "true"
fresco:actualImageScaleType="centerInside"
fresco:roundingBorderColor="@color/colorAccent"
fresco:roundingBorderWidth="1dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
fresco:backgroundImage="@mipmap/test_img"/>
並且不要忘記命名空間xmlns:fresco="http://schemas.android.com/apk/res-auto"
看一下效果可以看到出現了圓形圖片,並且還有1dp的紅色邊框
2.1一些坑
三、利用sharp做圓形圖
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thicknessRatio="1"
android:useLevel="false"
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent" />
<stroke
android:width="68dp"
android:color="#FFFFFFFF" />
</shape>
讓shape是ring即環形,並且設置填充顏色爲白色,線寬需要根據圖片自己調整<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/test_img" />
<item android:drawable="@drawable/circle" />
</layer-list>
layer-list的意思是讓ImageView中顯示的圖片產生一個疊加的效果,越靠下寫的,在顯示的時候就越靠上層<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/round_layers"/>
看一下效果吧實際上,該方法的原理就是在正常的ImageView上再疊加了一個白色的環形圖形,這樣顯示的效果就是圓形圖片了.但是缺點也是顯而易見的,即需要手動的調節環形的粗細,比較難控制