?一、说明
你是否有遇到过以下需求:
- 底部弹窗的高度为自适应,但最大不能高于 200dp,如果能有一个 maxHeight 属性该多好。但这个属性貌似只在使用 TextView 时见过,其它 View 就不支持了。
- 图片的宽度为屏幕宽度,图片的高度为按设计图尺寸自适应。
- 或者图片的高度固定,按一定比例自适应宽度。
以上的这些需求,Android 原生没有直接的属性支持。当然,你也可以每次去计算,但这样太费事了,如果能封装一个组件达到一劳永逸是不是会方便很多呢。
二、实现逻辑
1、在style.xml 中定义 style
<attr name="maxHeight" format="reference|dimension" />
<attr name="widthHeightRatio" format="float" />
<attr name="limitHeightByWidth" format="boolean" />
<attr name="limitWidthByHeight" format="boolean" />
<declare-styleable name="SizeLimitView">
<!--最大高度-->
<attr name="maxHeight" />
<!--宽高比-->
<attr name="widthHeightRatio" />
<!--是否通过宽度限制高度比率-->
<attr name="limitHeightByWidth" />
<!--是否通过高度限制宽度比率-->
<attr name="limitWidthByHeight" />
</declare-styleable>
2、实现逻辑
/**
* 限制 View 的尺寸自定义 View
*
* 使用方式:
* 将指定 View 包到该 View 中,即可限制其尺寸
*
* 限制方式:
* 方式 1:将高度设置为自适应,并设置最大高度的尺寸,当高度增大到一定程度时就不再增加尺寸了
* 方式 2:限制高度:设定宽高比,设置限制高度,组件会根据宽高比和自身宽度限制其高度
* 方式 3:限制宽度:设定宽高比,设置限制宽度,组件会根据宽高比和自身高度限制其宽度
*
* 应用场景举例:banner 宽度为屏幕宽度,高度为按设计图宽高比自适应,则可通过该组件轻松设定。
*/
class SizeLimitView : FrameLayout {
private var maxHeight = 0f // 最大高度
private var widthHeightRatio = 0f // 宽高比
private var isLimitWidth = false // 是否根据宽高比限制宽度
private var isLimitHeight = false // 是否根据宽高比限制高度
constructor(context: Context): this(context, null)
constructor(context: Context, attr: AttributeSet?): super(context, attr) {
if (attr == null) {
return
}
val ta = context.obtainStyledAttributes(attr, R.styleable.SizeLimitView)
maxHeight = ta.getDimension(R.styleable.SizeLimitView_maxHeight, 0f)
widthHeightRatio = ta.getFloat(R.styleable.SizeLimitView_widthHeightRatio, 0f)
isLimitHeight = ta.getBoolean(R.styleable.SizeLimitView_limitHeightByWidth, false)
if (!isLimitHeight) {
isLimitWidth = ta.getBoolean(R.styleable.SizeLimitView_limitWidthByHeight, false)
}
ta.recycle()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
var widthSize = MeasureSpec.getSize(widthMeasureSpec)
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
var heightSize = MeasureSpec.getSize(heightMeasureSpec)
when {
maxHeight != 0f -> {
heightSize = if (heightSize > maxHeight) maxHeight.toInt() else heightSize
}
isLimitWidth && widthHeightRatio != 0f -> {
widthSize = (heightSize * widthHeightRatio).toInt()
}
isLimitHeight && widthHeightRatio != 0f -> {
heightSize = (widthSize / widthHeightRatio).toInt()
}
}
val widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode)
val heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode)
super.onMeasure(widthSpec, heightSpec)
}
}
三、使用方式
1、限制最大高度
<SizeLimitView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:maxHeight="100dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
</SizeLimitView>
2、按比例限制高度
<SizeLimitView
android:layout_width="match_parent"
android:layout_height="100dp"
app:widthHeightRatio="1.5"
app:limitHeightByWidth="true">
<BannerView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</SizeLimitView>
|