栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

最强大的布局——约束布局(ConstraintLayout)的一些技巧

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

最强大的布局——约束布局(ConstraintLayout)的一些技巧

一.使用viewBinding
1.想开启那个模块的viewBinding就进入对应模块的build.gradle

2.进入app的build.gradle

开启viewbinding

viewBinding {
        enabled = true
    }

3.当你开启viewbinding后,app目录下的所有布局文件都会生成一个绑定类。这个类的类名是以xml布局文件名去掉下换线后,单词首字母大写加上Binding命名的。如activity_main.xml生成的绑定类为ActivityMainBinding.

如果你不想生成绑定类,也很简单,将tools:viewBindingIgnore=“true” 属性添加到相应布局文件的根视图中。

使用就更简单了,如下

package com.example.animationtest

import android.os.Bundle
import android.os.PersistableBundle
import androidx.appcompat.app.AppCompatActivity
import com.example.animationtest.databinding.ConstrainBinding

class Constraint:AppCompatActivity() {
    private val viewBinding=ConstrainBinding.inflate(layoutInflater)
    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)
        setContentView(viewBinding.root)
    }
}

viewBinding.root就是布局的根布局

二.开发中可能会遇到的场景

1.当A或者C宽度固定或者为wrap_content,你想要B的宽度自适应。

其实这个场景可以分解为:

B.width=屏幕宽度-A.width-C.width(视情况可能还会减去margin或padding)


如果用约束布局就要用android:layout_width="0dp"来解决这个问题,那就是把B的宽度设置为0dp。

如下




    

    

    


布局很简单,就三个Textview,把三个控件相互约束,再把把B的宽度设置为0dp。

2.如果想要三个控件平分宽度
2.1 如果你没有背景,就把三个控件相互约束,但三个控件的宽度都必须是wrap_content或固定宽度(这个应该都能理解吧,为match_parent其中一个子布局就充满了父控件了,就别谈自适应了)。


2.2 你有背景就把三个控件的宽度都设置为0dp

其实这个场景可以分解为:

任意一个的宽度=(屏幕宽度-(视情况可能减去margin或padding))/3




    

    

    


现在基本上都是用约束布局,这就像属性动画一样,它可以适用所有场景。

三.动态改变布局

1.获取屏幕宽度
可以去下面的博客去看,写的很好
Android 获取屏幕宽度和高度的几种方法
当你获取了屏幕宽度或高度,你就可以写一写适配Android的布局了。

val outSize = DisplayMetrics()
        windowManager.defaultDisplay.getRealMetrics(outSize)
        val width = outSize.widthPixels
        val height = outSize.widthPixels

        viewBinding.textA.updateLayoutParams {
            topMargin=width
        }

2.动态改变布局

2.1 改变布局属性
1.viewBinding.textA.updateLayoutParams { topMargin=width }
ConstraintLayout.LayoutParams 这里是父布局的LayoutParams,
比如我的text A的父布局就是ConstraintLayout

2.2 改变布局约束

 val constrainSet = ConstraintSet().apply { clone(viewBinding.root) }
        constrainSet.connect(
            viewBinding.textC.id,ConstraintSet.START,viewBinding.textA.id,ConstraintSet.END
        )
        constrainSet.applyTo(viewBinding.root)

    val constrainSet = ConstraintSet().apply { clone(viewBinding.root) }
    这段话就是复制一份父布局的约束,方法有三个如下:

    set.clone(constraintLayout: ConstraintLayout);
    set.clone(set: ConstraintSet);
    set.clone(context: Context, constraintLayoutId: Int);
    

    这里需要注意,在调用clone()方法的时候,必须保证这个父布局的所有子布局都设置了 id,不然会报错,这跟它的内部实现原理有关,有兴趣可以去看一下源码。

      设置组件之间的约束,常用方法有:
    set.connect(startID: Int, startSide: Int, endID: Int, endSide: Int, margin: Int)
     
    set.connect(startID: Int, startSide: Int, endID: Int, endSide: Int)
    
    constrainSet.connect(
                viewBinding.textC.id,ConstraintSet.START,viewBinding.textA.id,ConstraintSet.END,20
            )
    

    这句话的意思就是: 修改一个id为textC的约束,依赖的约束组件为一个id为textA的控件,修改为textC的左边和textA的右边对其,边距margin为20px:

    3.然后把新的布局约束设置到原来的布局

    constrainSet.applyTo(viewBinding.root)
    

    4.View.post()
    这是为了解决布局还没执行View的meaure()而获取宽高为0的其中一个解决方案。

    viewBinding.textB.post 
    { 
    val width=viewBinding.textB.width
    val width=viewBinding.textB.measuredWidth
    val height=viewBinding.textB.height
            }
    

    大家应该注意到我上面用了width和measuredWidth
    这两者有何区别呢
    很简单就是字母的区别(开个冷玩笑)
    measuredWidth:它的值在measure方法运行后会确定
    width:它的值在layout方法运行后会确定

    这里引用下这个博主的一段话
    Android是消息驱动的模式,View.post的Runnable任务会被加入任务队列,并且等待第一次TraversalRunnable执行结束后才执行,此时已经执行过一次measure,layout过程了,所以在后面执行post的Runnable时,已经有measure的结果,因此此时可以获取到View的宽高。

    转载请注明:文章转载自 www.mshxw.com
    本文地址:https://www.mshxw.com/it/755159.html
    我们一直用心在做
    关于我们 文章归档 网站地图 联系我们

    版权所有 (c)2021-2022 MSHXW.COM

    ICP备案号:晋ICP备2021003244-6号