Android屏幕适配利器:Kotlin动态尺寸计算工具类完整封装

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 表达式等,使代码更加简洁易用。根据项目需求,可以选择工具类形式或扩展函数形式来实现动态尺寸计算。

相关推荐
“初生”5 小时前
安卓手机安装 ChatGPT 全流程图文指南
android·chatgpt·智能手机
与籍同行6 小时前
20200201工作笔记常用命令要整理
android·笔记
aningxiaoxixi7 小时前
android property 系统
android
speop8 小时前
TASK05【Datawhale 组队学习】系统评估与优化
android·java·学习
zhu620197610 小时前
Android10如何设置ro.debuggable=1?
android·安全·android逆向·android10·ro.debuggable
androidwork11 小时前
Android 内存溢出(OOM)的 Kotlin 排查与优化指南
android·开发语言·kotlin
androidwork11 小时前
Kotlin与Flutter:跨平台开发的互补之道与实战指南
开发语言·flutter·kotlin
橙子1991101611 小时前
谈谈 Kotlin 中的构造方法,有哪些注意事项?
java·前端·kotlin
xzkyd outpaper11 小时前
Android中PID与UID的区别和联系
android·计算机八股