自学内容网 自学内容网

Android笔记(三十六):封装一个Matrix从顶部/底部对齐的ImageView

背景

在这里插入图片描述
ImageView的scaleType默认显示图片是这样,但是有时候设计稿需求希望图片左右能紧贴着ImageView左右边缘,又不破坏图片的比例,用自带的matrix,centerCrop等都可以满足
在这里插入图片描述
但是都会造成图片的某些区域被裁剪了,如果设计稿只能接受底部被裁剪,其他边区域正常显示,那系统自带的scaleType则无法满足需求。这时需要自定义新的scaleType来满足设计要求

源码解析

  • 以宽度为基准,计算图片与ImageView的缩放比例
scale = viewWidth.toFloat() / drawableWidth.toFloat()
  • 根据自定义的scale_type,算出图片显示区域,viewHeight / scale为图片显示高度
        var drawableRect: RectF? = null
        if (mCropType == FROM_TOP) {
            drawableRect = RectF(0f, 0f, drawableWidth.toFloat(), viewHeight / scale)
        } else if (mCropType == FROM_BOTTOM) {
            drawableRect = RectF(
                0f,
                drawableHeight - viewHeight / scale,
                drawableWidth.toFloat(),
                drawableHeight.toFloat()
            )
        }
  • 使用setImageMatrix设置图片绘制边界
val viewRect = RectF(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())
matrix.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.FILL)
setImageMatrix(matrix)

完整源码

class MatrixImageView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {

    companion object {
        const val DEFAULT = 0
        const val FROM_TOP = 1
        const val FROM_BOTTOM = 2
    }
    private var mCropType = DEFAULT

    init {
        val ta = context.obtainStyledAttributes(attrs, R.styleable.MatrixImageView, 0, 0)
        mCropType = ta.getInt(R.styleable.MatrixImageView_scale_type, DEFAULT)
        if (mCropType != DEFAULT) {
            setScaleType(ScaleType.MATRIX)
        }
        ta.recycle()
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        if (mCropType != DEFAULT) {
            setupImageMatrixRect()
        }
    }

    private fun setupImageMatrixRect() {
        if (getDrawable() == null) {
            return
        }
        val matrix = getImageMatrix()
        val scale: Float
        val viewWidth = width - paddingLeft - paddingRight
        val viewHeight = height - paddingLeft - paddingRight
        val drawableWidth = getDrawable().intrinsicWidth
        val drawableHeight = getDrawable().intrinsicHeight

        scale = viewWidth.toFloat() / drawableWidth.toFloat()

        var drawableRect: RectF? = null
        if (mCropType == FROM_TOP) {
            drawableRect = RectF(0f, 0f, drawableWidth.toFloat(), viewHeight / scale)
        } else if (mCropType == FROM_BOTTOM) {
            drawableRect = RectF(
                0f,
                drawableHeight - viewHeight / scale,
                drawableWidth.toFloat(),
                drawableHeight.toFloat()
            )
        }
        val viewRect = RectF(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())
        matrix.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.FILL)
        setImageMatrix(matrix)
    }

    fun setCropType(@CropType cropType: Int) {
        if (mCropType != cropType) {
            mCropType = cropType
            setupImageMatrixRect()
            invalidate()
        }
    }

    @IntDef(FROM_TOP, FROM_BOTTOM)
    @Retention(AnnotationRetention.SOURCE)
    annotation class CropType
}
    <declare-styleable name="MatrixImageView">
        <attr name="scale_type">
            <enum name="matrix_top" value="1" />
            <enum name="matrix_bottom" value="2" />
        </attr>
    </declare-styleable>

最终效果

在这里插入图片描述


原文地址:https://blog.csdn.net/weixin_40855673/article/details/143792680

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!