我目前正在开发一个小型Android应用程序并使用新的ConstraintLayout。
我有一个ImageView,它包含一个矢量图形图像,该图像应该占据相对于其纵横比的最大可用空间。我使用以下代码使用它:
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="@dimen/margin"
android:src="@drawable/image"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
现在,我想在准确的位置放置多个自定义视图(按钮)。使用约束指南,我想出了以下内容:
<android.support.constraint.Guideline
android:id="@+id/guideline_x"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.20"
tools:layout_editor_absoluteX="..."
tools:layout_editor_absoluteY="..."
/>
<android.support.constraint.Guideline
android:id="@+id/guideline_y"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.20"
tools:layout_editor_absoluteX="..."
tools:layout_editor_absoluteY="..."
/>
<com.example.android.myCustomView
android:id="@+id/myCustomView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doSomething"
app:layout_constraintLeft_toLeftOf="@+id/guideline_x"
app:layout_constraintTop_toTopOf="@+id/guideline_y"
/>
这适用于我最初测试过的特定设备。但是:一旦设备尺寸变化,自定义视图就会被放置在错误的位置。
我正在寻找一种相对于图像视图的x坐标放置自定义视图n%的方法。我已经尝试在指南中添加app:layout_constraintLeft_toLeftOf="@+id/imageView"
,但这没有任何改变。您有什么想法我可以解决这个问题吗?非常感谢!
编辑: 这里有2张图片说明了这个问题。
相对于Android图标,小红色方块应始终位于完全相同的位置。
答案 0 :(得分:4)
只要宽高比保持不变,这是一种将小部件精确放置在ImageView
或任何其他视图上的更简单方法,无论ImageView
的大小如何变化,都会保留其放置位置。在我的另一个答案的第一个提出的解决方案中,我建议使用偏差将小部件放在ImageView
内。不幸的是,将窗口小部件的相对大小更改为ImageView
的大小会导致窗口小部件移动到不希望的图像上。
为了解决这个问题,我建议使用偏差在Space
上放置1x1像素ImageView
视图。由于空间视图的大小仅为1x1像素,因此可以使用偏差将其放置在ImageView
内的任何位置。由于单个设备上的旋转或因为应用程序托管在具有不同屏幕尺寸的设备上,因此ImageView
更改大小时,相对位置将保持不变。无论屏幕的大小如何,图像的纵横比保持不变是非常重要的。
放置1x1像素视图后,可以通过约束附加窗口小部件。在下面的示例中,我选择通过将每个眼睛窗口小部件的所有边约束到其放置像素的相应边来将眼睛的窗口小部件置于放置像素的中心。
以下是一些显示效果的图片。我测试的不同尺寸的屏幕显示相同的结果。
Nexus 6 Portrait
Nexus 6格局
由于眼睛的ImageView
未缩放,因此它们在Nexus 10屏幕上显得更小。将眼睛放在与Nexus 6相同的位置。缩小眼睛是另一回事。
Nexus 10 Landscape
以下是显示约束的布局:
<强> position_view.xml 强>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/androidGreen"
android:layout_width="0dp"
android:layout_height="0dp"
android:src="@drawable/android_image"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<Space
android:id="@+id/pinpoint1"
android:layout_width="1px"
android:layout_height="1px"
app:layout_constraintBottom_toBottomOf="@id/androidGreen"
app:layout_constraintEnd_toEndOf="@id/androidGreen"
app:layout_constraintHorizontal_bias="0.373"
app:layout_constraintStart_toStartOf="@id/androidGreen"
app:layout_constraintTop_toTopOf="@id/androidGreen"
app:layout_constraintVertical_bias="0.19" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/circle"
app:layout_constraintBottom_toBottomOf="@id/pinpoint1"
app:layout_constraintEnd_toEndOf="@id/pinpoint1"
app:layout_constraintStart_toStartOf="@id/pinpoint1"
app:layout_constraintTop_toTopOf="@id/pinpoint1"
app:srcCompat="@drawable/circle"
tools:ignore="ContentDescription" />
<Space
android:id="@+id/pinpoint2"
android:layout_width="1px"
android:layout_height="1px"
android:background="@android:color/holo_red_light"
app:layout_constraintBottom_toBottomOf="@id/androidGreen"
app:layout_constraintEnd_toEndOf="@id/androidGreen"
app:layout_constraintHorizontal_bias="0.625"
app:layout_constraintStart_toStartOf="@id/androidGreen"
app:layout_constraintTop_toTopOf="@id/androidGreen"
app:layout_constraintVertical_bias="0.19" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/circle"
app:layout_constraintBottom_toBottomOf="@id/pinpoint2"
app:layout_constraintEnd_toEndOf="@id/pinpoint2"
app:layout_constraintStart_toStartOf="@id/pinpoint2"
app:layout_constraintTop_toTopOf="@id/pinpoint2"
tools:ignore="ContentDescription" />
</android.support.constraint.ConstraintLayout>
您还可以将ImageView
包裹在ConstraintLayout
中,并将ImageView
的宽度和高度设置为match_parent
,从而实现相同的目标。然后,您可以使用百分比指南在ImageView
上定位窗口小部件。此方法在布局层次结构中引入了另一个级别,但可能更容易理解。
这是演示此方法的XML。
使用嵌套ConstraintLayout
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.constraint.ConstraintLayout
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/androidGreen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/android_image"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<android.support.constraint.Guideline
android:id="@+id/guidelineHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.19" />
<android.support.constraint.Guideline
android:id="@+id/guidelineVerticalLeft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.375" />
<android.support.constraint.Guideline
android:id="@+id/guidelineVerticalRight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.625" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/circle"
app:layout_constraintBottom_toBottomOf="@id/guidelineHorizontal"
app:layout_constraintEnd_toEndOf="@id/guidelineVerticalLeft"
app:layout_constraintStart_toStartOf="@id/guidelineVerticalLeft"
app:layout_constraintTop_toTopOf="@id/guidelineHorizontal"
app:srcCompat="@drawable/circle"
tools:ignore="ContentDescription" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/circle"
app:layout_constraintBottom_toBottomOf="@id/guidelineHorizontal"
app:layout_constraintEnd_toEndOf="@id/guidelineVerticalRight"
app:layout_constraintStart_toStartOf="@id/guidelineVerticalRight"
app:layout_constraintTop_toTopOf="@id/guidelineHorizontal"
tools:ignore="ContentDescription" />
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
答案 1 :(得分:2)
如果您想在另一个视图中定位视图,请查看ConstraintLayout
中的Centering positioning and bias。
<强>偏置强>
遇到这种相反的约束时的默认设置是使窗口小部件居中;但你可以使用偏差属性来调整定位以支持一方而不是另一方:
这是TextView
位于距图像左侧20%,距离顶部70%的位置。不同屏幕尺寸的定位将保持不变,但您必须确保纵横比保持不变;否则,TextView
会漂移。
以下是上图中的XML:
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="16dp"
android:src="@drawable/ic_android_green_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:text="TextView here"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="@id/imageView"
app:layout_constraintEnd_toEndOf="@id/imageView"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintStart_toStartOf="@id/imageView"
app:layout_constraintTop_toTopOf="@id/imageView"
app:layout_constraintVertical_bias="0.7" />
</android.support.constraint.ConstraintLayout>
在视图中处理提供更精确定位的定位的另一种方法是定义Space
视图的水平和垂直链,这些视图使用权重来划分容器视图。以下是与上面相同的布局,但在Space
宽度的20%处,两个ImageView
视图之间具有垂直边界。另外两个Space
视图在容器视图的70%处具有水平边界。请参阅ConstraintLayout
的文档中的Chains。
这是XML:
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="16dp"
android:src="@drawable/ic_android_green_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Space
android:id="@+id/space1"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/holo_blue_light"
app:layout_constraintBottom_toBottomOf="@id/imageView"
app:layout_constraintEnd_toStartOf="@id/space2"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_weight="20"
app:layout_constraintStart_toStartOf="@id/imageView"
app:layout_constraintTop_toTopOf="@id/imageView" />
<Space
android:id="@+id/space2"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/holo_red_light"
app:layout_constraintBottom_toBottomOf="@id/imageView"
app:layout_constraintEnd_toEndOf="@id/imageView"
app:layout_constraintHorizontal_weight="80"
app:layout_constraintStart_toEndOf="@id/space1"
app:layout_constraintTop_toTopOf="@id/imageView" />
<Space
android:id="@+id/space3"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/holo_blue_light"
app:layout_constraintBottom_toTopOf="@id/space4"
app:layout_constraintEnd_toEndOf="@id/imageView"
app:layout_constraintStart_toStartOf="@id/imageView"
app:layout_constraintTop_toTopOf="@id/imageView"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintVertical_weight="70" />
<Space
android:id="@+id/space4"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/holo_red_light"
app:layout_constraintBottom_toBottomOf="@id/imageView"
app:layout_constraintEnd_toEndOf="@id/imageView"
app:layout_constraintStart_toStartOf="@id/imageView"
app:layout_constraintTop_toBottomOf="@id/space3"
app:layout_constraintVertical_weight="30" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView here"
android:textSize="24sp"
app:layout_constraintStart_toEndOf="@id/space1"
app:layout_constraintTop_toBottomOf="@id/space3" />
</android.support.constraint.ConstraintLayout>