前言
了解View的绘制三大流程后,接下来就要对这些知识做一个实践,首先来实现一个在Android中最为常见的控件——方形图片控件,即让图片在一个方形区域内显示,最常见的场景是在九宫格图片当中。
一般的场景需求是图片根据屏幕宽度进行三等分作为边长,来显示图片。
这样需求首先我们会想到根据屏幕宽度计算出每个正方形图片所需要的边长是多少?
就会有下面的步骤:
- 在xml文件中定义好ImageView控件
- 通过代码计算出根据屏幕宽度均分后的宽度
- 再通过代码将计算得出的边长设置到ImageView上
这种方式会出现大量的计算代码,代码会变多,同时复用性不强,那么有什么办法可以让我们在控件内部就将计算逻辑进行封装呢?
这就要开始我们绘制流程的第一个实践——方形图片控件
具体实现
思考方形图片的实现方法的过程中可以想到两种实现方法:
- 根据图片的宽高进行自绘
- 继承已有ImageView控件,进行尺寸的运算
第一种方式实现起来很复杂,相比较第二种实现方式,最终的实现结果还不一定好,果断放弃。
那么我们就直接通过第二种方式来进行方形图片的实现,通过继承ImageView,重写onMeasure的方式得到下面的代码:
class SquareImageView(context: Context, attrs: AttributeSet?) : androidx.appcompat.widget.AppCompatImageView(context, attrs) {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
// // 判断方式一
// val side = min(widthMeasureSpec, heightMeasureSpec)
// setMeasuredDimension(side, side)
// 判断方法二
setMeasuredDimension(widthMeasureSpec, widthMeasureSpec)
}
}
代码提供了两种判断方式:
- 根据定义的控件较小边为正方形边长来确定图片控件的长宽
- 直接根据图片控件定义的宽为正方形图片控件的边长
以上两方法都可以实现正方形图片的效果,一般更加倾向于第二种,因为一般图形的宽更适用于实际的需求。
注:setMeasuredDimension
是实际设置测量宽高的地方
实际效果
实际看看通过第二种方法实现的方形图片
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<com.redrain.viewdemo.measure_layout.SquareImageView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:src="@drawable/saber"/>
<com.redrain.viewdemo.measure_layout.SquareImageView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:src="@drawable/saber"/>
<com.redrain.viewdemo.measure_layout.SquareImageView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:src="@drawable/saber"/>
</LinearLayout>
图片是吾王,吾王赛高!!!咳咳
原图是长图,图片的scaleType
设置了centerCrop
,实际的效果布局:
下面是原图:
总结
这种方式实现的方形图适用于列表的Grid模式,可以做到较好的适配。
另外还有一种操作是直接将指定的Spec
参数直接放入到super的方法中去,如以下:
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec)
}
这种方式不是很推荐,因为会影响到ImageView本身的onMeasure方法中的逻辑。