Kotlin 动态计算尺寸工具类封装
以下是使用 Kotlin 实现的动态计算尺寸工具类,包含基础版和增强版功能。
1. 基础工具类封装
kotlin
import android.content.Context
import android.util.DisplayMetrics
import android.view.View
import android.view.ViewGroup
object ViewSizeUtils {
/**
* 按屏幕宽度百分比设置View的宽度
* @param view 需要设置的View
* @param widthPercent 宽度百分比 (0.0 - 1.0)
*/
fun setWidthByScreenPercent(view: View, widthPercent: Float) {
if (widthPercent <= 0 || widthPercent > 1) return
val displayMetrics = getDisplayMetrics(view.context)
view.updateLayoutParams {
width = (displayMetrics.widthPixels * widthPercent).toInt()
}
}
/**
* 按屏幕高度百分比设置View的高度
* @param view 需要设置的View
* @param heightPercent 高度百分比 (0.0 - 1.0)
*/
fun setHeightByScreenPercent(view: View, heightPercent: Float) {
if (heightPercent <= 0 || heightPercent > 1) return
val displayMetrics = getDisplayMetrics(view.context)
view.updateLayoutParams {
height = (displayMetrics.heightPixels * heightPercent).toInt()
}
}
/**
* 按屏幕宽高百分比同时设置View的宽高
* @param view 需要设置的View
* @param widthPercent 宽度百分比 (0.0 - 1.0)
* @param heightPercent 高度百分比 (0.0 - 1.0)
*/
fun setSizeByScreenPercent(view: View, widthPercent: Float, heightPercent: Float) {
if (widthPercent <= 0 || widthPercent > 1 || heightPercent <= 0 || heightPercent > 1) return
val displayMetrics = getDisplayMetrics(view.context)
view.updateLayoutParams {
width = (displayMetrics.widthPixels * widthPercent).toInt()
height = (displayMetrics.heightPixels * heightPercent).toInt()
}
}
/**
* 按父容器宽度百分比设置View的宽度
* @param view 需要设置的View
* @param widthPercent 宽度百分比 (0.0 - 1.0)
*/
fun setWidthByParentPercent(view: View, widthPercent: Float) {
if (widthPercent <= 0 || widthPercent > 1 || view.parent !is View) return
val parent = view.parent as View
val parentWidth = parent.width
if (parentWidth <= 0) {
parent.post {
setViewWidth(view, (parent.width * widthPercent).toInt())
}
} else {
setViewWidth(view, (parentWidth * widthPercent).toInt())
}
}
private fun setViewWidth(view: View, width: Int) {
view.updateLayoutParams {
this.width = width
}
}
private fun getDisplayMetrics(context: Context): DisplayMetrics {
return context.resources.displayMetrics
}
private inline fun View.updateLayoutParams(block: ViewGroup.LayoutParams.() -> Unit) {
val params = layoutParams ?: ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
).also { layoutParams = it }
params.block()
layoutParams = params
}
}
2. 增强版工具类(支持更多功能)
kotlin
import android.content.Context
import android.view.View
import android.view.ViewGroup
import kotlin.math.roundToInt
object ViewSizeHelper {
/**
* 设置View的宽高比(基于宽度计算高度)
* @param view 目标View
* @param aspectRatio 宽高比(宽度/高度)
*/
fun setAspectRatio(view: View, aspectRatio: Float) {
if (aspectRatio <= 0) return
view.addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
override fun onLayoutChange(
v: View,
left: Int, top: Int, right: Int, bottom: Int,
oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int
) {
val width = right - left
if (width > 0) {
v.updateLayoutParams {
height = (width / aspectRatio).roundToInt()
}
v.removeOnLayoutChangeListener(this)
}
}
})
}
/**
* 设置View的最小高度(单位:dp)
*/
fun setMinHeightDp(view: View, minHeightDp: Int) {
view.minimumHeight = dpToPx(view.context, minHeightDp)
}
/**
* 设置View的最小宽度(单位:dp)
*/
fun setMinWidthDp(view: View, minWidthDp: Int) {
view.minimumWidth = dpToPx(view.context, minWidthDp)
}
/**
* 设置View的固定尺寸(单位:dp)
*/
fun setFixedSizeDp(view: View, widthDp: Int, heightDp: Int) {
view.updateLayoutParams {
width = dpToPx(view.context, widthDp)
height = dpToPx(view.context, heightDp)
}
}
/**
* 设置View的宽度(单位:dp)
*/
fun setWidthDp(view: View, widthDp: Int) {
view.updateLayoutParams {
width = dpToPx(view.context, widthDp)
}
}
/**
* 设置View的高度(单位:dp)
*/
fun setHeightDp(view: View, heightDp: Int) {
view.updateLayoutParams {
height = dpToPx(view.context, heightDp)
}
}
/**
* 设置View的margin(单位:dp)
*/
fun setMarginsDp(
view: View,
leftDp: Int = Int.MIN_VALUE,
topDp: Int = Int.MIN_VALUE,
rightDp: Int = Int.MIN_VALUE,
bottomDp: Int = Int.MIN_VALUE
) {
val params = view.layoutParams as? ViewGroup.MarginLayoutParams ?: return
if (leftDp != Int.MIN_VALUE) params.leftMargin = dpToPx(view.context, leftDp)
if (topDp != Int.MIN_VALUE) params.topMargin = dpToPx(view.context, topDp)
if (rightDp != Int.MIN_VALUE) params.rightMargin = dpToPx(view.context, rightDp)
if (bottomDp != Int.MIN_VALUE) params.bottomMargin = dpToPx(view.context, bottomDp)
view.layoutParams = params
}
private fun dpToPx(context: Context, dp: Int): Int {
return (dp * context.resources.displayMetrics.density).roundToInt()
}
private inline fun View.updateLayoutParams(block: ViewGroup.LayoutParams.() -> Unit) {
val params = layoutParams ?: ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
).also { layoutParams = it }
params.block()
layoutParams = params
}
}
3. 扩展函数版本(更 Kotlin 化的实现)
kotlin
import android.content.Context
import android.util.DisplayMetrics
import android.view.View
import android.view.ViewGroup
import kotlin.math.roundToInt
// 扩展属性:获取屏幕宽度
val Context.screenWidth: Int
get() = resources.displayMetrics.widthPixels
// 扩展属性:获取屏幕高度
val Context.screenHeight: Int
get() = resources.displayMetrics.heightPixels
// 扩展函数:dp转px
fun Context.dpToPx(dp: Int): Int = (dp * resources.displayMetrics.density).roundToInt()
// 扩展函数:更新LayoutParams
inline fun View.updateLayoutParams(block: ViewGroup.LayoutParams.() -> Unit) {
val params = layoutParams ?: ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
).also { layoutParams = it }
params.block()
layoutParams = params
}
// 基础功能扩展函数
fun View.setWidthByScreenPercent(widthPercent: Float) {
if (widthPercent <= 0 || widthPercent > 1) return
updateLayoutParams {
width = (context.screenWidth * widthPercent).toInt()
}
}
fun View.setHeightByScreenPercent(heightPercent: Float) {
if (heightPercent <= 0 || heightPercent > 1) return
updateLayoutParams {
height = (context.screenHeight * heightPercent).toInt()
}
}
fun View.setSizeByScreenPercent(widthPercent: Float, heightPercent: Float) {
if (widthPercent <= 0 || widthPercent > 1 || heightPercent <= 0 || heightPercent > 1) return
updateLayoutParams {
width = (context.screenWidth * widthPercent).toInt()
height = (context.screenHeight * heightPercent).toInt()
}
}
// 增强功能扩展函数
fun View.setAspectRatio(aspectRatio: Float) {
if (aspectRatio <= 0) return
addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
override fun onLayoutChange(
v: View,
left: Int, top: Int, right: Int, bottom: Int,
oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int
) {
val width = right - left
if (width > 0) {
v.updateLayoutParams {
height = (width / aspectRatio).roundToInt()
}
v.removeOnLayoutChangeListener(this)
}
}
})
}
fun View.setMinHeightDp(minHeightDp: Int) {
minimumHeight = context.dpToPx(minHeightDp)
}
fun View.setMinWidthDp(minWidthDp: Int) {
minimumWidth = context.dpToPx(minWidthDp)
}
fun View.setFixedSizeDp(widthDp: Int, heightDp: Int) {
updateLayoutParams {
width = context.dpToPx(widthDp)
height = context.dpToPx(heightDp)
}
}
4. 使用示例
基础工具类使用
kotlin
// 设置按钮宽度为屏幕的50%
ViewSizeUtils.setWidthByScreenPercent(myButton, 0.5f)
// 设置图片高度为屏幕的30%
ViewSizeUtils.setHeightByScreenPercent(myImageView, 0.3f)
// 设置TextView宽高分别为屏幕的80%和20%
ViewSizeUtils.setSizeByScreenPercent(myTextView, 0.8f, 0.2f)
// 设置RecyclerView宽度为父容器的70%
ViewSizeUtils.setWidthByParentPercent(recyclerView, 0.7f)
增强工具类使用
kotlin
// 设置图片16:9的宽高比
ViewSizeHelper.setAspectRatio(myImageView, 16f/9f)
// 设置按钮最小高度为48dp
ViewSizeHelper.setMinHeightDp(myButton, 48)
// 设置固定尺寸为100dp×50dp
ViewSizeHelper.setFixedSizeDp(iconView, 100, 50)
// 设置margin
ViewSizeHelper.setMarginsDp(
view = myView,
leftDp = 16,
topDp = 8,
rightDp = 16,
bottomDp = 8
)
扩展函数版本使用
kotlin
// 使用扩展函数更简洁
myButton.setWidthByScreenPercent(0.5f)
myImageView.setHeightByScreenPercent(0.3f)
myTextView.setSizeByScreenPercent(0.8f, 0.2f)
// 设置宽高比
myVideoView.setAspectRatio(16f/9f)
// 设置最小尺寸
floatingButton.setMinWidthDp(48)
floatingButton.setMinHeightDp(48)
// 设置固定尺寸
iconView.setFixedSizeDp(100, 50)
这些 Kotlin 实现充分利用了语言特性,如扩展函数、属性、lambda 表达式等,使代码更加简洁易用。根据项目需求,可以选择工具类形式或扩展函数形式来实现动态尺寸计算。