【发布时间】:2017-08-16 12:44:04
【问题描述】:
是否可以在约束布局上实现负边距以实现重叠? 我正在尝试使图像以布局为中心并具有文本视图,使其与 x dp 重叠。我尝试设置负边距值但没有运气。 如果有办法实现这一点,那就太好了。
【问题讨论】:
-
Guideline 可能有帮助,我没试过。
标签: android android-constraintlayout constraint-layout-chains
是否可以在约束布局上实现负边距以实现重叠? 我正在尝试使图像以布局为中心并具有文本视图,使其与 x dp 重叠。我尝试设置负边距值但没有运气。 如果有办法实现这一点,那就太好了。
【问题讨论】:
标签: android android-constraintlayout constraint-layout-chains
更新 ConstraintLayout 现在支持 2.1.0-alpha2 版本的负边距。简单说明
android:layout_marginTop="-25dp"
对于负 25dp 边距。 (这仅在视图顶部受到约束时才有效。如果边距的一侧不受约束,则边距在 ConstraintLayout 中无效。)
澄清:下面的答案仍然有效,但我想澄清几件事。原始解决方案将放置一个相对于另一个视图具有 de facto 负偏移量的视图,并将显示在布局中,如图所示。
另一种解决方案是使用 Amir Khorsandi here 建议的 translationY 属性。我更喜欢该解决方案,但要注意一点:翻译发生在布局后,因此受限于位移视图的视图不会跟随翻译。
例如,以下 XML 在图像下方显示两个 TextView。每个视图都受到从上到下的约束,视图紧邻其上方。
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="150dp"
android:layout_height="150dp"
android:tint="#388E3C"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_action_droid" />
<TextView
android:id="@+id/sayName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Say my name."
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintTop_toBottomOf="@+id/imageView"
app:layout_constraintEnd_toEndOf="@+id/imageView"
app:layout_constraintStart_toStartOf="@+id/imageView" />
<TextView
android:id="@+id/sayIt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Say it."
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintEnd_toEndOf="@+id/sayName"
app:layout_constraintStart_toStartOf="@+id/sayName"
app:layout_constraintTop_toBottomOf="@id/sayName" />
</androidx.constraintlayout.widget.ConstraintLayout>
现在,让我们通过指定将“说出我的名字”TextView 向上翻译 50dp
android:translationY="-50dp"
这会产生以下内容:
“说出我的名字”TextView 已按预期向上移动,但“说出我的名字”TextView 并没有像我们预期的那样跟随它。这是因为翻译发生在布局后。尽管视图在布局后移动,但仍可以在新位置使其可点击。
所以,IMO,如果上面的警告不影响您的布局,请使用 translationX 和 translationY 来获得 ConstraintLayout 中的负边距;否则,请使用 space 小部件,如下所述。
另一个警告: 正如 Salam El-Banna 在对另一个答案的评论中所说,translationX 不是 RTL 布局的好解决方案,因为翻译的标志无论布局的 RTL 或 LTR 特性如何,都将决定移位的方向(左/右)。
原答案
虽然ConstraintLayout 似乎不支持负边距,但有一种方法可以使用可用且受支持的工具来实现此效果。这是一张图片,其中图片标题与图片底部 22dp 重叠 - 实际上是 -22dp 边距:
这是通过使用底部边距等于您想要的偏移量的Space 小部件来实现的。然后Space 小部件的底部被限制在ImageView 的底部。现在您需要做的就是将带有图像标题的TextView 的顶部限制在Space 小部件的底部。 TextView 将位于 Space 视图的底部,忽略设置的边距。
以下是实现此效果的 XML。我会注意到我使用了Space,因为它是轻量级的并且适用于这种类型的使用,但我可以使用另一种类型的View 并使其不可见。 (不过,您可能需要进行调整。)您还可以定义一个具有零边距的 View 和所需的插入边距的高度,并将 TextView 的顶部限制为插入 @987654348 的顶部@。
另一种方法是通过对齐顶部/底部/左侧/右侧并将TextView 覆盖在ImageView 的顶部,并对边距/填充进行适当的调整。下面演示的方法的好处是无需大量计算即可创建负边距。也就是说,有几种方法可以解决这个问题。
更新:有关此技术的快速讨论和演示,请参阅 Google Developers Medium blog post。
ConstraintLayout XML 的负边距
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@mipmap/ic_launcher" />
<android.support.v4.widget.Space
android:id="@+id/marginSpacer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="22dp"
app:layout_constraintBottom_toBottomOf="@+id/imageView"
app:layout_constraintLeft_toLeftOf="@id/imageView"
app:layout_constraintRight_toRightOf="@id/imageView" />
<TextView
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Say my name"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/marginSpacer" />
</android.support.constraint.ConstraintLayout>
【讨论】:
ImageView 以父级为中心,TextView 与ImageView 重叠。然后Space 在应用程序从后台返回时出错。我认为0dp,0dp会造成一些麻烦。不如直接使用Guideline。
android:layout_marginTop="-25dp"。没有影响
另一种方法是像这样使用translationX 或translationY:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:translationX="25dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
它将像android:layout_marginRight="-25dp"一样工作
【讨论】:
RelativeLayout 从未正式支持负边距。 ConstraintLayout 不支持负边距。 [...]
-- 2016 年 6 月 8 日的 Romain Guy
关注这两个问题:
https://code.google.com/p/android/issues/detail?id=212499 https://code.google.com/p/android/issues/detail?id=234866
【讨论】:
这是我经过数小时尝试寻找解决方案后得出的结论。
让我们考虑两个图像,image1 和 image2。 Image2 将放置在位于右下角的 image1 的顶部。
我们可以使用 Space 小部件来重叠视图。
分别用 image1 的四个边约束 Space 小部件的四个边。对于此示例,使用 Space 小部件的右侧限制 image2 的左侧,并使用 Space 小部件的底部限制 image2 的顶部。这会将 image2 与 Space 小部件联系起来,并且由于 Space 小部件受到所有方面的限制,我们可以定义所需的水平或垂直偏差,这将根据需要移动 image2。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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"
tools:context=".Player">
<ImageView
android:id="@+id/image1"
android:layout_width="250dp"
android:layout_height="167dp"
android:src="@android:color/holo_green_dark"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Space
android:id="@+id/space"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/image1"
app:layout_constraintEnd_toEndOf="@+id/image1"
app:layout_constraintHorizontal_bias="0.82"
app:layout_constraintStart_toStartOf="@+id/image1"
app:layout_constraintTop_toTopOf="@+id/image1"
app:layout_constraintVertical_bias="0.62" />
<ImageView
android:id="@+id/image2"
android:layout_width="82dp"
android:layout_height="108dp"
android:src="@android:color/holo_green_light"
app:layout_constraintStart_toEndOf="@+id/space"
app:layout_constraintTop_toBottomOf="@+id/space" />
</android.support.constraint.ConstraintLayout>
此外,为了将 image2 定位在 image1 的中心底部,我们可以分别用 Space 小部件的左侧和右侧约束 image2 的左侧和右侧。同样,我们可以通过使用 Space 小部件更改 image2 的约束来将 image2 放置在任何地方。
【讨论】:
我找到了一种更简单的方法。
基本上有了ImageView,然后在TextView上添加top约束来匹配图片的top约束,只需要添加TextView的margin top来匹配就可以实现-ve margin类型的行为。
【讨论】:
这将帮助很多人
就我而言,我想要这样的设计:
意味着我希望我的图像显示其宽度的一半,所以基本上我需要实际图像宽度一半的负边距,但我在约束布局和约束布局中的整个布局不允许负边距,所以我实现了这一点使用以下代码
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_launcher_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/guideline"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="50dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
这样 ImageView 将在指南的开头结束。效果和50dp开头的负边距一样。
如果你的视图的宽度不是固定的,它是百分比,这样你就可以用百分比放置指南并达到你想要的任何效果
快乐编码:)
【讨论】:
您只需要在布局中使用 Space 小部件
<android.support.constraint.ConstraintLayout 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">
<Space
android:id="@+id/negative_margin"
android:layout_width="16dp"
android:layout_height="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toLeftOf="parent"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Widget who needs negative margin"
app:layout_constraintTop_toBottomOf="@+id/negative_margin"
app:layout_constraintLeft_toLeftOf="@+id/negative_margin" />
【讨论】:
将背景视图放在主题视图后面
我想使用负边距在主题视图后面添加一个视图,该视图按比例大于主题视图。我找到的解决方案是缩放android:scaleX="1.2" 和android:scaleY="1.2" 背景视图,同时将其限制在主题的各个方面。
<View
android:id="@+id/subjectBackground"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleY="1.2"
android:scaleX="1.2"
app:layout_constraintBottom_toBottomOf="@+id/subjectView"
app:layout_constraintEnd_toEndOf="@+id/subjectView"
app:layout_constraintStart_toStartOf="@+id/subjectView"
app:layout_constraintTop_toTopOf="@+id/subjectView" />
【讨论】:
这是一个老问题,但被问得很多,最快的方法是将顶部和底部限制在要锚定到的视图的一侧,如下所示:
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="55dp"
android:layout_height="55dp"
app:layout_constraintBottom_toBottomOf="@+id/parent_view_id"
app:layout_constraintTop_toBottomOf="@+id/parent_view_id"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
这将使它在视图的底线居中,水平居中。
【讨论】:
大家可以试试这个方法,简单多了
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MyProfileFragment">
<ImageView
android:id="@+id/imageViewUserPic"
android:layout_width="@dimen/dp60"
android:src="@mipmap/ic_launcher"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_margin="20dp"
android:layout_height="wrap_content">
</ImageView>
<ImageView
android:id="@+id/imageViewEdit"
app:layout_constraintBottom_toBottomOf="@+id/imageViewUserPic"
android:src="@drawable/ic_edit_red_round"
app:layout_constraintEnd_toEndOf="@+id/imageViewUserPic"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ImageView>
</androidx.constraintlayout.widget.ConstraintLayout>
【讨论】:
这是我的解决方案
<com.oven.test.avatar
android:id="@+id/imageview_a"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_marginTop="28dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<com.oven.test.smallicon
android:id="@+id/small_icon_overlap_a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="@+id/imageview_a"
app:layout_constraintTop_toTopOf="@+id/imageview_a"
app:layout_constraintVertical_bias="1"
android:layout_marginBottom="20dp"/>
【讨论】:
使用 translationX 和 translationY 可能适合您的情况。
<TextView
android:id="@+id/tvText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text"
android:translationX="-15dp"
android:translationY="10dp"
app:layout_constraintEnd_toEndOf="@+id/imageView"
app:layout_constraintTop_toTopOf="@+id/imageView" />
【讨论】:
一个简单的方法。
我不确定最好的方法。
只需使用 LinearLayout 进行包装
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<View
android:layout_width="wrap_content"
android:layout_marginLeft="-20dp"
android:layout_height="wrap_content"/>
</LinearLayout>
【讨论】: