美文网首页
自定义圆形ImageView

自定义圆形ImageView

作者: Lost_Robot | 来源:发表于2018-07-10 15:17 被阅读15次

显示头像需要显示圆形头像,RoundImageView继承自ImageView

1.定义属性,在使用RoundImageView时,使用属性设置是圆形还是普通还是使用圆角
在项目的res中的values中选择attrs文件定义属性
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="RoundImageView">
        <attr name="type" format="enum">
            <enum name="circle" value="1"/>
            <enum name="round" value="2"/>
        </attr>
        <attr name="radius" format="dimension"/>ssss
    </declare-styleable>

</resources>

2.定义继承ImageView,在构造函数中,获取属性
 private fun obtainStyledAttrs(context: Context, attrs: AttributeSet, defStyleAttr: Int) {
        val a = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView, defStyleAttr, 0)
        currMode = if (a.hasValue(R.styleable.RoundImageView_type)) a.getInt(R.styleable.RoundImageView_type, MODE_NONE) else MODE_NONE
        currRound = if (a.hasValue(R.styleable.RoundImageView_radius)) a.getDimensionPixelSize(R.styleable.RoundImageView_radius, currRound) else currRound
        a.recycle()   //切记一定要回收
    }

2.重写onDraw方法,对比ImageView的onDraw方法,其实只是添加了一部分if判断是圆角还是圆形:

   override fun onDraw(canvas: Canvas) {
        val mDrawable = drawable
        val mDrawMatrix = imageMatrix
        if (mDrawable == null) {
            return  // couldn't resolve the URI
        }

        if (mDrawable.intrinsicWidth == 0 || mDrawable.intrinsicHeight == 0) {
            return      // nothing to draw (empty bounds)
        }

        if (mDrawMatrix == null && paddingTop == 0 && paddingLeft == 0) {
            mDrawable.draw(canvas)
        } else {
            val saveCount = canvas.saveCount
            canvas.save()

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                if (cropToPadding) {
                    val scrollX = scrollX
                    val scrollY = scrollY
                    canvas.clipRect(scrollX + paddingLeft, scrollY + paddingTop,
                            scrollX + right - left - paddingRight,
                            scrollY + bottom - top - paddingBottom)
                }
            }

            canvas.translate(paddingLeft.toFloat(), paddingTop.toFloat())

            if (currMode == MODE_CIRCLE) {//当为圆形模式的时候,注意此处的代码不是很好,需要再优化,没有判处使用padding的时候,是否能够正常显示,如果在使用padding的时候,会显示不正常。
                val bitmap = drawable2Bitmap(mDrawable)
                mPaint?.setShader(BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP))
                val viewMiniSize = Math.min(width, height)
                val radius = viewMiniSize / 2.5f
                canvas.drawCircle(width / 2.0f, height / 2.0f, radius, mPaint)  //cx:x坐标 cy:y坐标
            } else if (currMode == MODE_ROUND) {//当为圆角模式的时候
                val bitmap = drawable2Bitmap(mDrawable)
                mPaint?.setShader(BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP))
                canvas.drawRoundRect(RectF(paddingLeft.toFloat(), paddingTop.toFloat(), width.toFloat() - paddingRight, height.toFloat() - paddingBottom),
                        currRound.toFloat(), currRound.toFloat(), mPaint)
            } else {
                if (mDrawMatrix != null) {
                    canvas.concat(mDrawMatrix)
                }
                mDrawable.draw(canvas)
            }
            canvas.restoreToCount(saveCount)
        }
    }


重写onMeasure方法:


override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        /**
         * 当模式为圆形模式的时候,我们强制让宽高一致
         */
        if (currMode == MODE_CIRCLE) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
            val result = Math.min(measuredHeight, measuredWidth)
            setMeasuredDimension(result, result)
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        }
    }

3.全部代码
package com.cmbc.creditcard.cmms.view

import android.content.Context
import android.graphics.*
import android.graphics.drawable.Drawable
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.util.TypedValue
import android.widget.ImageView
import com.cmbc.creditcard.cmms.R


/**
 * Created by Aqua on 2018-07-09.
 * <br>
 * fIREFLY
 * com.cmbc.creditcard.cmms.view
 * @author  Isan
 * @date 2018-07-09    15:07
 * @version  3.2.1
 * @api  6
 * <br>
 * CMBC-版权所有
 * <br>
 */
class RoundImageView : ImageView {

    /**
     * 圆形模式
     */
    private val MODE_CIRCLE = 1
    /**
     * 普通模式
     */
    private val MODE_NONE = 0
    /**
     * 圆角模式
     */
    private val MODE_ROUND = 2
    private var mPaint: Paint? = null
    private var currMode = 0
    /**
     * 圆角半径
     */
    private var currRound = dp2px(10.0f)


    constructor(context: Context) : super(context) {
        initViews()
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {

        obtainStyledAttrs(context, attrs, 0);
        initViews()
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        obtainStyledAttrs(context, attrs, defStyleAttr);
        initViews()
    }

    private fun obtainStyledAttrs(context: Context, attrs: AttributeSet, defStyleAttr: Int) {
        val a = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView, defStyleAttr, 0)
        currMode = if (a.hasValue(R.styleable.RoundImageView_type)) a.getInt(R.styleable.RoundImageView_type, MODE_NONE) else MODE_NONE
        currRound = if (a.hasValue(R.styleable.RoundImageView_radius)) a.getDimensionPixelSize(R.styleable.RoundImageView_radius, currRound) else currRound
        a.recycle()
    }

    private fun initViews() {
        mPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG)
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        /**
         * 当模式为圆形模式的时候,我们强制让宽高一致
         */
        if (currMode == MODE_CIRCLE) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
            val result = Math.min(measuredHeight, measuredWidth)
            setMeasuredDimension(result, result)
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        }
    }

    override fun onDraw(canvas: Canvas) {
        val mDrawable = drawable
        val mDrawMatrix = imageMatrix
        if (mDrawable == null) {
            return  // couldn't resolve the URI
        }

        if (mDrawable.intrinsicWidth == 0 || mDrawable.intrinsicHeight == 0) {
            return      // nothing to draw (empty bounds)
        }

        if (mDrawMatrix == null && paddingTop == 0 && paddingLeft == 0) {
            mDrawable.draw(canvas)
        } else {
            val saveCount = canvas.saveCount
            canvas.save()

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                if (cropToPadding) {
                    val scrollX = scrollX
                    val scrollY = scrollY
                    canvas.clipRect(scrollX + paddingLeft, scrollY + paddingTop,
                            scrollX + right - left - paddingRight,
                            scrollY + bottom - top - paddingBottom)
                }
            }

            canvas.translate(paddingLeft.toFloat(), paddingTop.toFloat())

            if (currMode == MODE_CIRCLE) {//当为圆形模式的时候
                val bitmap = drawable2Bitmap(mDrawable)
                mPaint?.setShader(BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP))
                val viewMiniSize = Math.min(width, height)
                val radius = viewMiniSize / 2.5f
                canvas.drawCircle(width / 2.0f, height / 2.0f, radius, mPaint)  //cx:x坐标 cy:y坐标
            } else if (currMode == MODE_ROUND) {//当为圆角模式的时候
                val bitmap = drawable2Bitmap(mDrawable)
                mPaint?.setShader(BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP))
                canvas.drawRoundRect(RectF(paddingLeft.toFloat(), paddingTop.toFloat(), width.toFloat() - paddingRight, height.toFloat() - paddingBottom),
                        currRound.toFloat(), currRound.toFloat(), mPaint)
            } else {
                if (mDrawMatrix != null) {
                    canvas.concat(mDrawMatrix)
                }
                mDrawable.draw(canvas)
            }
            canvas.restoreToCount(saveCount)
        }
    }

    /**
     * drawable转换成bitmap
     */
    private fun drawable2Bitmap(drawable: Drawable?): Bitmap? {
        if (drawable == null) {
            return null
        }
        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        //根据传递的scaletype获取matrix对象,设置给bitmap
        val matrix = imageMatrix
        if (matrix != null) {
            canvas.concat(matrix)
        }
        drawable.draw(canvas)
        return bitmap
    }

    private fun dp2px(value: Float): Int {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, resources.displayMetrics).toInt()
    }

}

4.使用

 <com.test.view.RoundImageView
            android:id="@+id/sign_head_iv"
            android:layout_width="@dimen/max_head_image_size"
            android:layout_height="@dimen/max_head_image_size"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="@dimen/padding_size_two"
            android:src="@drawable/head_max"
            app:type="circle"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/sign_head_title" />
使用效果

相关文章

网友评论

      本文标题:自定义圆形ImageView

      本文链接:https://www.haomeiwen.com/subject/mkigjxtx.html