昨天有個朋友讓我折騰一個這樣的ImageView,
他說“我想要一個既可以圓角又可以設定寬高比的imageview”
是以我就折騰了下。
大概是這樣的
1.attributes
這裡說一下:如果參考邊是:寬,那麼你高度的設定其實是沒有效果的
因為,代碼裡面 我直接把高度重新計算了
<declare-styleable name="SakuraImage">
<!--參考邊-->
<attr name="refer" format="enum">
<enum name="寬" value="1"/>
<enum name="高" value="2"/>
</attr>
<!--長寬比例-->
<attr name="ratio" format="float"/>
<!--圓弧度-->
<attr name="radius" format="float"/>
</declare-styleable>
2.xml
<mos.kos.cache.widget.SakuraImage
android:layout_width="200dp"
android:layout_height="200dp"
android:scaleType="centerCrop"
android:src="@drawable/image"
sakura:radius="20"
sakura:ratio="1"
sakura:refer="高"/>
3.Code
3.1.長寬按比例設定
這一步主要是在
onMeasure
裡面完成的
具體的看下面的代碼和代碼裡的注釋
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (ratio > 0) {
//參考邊為:寬
if (referEdge == 1) {
ratioW = MeasureSpec.getSize(widthMeasureSpec);
ratioH = (int) (ratioW * ratio);//根據寬來計算高
//參考邊為:高
} else {
ratioH = MeasureSpec.getSize(heightMeasureSpec);
ratioW = (int) (ratioH * ratio);//根據高來計算寬
}
//丢給父類處理
super.onMeasure(MeasureSpec.makeMeasureSpec(ratioW, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(ratioH, MeasureSpec.EXACTLY));
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Logger.v("寬高1:ratioW=" + ratioW + ",ratioH=" + ratioH);
}
3.2.設定帶圓弧的圖檔
這裡稍微麻煩一點,不過主要還是在 onDraw
裡面處理的
- 1.先找到圖檔的錨點
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
rectF.top = 0;
rectF.left = 0;
rectF.right = getWidth(); // 寬度
rectF.bottom = getHeight(); // 高度
setBitmapShader();
}
- 2.關鍵的一步:設定圖檔的透明區域Shader
下面是一段僞代碼,把這一塊的關鍵點都整到一起的
//先整一個畫筆
Paint bmpPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
bmpPaint.setStyle(Paint.Style.FILL);
bmpPaint.setAntiAlias(true);
//這裡的bmp是搞到的Bitmap圖檔
BitmapShader bmpShader = new BitmapShader(bmp,
Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//bmpShader 就是圓弧所裁剪調的透明區域
bmpPaint.setShader(bmpShader);
//這個矩陣主要是對裁剪後的圖檔做縮放、還有位置的處理
matrix.set(null);//設為預設值,固定為CENTER_CROP
// 縮放
float scale = Math.max(getWidth() * 1f / bmp.getWidth(), getHeight() * 1f / bmp.getHeight());
// 居中
float dx = (getWidth() - bmp.getWidth() * scale) / 2;
float dy = (getHeight() - bmp.getHeight() * scale) / 2;
matrix.setScale(scale, scale);
matrix.postTranslate(dx, dy);
bmpShader.setLocalMatrix(matrix);
invalidate();//重新整理
- 3.最後繪制
這裡我踩了個坑,記錄一下:
繪制的時候
用Canvas 的路徑繪制
最好
canvas.drawPath()
,就是第1步打的那4個錨點,這樣也是最簡單的
我之前嘗試過直接用畫布來繪制矩形
或者繪制圖形
canvas.drawRoundRect(
canvas.drawBitmap(
。
雖然也成功了,但是效果不怎麼理想。
@Override
protected void onDraw(Canvas canvas) {
if (bmp != null) {
path.reset();
path.addRoundRect(rectF, radius, radius, Path.Direction.CW);
canvas.drawPath(path, bmpPaint);
}
}
最後丢再幾張效果圖
- 1.寬高比為1的時候
- 2.這裡是以寬為參考邊
- 3.這裡是以高為參考邊
源碼下載下傳