今天突然看到自己的發(fā)泥盒(一個(gè)六邊形的盒子)查剖,所以突發(fā)奇想想封裝一個(gè)這樣的ImageView控件飒泻,之后用鞭光,有什么用吏廉,不告訴你泞遗。發(fā)泥盒我就不發(fā)照片了,以免認(rèn)為我在做廣告席覆。
PS:我只寫干貨史辙,如果你發(fā)現(xiàn)文中有不是干貨的地方,你就當(dāng)沒看見佩伤。
題目可能有些不清楚聊倔,其實(shí)是要實(shí)現(xiàn)一個(gè)正六邊形的ImageView。感覺這個(gè)也沒什么好寫的生巡。圓形呀耙蔑,圓角矩形呀,類似的這些基本都寫爛了孤荣,你就隨便看看好了甸陌。
實(shí)現(xiàn)這個(gè)東西须揣,本人想到兩種方法:
- Xformode
- Shader
Xformode可以說是處理這種萬能的方法。用過的應(yīng)該都懂钱豁。但是它的性能不高耻卡,因?yàn)槊看味妓媰纱危粋€(gè)蒙板一個(gè)原圖牲尺,然后兩個(gè)圖疊加做相應(yīng)的計(jì)算卵酪。所以如果不是其他方法都不行,我是絕對不會用它的谤碳。
那么Shader貌似是一個(gè)好的方案溃卡,但是Shader就是需要自己想辦法畫出一個(gè)正六邊形了。這個(gè)時(shí)候我內(nèi)心OS了一下估蹄∷芗澹靠,我要是畫不出個(gè)正六邊形臭蚁,我就不做Android了!
正六邊形畫法
在Android中的畫法和現(xiàn)實(shí)中的畫法基本差不多最铁。這個(gè)其實(shí)看成一個(gè)簡單的多邊形,使用Android中的Path就好了垮兑。只是需要確定幾個(gè)關(guān)鍵點(diǎn)的坐標(biāo)冷尉。這里我們假設(shè)寬度撐滿。高度居中系枪。那么我們的代碼基本就是這個(gè)樣子:
正六邊形的邊長l就是寬的一半雀哨,正六邊形的高是 Math.sqrt(3)*l
,然后可以算出正六邊形頂部的top值私爷,之后只要依次遍歷連接每個(gè)點(diǎn)雾棺,即可畫出正六邊形。
代碼如下:
float l = (float) (getWidth() / 2);
float h = (float) (Math.sqrt(3)*l);
float top = (getHeight() - h) / 2 ;
mPath.reset();
mPath.moveTo(l/2,top);
mPath.lineTo(0,h/2+top);
mPath.lineTo(l/2,h+top);
mPath.lineTo((float) (l*1.5),h+top);
mPath.lineTo(2*l,h/2+top);
mPath.lineTo((float) (l*1.5),top);
mPath.lineTo(l/2,top);
mPath.close();
設(shè)置Shader
對于Shader還不了解的人衬浑,可以去搜一搜其他博客捌浩,講這個(gè)的已經(jīng)很多了,我就不再講一遍了工秩。這里我們使用的是BitmapShader尸饺,這個(gè)類名副其實(shí),它可以把一個(gè)Bitmap做為我們的渲染對象助币,在設(shè)置Bitmap的時(shí)候把Bitmap初始化BitmapShader浪听,然后設(shè)置給Paint。直接上代碼了眉菱。
// 先把要設(shè)置的bitmap設(shè)置給一個(gè)BitmapShader
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) ;
// 然后給Paint設(shè)置shader
mPaint.setShader(shader) ;
使用Shader繪制正六邊形
我們重寫onDraw方法:
@Override
public void onDraw(Canvas canvas) {
canvas.drawPath(mPath,mPaint);
}
看下效果:
封裝到Drawable中
寫完之后迹栓,發(fā)現(xiàn)功能簡單相對獨(dú)立,沒有使用自定義View的必要俭缓,因此將其封裝成Drawable克伊,使用起來也將更加方便叉抡。代碼如下:
public class HiveDrawable extends Drawable {
// 用于記錄邊界信息的Rect
Rect mRect = new Rect();
Paint mPaint;
Path mPath ;
BitmapShader mShader;
Bitmap mBitmap ;
public HiveDrawable() {
this(null) ;
}
public HiveDrawable(Bitmap bitmap) {
init();
setBitmap(bitmap);
}
private void init() {
initPaint() ;
initPath() ;
}
private void ensurePaint(){
if (mPaint == null) {
mPaint = new Paint() ;
}
}
private void ensurePath(){
if (mPath == null) {
mPath = new Path() ;
}
}
private void initPaint() {
ensurePaint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(3f);
}
public Bitmap getBitmap() {
return mBitmap;
}
// 設(shè)置Bitmap的時(shí)候初始化shader,并設(shè)置給paint
public void setBitmap(Bitmap bitmap) {
this.mBitmap = bitmap;
if (bitmap == null) {
mShader =null ;
} else {
mShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) ;
mPaint.setShader(mShader) ;
}
}
// 初始化好Path要走的路徑
private void initPath() {
ensurePath();
float l = (float) (mRect.width() / 2);
float h = (float) (Math.sqrt(3)*l);
float top = (mRect.height() - h) / 2 ;
mPath.reset();
mPath.moveTo(l/2,top);
mPath.lineTo(0,h/2+top);
mPath.lineTo(l/2,h+top);
mPath.lineTo((float) (l*1.5),h+top);
mPath.lineTo(2*l,h/2+top);
mPath.lineTo((float) (l*1.5),top);
mPath.lineTo(l/2,top);
mPath.close();
}
@Override
public void draw(Canvas canvas) {
canvas.drawPath(mPath,mPaint);
}
@Override
public void setAlpha(int alpha) {
if (mPaint != null) {
mPaint.setAlpha(alpha);
}
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
if (mPaint != null) {
mPaint.setColorFilter(colorFilter) ;
}
}
@Override
public int getOpacity() {
return 0 ;
}
// 設(shè)置邊界信息
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
mRect.set(left, top, right, bottom);
initPath();
}
@Override
public int getIntrinsicWidth() {
if (mBitmap != null) {
return mBitmap.getWidth();
} else {
return super.getIntrinsicWidth() ;
}
}
@Override
public int getIntrinsicHeight() {
if (mBitmap != null) {
return mBitmap.getHeight() ;
}
return super.getIntrinsicHeight();
}
}
HiveDrawable 的使用:
// imageView是一個(gè)ImageView直接通過ImageDrawable方法設(shè)置一個(gè)HiveDrawable進(jìn)來即可答毫。
imageView.setImageDrawable(new HiveDrawable(BitmapFactory.decodeResource(getResources(),R.drawable.img_1)));
運(yùn)行效果是一樣的褥民,就不展示了。