相对于ImageView维度的ConstraintLayout

时间:2017-10-22 17:11:30

标签: android android-custom-view vector-graphics android-constraintlayout

我目前正在开发一个小型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张图片说明了这个问题。

三星Galaxy S8: Samsung Galaxy S8

Google Pixel XL: Google Pixel XL

相对于Android图标,小红色方块应始终位于完全相同的位置。

2 个答案:

答案 0 :(得分:4)

只要宽高比保持不变,这是一种将小部件精确放置在ImageView或任何其他视图上的更简单方法,无论ImageView的大小如何变化,都会保留其放置位置。在我的另一个答案的第一个提出的解决方案中,我建议使用偏差将小部件放在ImageView内。不幸的是,将窗口小部件的相对大小更改为ImageView的大小会导致窗口小部件移动到不希望的图像上。

为了解决这个问题,我建议使用偏差在Space上放置1x1像素ImageView视图。由于空间视图的大小仅为1x1像素,因此可以使用偏差将其放置在ImageView内的任何位置。由于单个设备上的旋转或因为应用程序托管在具有不同屏幕尺寸的设备上,因此ImageView更改大小时,相对位置将保持不变。无论屏幕的大小如何,图像的纵横比保持不变是非常重要的。

放置1x1像素视图后,可以通过约束附加窗口小部件。在下面的示例中,我选择通过将每个眼睛窗口小部件的所有边约束到其放置像素的相应边来将眼睛的窗口小部件置于放置像素的中心。

以下是一些显示效果的图片。我测试的不同尺寸的屏幕显示相同的结果。

Nexus 6 Portrait

Nexus 6 Portrait

Nexus 6格局

enter image description here

由于眼睛的ImageView未缩放,因此它们在Nexus 10屏幕上显得更小。将眼睛放在与Nexus 6相同的位置。缩小眼睛是另一回事。

Nexus 10 Landscape

enter image description here

以下是显示约束的布局:

enter image description here

<强> 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

中的指南的XML
<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会漂移。

enter image description here

以下是上图中的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

enter image description here

这是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>