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

相关推荐
BD_Marathon4 小时前
【MySQL】函数
android·数据库·mysql
西西学代码5 小时前
安卓开发---耳机的按键设置的UI实例
android·ui
maki0779 小时前
虚幻版Pico大空间VR入门教程 05 —— 原点坐标和项目优化技巧整理
android·游戏引擎·vr·虚幻·pico·htc vive·大空间
千里马学框架10 小时前
音频焦点学习之AudioFocusRequest.Builder类剖析
android·面试·智能手机·车载系统·音视频·安卓framework开发·audio
fundroid13 小时前
掌握 Compose 性能优化三步法
android·android jetpack
TeleostNaCl14 小时前
如何在 IDEA 中使用 Proguard 自动混淆 Gradle 编译的Java 项目
android·java·经验分享·kotlin·gradle·intellij-idea
旷野说15 小时前
Android Studio Narwhal 3 特性
android·ide·android studio
maki07721 小时前
VR大空间资料 01 —— 常用VR框架对比
android·ue5·游戏引擎·vr·虚幻·pico
xhBruce1 天前
InputReader与InputDispatcher关系 - android-15.0.0_r23
android·ims
领创工作室1 天前
安卓设备分区作用详解-测试机红米K40
android·java·linux