美文网首页
自定义圆形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