ConstraintLayout中设置负值的margin失效了?不妨换一种思路来实现!

在某些场景下,我们可能需要实现两个View的压盖效果,比如常见的气泡、小红点等等,如下所示:

如果父布局是RelativeLayout,那么实现起来比较简单,只要给目标View设置负值margin,就能实现我们的效果;而如果父布局是ConstraintLayout,会发现设置负值margin不起作用,那么此时我们可以选择其他的方式来实现,针对这两种情况分别来实现一下。

注:实现上述效果不止这两种方案,这里主要为了说明如何在ConstraintLayout中实现对应效果。

在RelativeLayout中使用负值margin(有效)

ini 复制代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    android:clipToPadding="false">
    
    <RelativeLayout
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_centerInParent="true"
        android:visibility="visible">

        <androidx.appcompat.widget.LinearLayoutCompat
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/gray_400" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_alignParentEnd="true"
            android:layout_marginTop="-10dp"
            android:layout_marginEnd="-10dp"
            android:background="@drawable/text_red_bg"
            android:text="全新"
            android:textColor="#FFFFFF"
            android:textSize="12sp" />
    </RelativeLayout>
</RelativeLayout>

执行结果如上图所示,这里注意一点需要在祖父节点上设置android:clipChildren="false"来允许TextView可以超出父布局的范围。

在ConstraintLayout中如何实现类似效果?

如果想在ConstraintLayout中也实现类似效果,如果也设置负值margin,会发现不生效,可以通过其他方式来实现。

方案一:升级ConstraintLayout版本

可以看到当ConstraintLayout升级到2.1.0-alpha2时,默认已经支持负值margin了,所以如果项目中支持,直接升级ConstraintLayout版本来达到效果。

方案二:使用Space实现

ini 复制代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    android:clipToPadding="false">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_centerInParent="true"
        android:visibility="visible">

        <androidx.appcompat.widget.LinearLayoutCompat
            android:id="@+id/ll_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/gray_400" />

        <Space
            android:id="@+id/txt_spacer"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="10dp"
            android:layout_marginBottom="10dp"
            app:layout_constraintBottom_toTopOf="parent"
            app:layout_constraintStart_toEndOf="parent" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/text_red_bg"
            android:text="全新"
            android:textColor="#FFFFFF"
            android:textSize="12sp"
            app:layout_constraintEnd_toEndOf="@+id/txt_spacer"
            app:layout_constraintTop_toTopOf="@+id/txt_spacer" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>

通过上述代码,借助Space在ConstraintLayout中实现了同样的效果,效果图不再贴了,先来看下Space是个什么:

Space is a lightweight View subclass that may be used to create gaps between components in general purpose layouts.

Space是一个轻量级的View子类,可用于在通用布局中创建组件之间的间隙。

Space是专门用来处理组件之间间隙的(Space用于占位),主要通过Space增加偏移量,另一个组件以Space为基础就可以实现View压盖或负值margin了。

方案三:使用translationX、translationY实现(有局限性)

ini 复制代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    android:clipToPadding="false">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_centerInParent="true"
        android:visibility="visible">

        <androidx.appcompat.widget.LinearLayoutCompat
            android:id="@+id/ll_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/gray_400" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/text_red_bg"
            android:text="全新"
            android:textColor="#FFFFFF"
            android:textSize="12sp"
            android:translationX="10dp"
            android:translationY="-10dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>

</RelativeLayout>

通过translationX、translationY也可以实现对应的效果。translationX、translationY是view在x/y方向偏移量,因为translationX、translationY是在layout之后执行的,可能会导致相互依赖的其他控件的位置没有跟着变化,具体还是要看使用场景,如果translationX、translationY能够满足你的要求,那么用其实现压盖效果也是ok的。

PS:x、getLeft()、translationX的关系 :可以认为x = getLeft() + translationX

相关推荐
千里马学框架7 小时前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台7 小时前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone8 小时前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc8 小时前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo10 小时前
Kotlin 协程中的 Job 结构化并发与取消
android
sun00770010 小时前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼11 小时前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone12 小时前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen12 小时前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone12 小时前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui