背景
ImageView的scaleType默认显示图片是这样,但是有时候设计稿需求希望图片左右能紧贴着ImageView左右边缘,又不破坏图片的比例,用自带的matrix,centerCrop等都可以满足
但是都会造成图片的某些区域被裁剪了,如果设计稿只能接受底部被裁剪,其他边区域正常显示,那系统自带的scaleType则无法满足需求。这时需要自定义新的scaleType来满足设计要求
源码解析
- 以宽度为基准,计算图片与ImageView的缩放比例
scale = viewWidth.toFloat() / drawableWidth.toFloat()
- 根据自定义的scale_type,算出图片显示区域,viewHeight / scale为图片显示高度
var drawableRect: RectF? = nullif (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 = 0const val FROM_TOP = 1const val FROM_BOTTOM = 2}private var mCropType = DEFAULTinit {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: Floatval viewWidth = width - paddingLeft - paddingRightval viewHeight = height - paddingLeft - paddingRightval drawableWidth = getDrawable().intrinsicWidthval drawableHeight = getDrawable().intrinsicHeightscale = viewWidth.toFloat() / drawableWidth.toFloat()var drawableRect: RectF? = nullif (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 = cropTypesetupImageMatrixRect()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>