# 自定义ImageView
要实现的功能
- 圆角View
- 圆形View
下面是发车指南:
# 创建RoundBitmapView.kt
//继承 ImageView
class RoundBitmapView(context: Context, attrs: AttributeSet? = null) :
ImageView(context, attrs) {}
用到类:
- PorterDuffXfermode
- Matrix 矩阵
Matrix
/** Set the matrix to scale by sx and sy. */
//设置缩放比例
public void setScale(float sx, float sy) {
nSetScale(native_instance, sx, sy);
}
定义一些变量:
private val mContext: Context = context
//加载的Bitmap
private var bitmap: Bitmap? = null
//设置圆角角度
private var mRadius: Float = 0f
//是否圆View
private var mIsCircle: Boolean = false
//控件的宽
private var width: Int? = 0
//控件的高
private var height: Int? = 0
设置attrs
<declare-styleable name="RoundBitmapView">
<!--圆角角度-->
<attr name="corners_size" format="integer"/>
<!--是否绘制圆-->
<attr name="is_circle" format="boolean"/>
</declare-styleable>
private fun initAttrs(attrs: AttributeSet?) {
val typedArray: TypedArray = mContext.obtainStyledAttributes(attrs, R.styleable.RoundBitmapView)
mIsCircle = typedArray.getBoolean(R.styleable.RoundBitmapView_is_circle, mIsCircle)
mRadius = typedArray.getInt(R.styleable.RoundBitmapView_corners_size, mRadius.toInt()).toFloat()
typedArray.recycle()
}
自定义控件 三步走:
override fun onDraw(canvas: Canvas?) {
initBitmap()
val pLeft: Float? = paddingLeft.toFloat()
val pTop: Float? = paddingTop.toFloat()
//是否圆View
when (mIsCircle) {
true -> {
val bitmapC: Bitmap? =
width?.let { height?.let { it1 -> bitmap?.let { it2 -> reSizeImageC(it2, it, it1) } } }
val createBitmap: Bitmap? =
bitmapC?.let { width?.let { it1 -> height?.let { it2 -> createCircleImage(it, it1, it2) } } }
if (createBitmap != null) {
pTop?.let { pLeft?.let { it1 -> canvas?.drawBitmap(createBitmap, it1, it, null) } }
}
}
false -> {
val bitmapC: Bitmap? =
width?.let { height?.let { it1 -> bitmap?.let { it2 -> reSizeImage(it2, it, it1) } } }
val createBitmap: Bitmap? =
bitmapC?.let { width?.let { it1 -> height?.let { it2 -> createRoundImage(it, it1, it2) } } }
if (createBitmap != null) {
pTop?.let { pLeft?.let { it1 -> canvas?.drawBitmap(createBitmap, it1, it, null) } }
}
}
}
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
width = measuredWidth
height = measuredHeight
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val width = MeasureSpec.getSize(widthMeasureSpec)
val height = MeasureSpec.getSize(heightMeasureSpec)
setMeasuredDimension(width, height)
}
换算Bitmap 宽高:
/**
* 重设Bitmap的宽高
*
* @param bitmap
* @param newWidth
* @param newHeight
* @return
*/
private fun reSizeImage(bitmap: Bitmap, newWidth: Int, newHeight: Int): Bitmap {
val width = bitmap.width
val height = bitmap.height
// 计算出缩放比
val scaleWidth = newWidth.toFloat() / width
val scaleHeight = newHeight.toFloat() / height
//等比例缩放
val scale = if (scaleWidth > scaleHeight) scaleWidth else scaleHeight
// 矩阵缩放bitmap
val matrix = Matrix()
matrix.postScale(scale, scale)
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true)
}
/**
* 重设Bitmap的宽高
*
* @param bitmap
* @param newWidth
* @param newHeight
* @return
*/
private fun reSizeImageC(bitmap: Bitmap, newWidth: Int, newHeight: Int): Bitmap {
val width = bitmap.width
val height = bitmap.height
// 计算出缩放比
val scaleWidth = newWidth.toFloat() / width
val scaleHeight = newHeight.toFloat() / height
//等比例缩放
val scale = if (scaleWidth > scaleHeight) scaleWidth else scaleHeight
// 矩阵缩放bitmap
val matrix = Matrix()
matrix.postScale(scale, scale)
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true)
}
绘制Bitmap:
/**
* 画圆角
*
* @param source
* @param width
* @param height
* @return
*/
private fun createRoundImage(source: Bitmap, width: Int, height: Int): Bitmap {
val paint = Paint()
paint.isAntiAlias = true
val target = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(target)
val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
canvas.drawRoundRect(rect, mRadius, mRadius, paint)
// 核心代码取两个图片的交集部分
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(source, ((width - source.width) / 2).toFloat(), ((height - source.height) / 2).toFloat(), paint
)
return target
}
/**
* 画圆
*
* @param source
* @param width
* @param height
* @return
*/
private fun createCircleImage(source: Bitmap, width: Int, height: Int): Bitmap {
val paint = Paint()
paint.isAntiAlias = true
val target = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(target)
canvas.drawCircle(
(width / 2).toFloat(), (height / 2).toFloat(), (Math.min(width, height) / 2).toFloat(),
paint
)
// 核心代码取两个图片的交集部分
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(
source, ((width - source.width) / 2).toFloat(),
((height - source.height) / 2).toFloat(), paint
)
return target
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:padding="10dp"
android:layout_height="match_parent">
<com.joyssom.example.draw.RoundBitmapView
android:layout_width="100dp"
android:src="@drawable/icon"
app:corners_size="20"
app:is_circle="false"
android:scaleType="centerCrop"
android:layout_height="100dp"/>
<com.joyssom.example.draw.RoundBitmapView
android:layout_width="100dp"
android:src="@drawable/icon"
app:is_circle="true"
android:scaleType="centerCrop"
android:layout_centerInParent="true"
android:layout_height="100dp"/>
</RelativeLayout>