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

Kotlin 动态计算尺寸工具类封装

以下是使用 Kotlin 实现的动态计算尺寸工具类,包含基础版和增强版功能。

1. 基础工具类封装

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. 增强版工具类(支持更多功能)

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 化的实现)

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. 使用示例

基础工具类使用

// 设置按钮宽度为屏幕的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)

增强工具类使用

// 设置图片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
)

扩展函数版本使用

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值