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

相关推荐
天空中的野鸟44 分钟前
Android音频采集
android·音视频
小白也想学C2 小时前
Android 功耗分析(底层篇)
android·功耗
曙曙学编程2 小时前
初级数据结构——树
android·java·数据结构
闲暇部落4 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX6 小时前
Android 分区相关介绍
android
大白要努力!7 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee7 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood7 小时前
Perfetto学习大全
android·性能优化·perfetto
Dnelic-10 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Eastsea.Chen13 小时前
MTK Android12 user版本MtkLogger
android·framework