Android开发——RelativeLayout.LayoutParams的使用

本文深入解析了Android开发中RelativeLayout.LayoutParams的使用方法,包括初始化、addRule、setMargins等关键API,帮助开发者掌握动态调整控件位置的技术。

前言

在日常的Android开发当中,我们少不了需要动态改变控件在RelativeLayout界面的位置。那么我们就需要使用到RelativeLayout.LayoutParams。

RelativeLayout.LayoutParams

RelativeLayout.LayoutParams是一个RelativeLayout的布局参数,我们改变控件的就需要使用到。

初始化

// 包裹内容
RelativeLayout.LayoutParams layoutParams = new  RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT);

// 全部内容
RelativeLayout.LayoutParams layoutParams = new  RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT);

其中 new RelativeLayout.LayoutParams()需要填写宽度和高度两个参数。

addRule方法

addRule方法是我们最常用到的,动态设置控件的位置是一定要使用这个方法的。这个方法有两种方式

addRule(int verb)

verb主要的参数有:

  • ABOVE
  • ALIGN_BASELINE
  • ALIGN_BOTTOM
  • ALIGN_END
  • ALIGN_LEFT
  • ALIGN_PARENT_BOTTOM
  • ALIGN_PARENT_END
  • ALIGN_PARENT_LEFT
  • ALIGN_PARENT_RIGHT
  • ALIGN_PARENT_START
  • ALIGN_PARENT_TOP
  • ALIGN_RIGHT
  • ALIGN_START
  • ALIGN_TOP
  • BELOW
  • CENTER_HORIZONTAL
  • CENTER_IN_PARENT
  • CENTER_VERTICAL
  • END_OF
  • LEFT_OF
  • RIGHT_OF
  • START_OF
  • TRUE
addRule(int verb, int subject)

verb主要的参数有:

  • ABOVE
  • ALIGN_BASELINE
  • ALIGN_BOTTOM
  • ALIGN_END
  • ALIGN_LEFT
  • ALIGN_PARENT_BOTTOM
  • ALIGN_PARENT_END
  • ALIGN_PARENT_LEFT
  • ALIGN_PARENT_RIGHT
  • ALIGN_PARENT_START
  • ALIGN_PARENT_TOP
  • ALIGN_RIGHT
  • ALIGN_START
  • ALIGN_TOP
  • BELOW
  • CENTER_HORIZONTAL
  • CENTER_IN_PARENT
  • CENTER_VERTICAL
  • END_OF
  • LEFT_OF
  • RIGHT_OF
  • START_OF
  • TRUE

subject参数是我们另外的控件ID。

setMargins(int left, int top, int right, int bottom)

当前控件设置边距,参数分别是左边,上边,右边,下边。单位是px。

setMarginStart(int start)

当前控件设置开始边距,国内默认是左边的边距,单位是px。

setMarginEnd(int end)

当前控件设置结束边距,国内默认是右边的边距,单位是px。

总结

上述的内容是我阅读RelativeLayout.LayoutParams的源码结合实际开发经常用到的方法笔记。希望对看到这篇博客的小伙伴们有帮助。

package com.tplink.libskeleton import android.content.Context import android.graphics.drawable.ColorDrawable import android.graphics.drawable.GradientDrawable import android.util.TypedValue import android.view.Gravity import android.view.LayoutInflater import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import android.widget.LinearLayout import android.widget.RelativeLayout import androidx.constraintlayout.widget.ConstraintLayout import androidx.coordinatorlayout.widget.CoordinatorLayout.Behavior.setTag import androidx.core.content.ContextCompat /** * @Author: admin * @CreateDate: 2025/12/11 17:12 * @Description: */ class SkeletonBuilder(private val viewGroup: ViewGroup) { private val config = SkeletonDefaults.defaultConfig.copy() // 使用默认值初始化 fun maskColorRes(resId: Int): SkeletonBuilder = apply { config.maskColorRes = resId } fun cornerRadius(dp: Float): SkeletonBuilder = apply { config.cornerRadius = dp } fun shimmerEnabled(enabled: Boolean): SkeletonBuilder = apply { config.shimmerEnabled = enabled } fun shimmerDuration(duration: Long): SkeletonBuilder = apply { config.shimmerDuration = duration } fun shimmerColorRes(resId: Int): SkeletonBuilder = apply { config.shimmerColorRes = resId } fun shimmerAngle(angle: Int): SkeletonBuilder = apply { config.shimmerAngle = angle } fun shimmerWidth(ratio: Float): SkeletonBuilder = apply { config.shimmerWidth = ratio } fun recyclerItemCount(count: Int): SkeletonBuilder = apply { config.recyclerItemCount = count } fun customLayoutRes(resId: Int?): SkeletonBuilder = apply { config.customLayoutRes = resId } fun skeletonItemType(type: SkeletonItemType?): SkeletonBuilder = apply { config.skeletonItemType = type } fun recyclerItemLayoutRes(resId: Int?): SkeletonBuilder = apply { config.recyclerItemLayoutRes = resId } fun recyclerSkeletonItemLayoutRes(resId: Int?): SkeletonBuilder = apply { config.recyclerSkeletonItemLayoutRes = resId } fun keepFirstLayerViewGroupBackground(keep: Boolean): SkeletonBuilder = apply { config.keepFirstLayerViewGroupBackground = keep } fun generateSkeletonScreenWithCurrentView(generate: Boolean): SkeletonBuilder = apply { config.generateSkeletonScreenWithCurrentView = generate } fun ignoreExistingContent(ignore: Boolean): SkeletonBuilder = apply { config.ignoreExistingContent = ignore } fun itemSizeMap(map: Map<Int, Size>): SkeletonBuilder = apply { config.itemSizeMap = map } fun showIndices(show: Boolean): SkeletonBuilder = apply { config.showIndices = show } fun maxViewGroupDepth(depth: Int): SkeletonBuilder = apply { config.maxViewGroupDepth = depth } fun fadeOut(fadeOut: Boolean): SkeletonBuilder = apply { config.fadeOut = fadeOut } fun showSkeleton(config: SkeletonConfig = SkeletonDefaults.defaultConfig) { hideSkeleton() val skeletonView = LayoutInflater.from(context).inflate(config.customLayoutRes!!, this, false) // 根据容器类型生成适配的布局参数 val layoutParams = generateOverlayLayoutParams() // 4防止点击/触摸事件穿透 setupTouchInterceptor(skeletonView) addView(skeletonView, layoutParams) val animation = AnimationManager(skeletonView, config) animation.start() setTag(R.id.tag_skeleton_view, SkeletonView(skeletonView, animation)) } private fun generateOverlayLayoutParams(): ViewGroup.LayoutParams { return when (this) { is FrameLayout -> FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ).apply { gravity = Gravity.START or Gravity.TOP } is LinearLayout -> LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) is RelativeLayout -> RelativeLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ).apply { addRule(RelativeLayout.ALIGN_PARENT_START) addRule(RelativeLayout.ALIGN_PARENT_TOP) addRule(RelativeLayout.ALIGN_PARENT_END) addRule(RelativeLayout.ALIGN_PARENT_BOTTOM) } is ConstraintLayout -> ConstraintLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, // MATCH_CONSTRAINT 0 // MATCH_CONSTRAINT ).apply { topToTop = ConstraintLayout.LayoutParams.PARENT_ID bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID startToStart = ConstraintLayout.LayoutParams.PARENT_ID endToEnd = ConstraintLayout.LayoutParams.PARENT_ID } else -> ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) } } private fun setupTouchInterceptor(view: View) { view.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN, MotionEvent.ACTION_UP -> true else -> true } } } /** * 隐藏 ViewGroup 的骨架屏,恢复原始子 View 状态 */ fun ViewGroup.hideSkeleton() { // 通过 tag 找到骨架 View,停止动画并移除 val skeletonTag = getTag(R.id.tag_skeleton_view) as? SkeletonView ?: return val skeletonView = skeletonTag.view val animationManager = skeletonTag.animationManager // 停止所有动画 animationManager.stop() // 从父布局中移除骨架 View if (skeletonView.parent == this) { removeView(skeletonView) } // 清理 Tag,避免重复添加或内存泄漏 setTag(R.id.tag_skeleton_view, null) } } 修改这个代码使得语法通过
最新发布
12-12
internal fun ViewGroup.LayoutParams.copy(): ViewGroup.LayoutParams { return when (this) { is ConstraintLayout.LayoutParams -> ConstraintLayout.LayoutParams(this).apply { width = this@copy.width height = this@copy.height marginStart = this@copy.marginStart topMargin = this@copy.topMargin marginEnd = this@copy.marginEnd bottomMargin = this@copy.bottomMargin horizontalBias = this@copy.horizontalBias verticalBias = this@copy.verticalBias circleConstraint = this@copy.circleConstraint circleRadius = this@copy.circleRadius circleAngle = this@copy.circleAngle matchConstraintPercentWidth = this@copy.matchConstraintPercentWidth matchConstraintPercentHeight = this@copy.matchConstraintPercentHeight matchConstraintDefaultWidth = this@copy.matchConstraintDefaultWidth matchConstraintDefaultHeight = this@copy.matchConstraintDefaultHeight startToStart = this@copy.startToStart startToEnd = this@copy.startToEnd endToEnd = this@copy.endToEnd endToStart = this@copy.endToStart topToTop = this@copy.topToTop topToBottom = this@copy.topToBottom bottomToBottom = this@copy.bottomToBottom bottomToTop = this@copy.bottomToTop baselineToBaseline = this@copy.baselineToBaseline } is RelativeLayout.LayoutParams -> RelativeLayout.LayoutParams(this).apply { width = this@copy.width height = this@copy.height leftMargin = this@copy.leftMargin topMargin = this@copy.topMargin rightMargin = this@copy.rightMargin bottomMargin = this@copy.bottomMargin // 正确复制所有规则:遍历 getRules() 数组 val rules = this@copy.getRules() for (i in rules.indices) { if (rules[i] > 0) { // 只添加有效规则 addRule(i, rules[i]) } } } is ViewGroup.MarginLayoutParams -> ViewGroup.MarginLayoutParams(this).apply { width = this@copy.width height = this@copy.height leftMargin = this@copy.leftMargin topMargin = this@copy.topMargin rightMargin = this@copy.rightMargin bottomMargin = this@copy.bottomMargin } else -> ViewGroup.LayoutParams(this).apply { width = this@copy.width height = this@copy.height } } }这个有问题,如果高度是0,那么高度设置为wrapcontent,如果宽度是0,设置为matchparent
12-08
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值