kotlin 自定义 ImageView

2,294 阅读2分钟

# 自定义ImageView

要实现的功能

  • 圆角View
  • 圆形View

下面是发车指南:

# 创建RoundBitmapView.kt

//继承 ImageView
class RoundBitmapView(context: Context, attrs: AttributeSet? = null) :
    ImageView(context, attrs) {}

用到类:

  • PorterDuffXfermode
  • Matrix 矩阵

PorterDuffXfermode图形混合

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>