Android: layout size issue when changing device settings - android

I am currently facing a trouble regarding size change.
I have coded my xml files using dp's, but when I change the device screen size, the layout would change.
For example, when I go into Settings - Display - Screen zoom and font and set screen zoom from medium to large, some of the elements in my layout such as imageview or button would grow and go beyond the screen.
Since I'm using a complex layout containing LinearLayouts and FrameLayouts, I am not clear about how I should make this layout look alright in any other devices or screen sizes. It seems like when I change the screen zoom setting, the value of dp changes.
Is there a way to avoid this problem, or maybe to programmatically set screen zoom setting to medium?
Here is my code:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_gravity="center"
android:layout_marginTop="65dp">
<android.support.constraint.ConstraintLayout
android:id="#+id/frameLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="95dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3">
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/home_map" />
<Button
android:id="#+id/pick1"
android:layout_width="34dp"
android:layout_height="56dp"
android:background="#drawable/top_deselected"
app:layout_constraintBottom_toBottomOf="#+id/imageView"
app:layout_constraintEnd_toEndOf="#+id/imageView"
app:layout_constraintHorizontal_bias="0.17"
app:layout_constraintStart_toStartOf="#+id/imageView"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.18" />
<Button
android:id="#+id/pick2"
android:layout_width="34dp"
android:layout_height="56dp"
android:background="#drawable/jungle_deselected"
app:layout_constraintBottom_toBottomOf="#+id/imageView"
app:layout_constraintEnd_toEndOf="#+id/imageView"
app:layout_constraintHorizontal_bias="0.28"
app:layout_constraintStart_toStartOf="#+id/imageView"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.367" />
<Button
android:id="#+id/pick3"
android:layout_width="34dp"
android:layout_height="56dp"
android:background="#drawable/mid_deselected"
app:layout_constraintBottom_toBottomOf="#+id/imageView"
app:layout_constraintEnd_toEndOf="#+id/imageView"
app:layout_constraintHorizontal_bias="0.424"
app:layout_constraintStart_toStartOf="#+id/imageView"
app:layout_constraintTop_toTopOf="#+id/imageView"
app:layout_constraintVertical_bias="0.43" />
<Button
android:id="#+id/pick4"
android:layout_width="34dp"
android:layout_height="56dp"
android:background="#drawable/support_deselected"
app:layout_constraintBottom_toBottomOf="#+id/imageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.615"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/imageView"
app:layout_constraintVertical_bias="0.71" />
<Button
android:id="#+id/pick5"
android:layout_width="34dp"
android:layout_height="56dp"
android:background="#drawable/adc_deselected"
app:layout_constraintBottom_toBottomOf="#+id/imageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.733"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/imageView"
app:layout_constraintVertical_bias="0.71" />
</android.support.constraint.ConstraintLayout>
<Button
android:layout_width="335dp"
android:layout_height="42.5dp"
android:layout_marginBottom="5.5dp"
android:background="#drawable/home_mode"
android:id="#+id/home_mode"/>
<Button
android:layout_width="335dp"
android:layout_height="42.5dp"
android:background="#drawable/home_match"
android:id="#+id/home_match"/>
</LinearLayout>
The constraint layout used to be a frame layout, but I was just now trying out the constraint layout.

You can also use this library, it is working on all devices, no need to make any dimen file and all. but use this only for the size of widgets, for text size use "sp" only.
https://github.com/intuit/sdp

Related

Android Studio Different Screen Sizes

Hello i make my first app in the Android Studio and i have some problem. I was read every stackoverflow's topics and android documentation about my problem but i still don't understand what i should do.
I uses a ConstraintLayout for application and uses "SDP" "SSP" library for different screen sizes. In the Android Studio preview on every devices (also my custom device) my app looks good
screenshoot
But when i test app on my phone (the same phone like a device in Android Studio "LG") the app isn't the same like in the preview
screenshoot
Like you can see some elements are disappear
What should I do to make the application on the phone look the same as in the preview and to be adapted to different devices and screen sizes?'
Here's my XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
android:background="#ff11111a"
android:theme="#style/Theme.PlayRPGMobile"
tools:context=".MainActivity">
<ImageView
android:id="#+id/imageView"
android:layout_width="#dimen/_230sdp"
android:layout_height="#dimen/_300sdp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/login_logo"
app:layout_constraintVertical_bias="0.299"
app:srcCompat="#drawable/rectangle" />
<ImageView
android:id="#+id/login_logo"
android:layout_width="#dimen/_300sdp"
android:layout_height="0dp"
android:layout_marginTop="#dimen/_64sdp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.476"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/logo" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_28sdp"
android:fontFamily="sans-serif-medium"
android:text="Wprowadź swoje dane"
android:textSize="#dimen/_15ssp"
app:layout_constraintBottom_toTopOf="#+id/loginEdit"
app:layout_constraintEnd_toEndOf="#+id/imageView"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="#+id/imageView"
app:layout_constraintTop_toTopOf="#+id/imageView"
app:layout_constraintVertical_bias="0.0"
tools:text="Wprowadź swoje dane" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_24sdp"
android:fontFamily="sans-serif-medium"
android:text="Play RPG © 2022"
android:textSize="#dimen/_15ssp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/imageView"
tools:text="Play RPG © 2022" />
<EditText
android:id="#+id/loginEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_80sdp"
android:background="#ff222228"
android:ems="10"
android:hint="Login..."
android:inputType="textPersonName"
android:minHeight="#dimen/_38sdp"
android:paddingLeft="#dimen/_10sdp"
android:paddingTop="#dimen/_5sdp"
android:paddingBottom="#dimen/_2sdp"
app:layout_constraintEnd_toEndOf="#+id/imageView"
app:layout_constraintHorizontal_bias="0.533"
app:layout_constraintStart_toStartOf="#+id/imageView"
app:layout_constraintTop_toTopOf="#+id/imageView" />
<EditText
android:id="#+id/passEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_20sdp"
android:background="#ff222228"
android:ems="10"
android:hint="Hasło..."
android:inputType="textPassword"
android:minHeight="#dimen/_38sdp"
android:paddingLeft="#dimen/_10sdp"
android:paddingTop="#dimen/_5sdp"
android:paddingBottom="#dimen/_5sdp"
app:layout_constraintEnd_toEndOf="#+id/loginEdit"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="#+id/loginEdit"
app:layout_constraintTop_toBottomOf="#+id/loginEdit" />
<Button
android:id="#+id/loginBtn"
android:layout_width="#dimen/_130sdp"
android:layout_height="#dimen/_38sdp"
android:backgroundTint="#ff222228"
android:fontFamily="sans-serif-medium"
android:text="Zaloguj"
android:textColor="#color/white"
app:layout_constraintBottom_toBottomOf="#+id/imageView"
app:layout_constraintEnd_toEndOf="#+id/pinEdit"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="#+id/pinEdit"
app:layout_constraintTop_toBottomOf="#+id/pinEdit"
app:layout_constraintVertical_bias="0.512" />
<EditText
android:id="#+id/pinEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_20sdp"
android:background="#ff222228"
android:ems="10"
android:hint="PIN..."
android:inputType="number"
android:minHeight="#dimen/_38sdp"
android:paddingLeft="#dimen/_10sdp"
android:paddingTop="#dimen/_5sdp"
android:paddingBottom="#dimen/_5sdp"
app:layout_constraintEnd_toEndOf="#+id/passEdit"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="#+id/passEdit"
app:layout_constraintTop_toBottomOf="#+id/passEdit" />
</androidx.constraintlayout.widget.ConstraintLayout>
For making responsive UI I would suggest using guidelines in constraint layout. You can take help of this constraint layout training guide.
Also you can make use of chains in constraint layout Chains
Avoid hard-coded layout sizes for Different Screen Sizes
To ensure that your layout is flexible and adapts to different screen sizes, you should use wrap_content or match_parent for the width and height of most view components, instead of hard-coded sizes.
wrap_content tells the view to set its size to whatever is necessary to fit the content within that view.
match_parent makes the view expand to as much as possible within the parent view.
It would be helpful for you to look at the Android documentation.
Use guidelines and constraint the views to it. I faced the same problem and guidelines helped me a lot.

how to add tablet resolution support in Android Studio

Using ConstraintLayout I saw this problem: on phones, the resolution of my widgets is normal and takes up almost all of the
screen space:
But when I switch to the resolution of the tablets, all the widgets become small and cannot be viewed on the screen:
How to make the resolution of widgets look normal on all resolutions and devices?
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TableLayout
android:id="#+id/table_l"
android:layout_width="297dp"
android:layout_height="329dp"
android:layout_weight="1"
android:layout_x="57dp"
android:layout_y="202dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" />
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" />
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</TableRow>
</TableLayout>
<Button
android:id="#+id/st"
android:layout_width="178dp"
android:layout_height="wrap_content"
android:layout_x="120dp"
android:layout_y="112dp"
android:text="start"
app:layout_constraintBottom_toTopOf="#+id/table_l"
app:layout_constraintEnd_toEndOf="#+id/table_l"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="#+id/table_l"
app:layout_constraintTop_toTopOf="parent"
android:layout_weight="1"
app:layout_constraintVertical_bias="0.647" />
<TextView
android:id="#+id/X_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="48dp"
android:layout_x="118dp"
android:layout_y="608dp"
android:text="x:"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="#+id/O_text"
app:layout_constraintStart_toStartOf="#+id/O_text"
app:layout_constraintTop_toBottomOf="#+id/O_text" />
<TextView
android:id="#+id/O_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="36dp"
android:layout_x="116dp"
android:layout_y="661dp"
android:text="o:"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="#+id/table_l"
app:layout_constraintHorizontal_bias="0.153"
app:layout_constraintStart_toStartOf="#+id/table_l"
app:layout_constraintTop_toBottomOf="#+id/table_l"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="#+id/textView3"
android:layout_width="27dp"
android:layout_height="47dp"
android:layout_marginTop="36dp"
android:textSize="36sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.139"
app:layout_constraintStart_toEndOf="#+id/O_text"
app:layout_constraintTop_toBottomOf="#+id/table_l"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="#+id/textView4"
android:layout_width="25dp"
android:layout_height="45dp"
android:layout_marginBottom="52dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.151"
app:layout_constraintStart_toEndOf="#+id/X_text"
app:layout_constraintTop_toBottomOf="#+id/textView3"
app:layout_constraintVertical_bias="0.571" />
</androidx.constraintlayout.widget.ConstraintLayout>
You should create layout xml files for different screen size. For example; If your app running in Tablet(7 inch), you must create new layout as a layout-sw600dp.
Look at this link for more details.
You should stop using fixed sizes and x/y positions for layouts. There might be exceptions, but in general, all views should be able to dynamically resize themselves. That means, you almost never use fixed values for widths but instead wrap_content or match_parent. After 4 years of android development I also have to find one case where I ever needed the layout_x and layout_y XML tags.
Otherwise, this layout will be small on big screens and it won't fit on small screens.
For 90% of layouts, all you need is ConstraintLayout and maybe LinearLayout. RelativeLayouts have become mostly obsolete.
Explaining how to properly arrange your ui would be to exhaustive here. Instead, I recommend you to take the time to go through a tutorial like this google codelab on building a responsive UI with constraintlayouts. If done correctly, you can build one UI which looks good an smartphones and tablets.
But if you want to have an entirely different layout for tablets, then #Mustafa Yanık's approach is correct. Then you need to create a second layout in a different subfolder.

Issue in ConstraintLayout implementation

I expect layout_constraintDimensionRatio to work with layout_constraintWidth_percent. But not working as expected. For example create a square view, which width is half of parent width.
<Button
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constrainedHeight="true"
app:layout_constrainedWidth="true"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.5" />
I am reading following from android.support.constraint.ConstraintLayout
private void setChildrenConstraints() {
...............
if(layoutParams.dimensionRatio != null) {
widget.setDimensionRatio(layoutParams.dimensionRatio);
}
widget.setHorizontalWeight(layoutParams.horizontalWeight);
widget.setVerticalWeight(layoutParams.verticalWeight);
widget.setHorizontalChainStyle(layoutParams.horizontalChainStyle);
widget.setVerticalChainStyle(layoutParams.verticalChainStyle);
widget.setHorizontalMatchStyle(layoutParams.matchConstraintDefaultWidth, layoutParams.matchConstraintMinWidth, layoutParams.matchConstraintMaxWidth, layoutParams.matchConstraintPercentWidth);
widget.setVerticalMatchStyle(layoutParams.matchConstraintDefaultHeight, layoutParams.matchConstraintMinHeight, layoutParams.matchConstraintMaxHeight, layoutParams.matchConstraintPercentHeight);
}
}
I think, setDimensionRatio should be called after setVerticalWeight for this. Is this a bug inside ConstraintLayout. Or Am I missing any thing?
If you want your View to be 50% of width Add Guideline with orientation="vertical"
E.g.
<ImageView
android:id="#+id/imageView7"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toStartOf="#+id/guideline4"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/attach_audio" />
<android.support.constraint.Guideline
android:id="#+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
Imageview of 50% width of parent
Can you post more about your ConstraintLayout attributes? According to what I know and the official document,
You can also define one dimension of a widget as a ratio of the other one. In order to do that, you need to have at least one constrained dimension be set to 0dp (i.e., MATCH_CONSTRAINT), and set the attribute layout_constraintDimensionRatio to a given ratio.
Have you set the layout_width to 0dp ?
with the help of Dipali's answer I could make the design as I want.
<Button
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintRight_toLeftOf="#+id/guide_line"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.constraint.Guideline
android:id="#+id/guide_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
But what I found is : layout_constraintDimensionRatio will not work with layout_constraintWidth_percent or layout_constraintHorizontal_chainStyle etc.

ConstraintLayout relative to ImageView dimensions

I'm currently developing a small Android application and use the new ConstraintLayout.
I have an ImageView which contains a vector graphic image which is supposed to take the maximum space available with respect to its aspect ratio. I got this to work with the following code:
<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"
/>
Now, I want to place multiple custom views (buttons) at exact positions. Using Constraint Guidelines, I came up with the following:
<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"
/>
This works great for the specific device that I've been testing with initially. But: As soon as the device dimensions vary, the custom views are placed at wrong positions.
I am looking for a way to place a custom view n% relative to the x coordinate of the image view. I've tried adding app:layout_constraintLeft_toLeftOf="#+id/imageView" to the guidelines but this changes nothing. Do you have any ideas how I can resolve this issue? Thanks a lot!
Edit:
Here are 2 images which illustrate the issue.
Samsung Galaxy S8:
Google Pixel XL:
The little red square should always be at the exact same position relative to the Android icon.
Here is a easier way to place a widget precisely on an ImageView or any other view that will retain it placement regardless of any change in size of the ImageView as long as the aspect ratio remains constant. In the first proposed solution of my other answer, I suggested using bias to place the widget within the ImageView. Unfortunately, a change in the relative size of the widget to to the size of the ImageView causes the widget to shift on the image which is not desireable.
To get around this, I suggest placing a 1x1 pixel Space view on the ImageView using bias. Because the Space view is just 1x1 pixel in size, it can be placed anywhere within the ImageView by using bias. It's relative position will remain constant as the ImageView changes size due to rotation on a single device or because the app is being hosted on devices with different screen sizes. It is just important that the aspect ratio of the image remain constant regardless of the size of the screen.
Once the 1x1 pixel view is placed, the widget can be attached through constraints. In the example below, I have chosen to center the widgets for the eyes on the placement pixels by constraining all sides of each eye widget to the corresponding sides of its placement pixel.
Here are some images showing the effect. Screen with varying sizes that I have tested show the same result.
Nexus 6 Portrait
Nexus 6 Landscape
Because the ImageViews for the eyes are not scaled, they appear smaller on the Nexus 10 screen. The eyes are placed in the same location as on the Nexus 6. Scaling the eyes is a different matter.
Nexus 10 Landscape
Here is the layout showing the constraints:
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>
You can also achieve the same goal by wrapping the ImageView in a ConstraintLayout and setting the width and height of the ImageView to match_parent. You can then use percent guidelines to position a widget on the ImageView. This method introduces another level in the layout hierarchy but may be easier to understand.
Here is XML that will demonstrate this method.
XML using guidelines within nested 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>
If you want to position a view within another view, take a look at Centering positioning and bias in ConstraintLayout.
Bias
The default when encountering such opposite constraints is to center the widget; but you can tweak the positioning to favor one side over another using the bias attributes:
Here is a TextView positioned 20% from the left side of the image and 70% from the top. The positioning will remain constant with different screen sizes, but you will have to make sure the aspect ratio stays constant; otherwise, the TextView will drift.
Here is the XML for the image above:
<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>
Another way to handle positioning within a view that provides more precise targeting is to define a horizontal and vertical chain of Space views that use weights to divide up the container view. Here is the same layout as above but with a vertical boundary between two Space views at 20% of the width of the ImageView. An additional two Space views have a horizontal boundary at 70% of the container view. See Chains in the documentation for ConstraintLayout.
Here is the 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>

Evenly spacing views using ConstraintLayout

A common use for LinearLayout is to evenly space (weight) views, for example:
How do you implement evenly spaced views like this using the new ConstraintLayout?
ConstraintLayout links for reference: blog post, I/O session video
There are two ways to accomplish this using ConstraintLayout: Chains and Guidelines. To use Chains, make sure you are using ConstraintLayout Beta 3 or newer and if you want to use the visual layout editor in Android Studio, make sure you are using Android Studio 2.3 Beta 1 or newer.
Method 1 - Using Chains
Open the layout editor and add your widgets as normal, adding parent constraints as needed. In this case, I have added two buttons with constraints to the bottom of the parent and side of the parent (left side for Save button and right side for Share button):
Note that in this state, if I flip to landscape view, the views do not fill the parent but are anchored to the corners:
Highlight both views, either by Ctrl/Cmd clicking or by dragging a box around the views:
Then right-click on the views and choose "Center Horizontally":
This sets up a bi-directional connection between the views (which is how a Chain is defined). By default the chain style is "spread", which is applied even when no XML attribute is included. Sticking with this chain style but setting the width of our views to 0dp lets the views fill the available space, spreading evenly across the parent:
This is more noticeable in landscape view:
If you prefer to skip the layout editor, the resulting XML will look like:
<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">
<Button
android:id="#+id/button_save"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/button_save_text"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="4dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="#+id/button_share"
app:layout_constraintHorizontal_chainStyle="spread" />
<Button
android:id="#+id/button_share"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/button_share_text"
android:layout_marginStart="4dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="#+id/button_save"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</android.support.constraint.ConstraintLayout>
Details:
setting the width of each item to 0dp or MATCH_CONSTRAINT lets the views fill the parent (optional)
the views must be linked together bidirectionally (right of save button links to share button, left of share button links to save button), this will happen automatically via the layout editor when choosing "Center Horizontally"
the first view in the chain can specify the chain style via layout_constraintHorizontal_chainStyle, see the documentation for various chain styles, if the chain style is omitted, the default is "spread"
the weighting of the chain can be adjusted via layout_constraintHorizontal_weight
this example is for a horizontal chain, there are corresponding attributes for vertical chains
Method 2 - Using a Guideline
Open your layout in the editor and click the guideline button:
Then select "Add Vertical Guideline":
A new guideline will appear, that by default, will likely be anchored to the left in relative values (denoted by left-facing arrow):
Click the left-facing arrow to switch it to a percentage value, then drag the guideline to the 50% mark:
The guideline can now be used as an anchor for other views. In my example, I attached the right of the save button and the left of the share button to the guideline:
If you want the views to fill up the available space then the constraint should be set to "Any Size" (the squiggly lines running horizontally):
(This is the same as setting the layout_width to 0dp).
A guideline can also be created in XML quite easily rather than using the layout editor:
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/guideline"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
To create 2 views in same line, equal width, just need to define
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="#+id/button1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button 1"
app:layout_constraintEnd_toStartOf="#+id/button2"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/button2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button 2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/button1" />
</android.support.constraint.ConstraintLayout>
Note
width = 0dp (MATCH_CONSTRAINT)
Constraint of button1 and button2 must like above
Result
MORE
If you want View1 bigger than View2 you can use weight or percent.
Example, View1 width = 2 *View2 width use weight
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<Button
android:id="#+id/button3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button 3"
app:layout_constraintEnd_toStartOf="#+id/button4"
app:layout_constraintHorizontal_weight="2"
app:layout_constraintStart_toStartOf="parent"
/>
<Button
android:id="#+id/button4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button 4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toEndOf="#+id/button3"
/>
</android.support.constraint.ConstraintLayout>
Result
Example, View1 width = 2 *View2 width use percent
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<Button
android:id="#+id/button5"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button 5"
app:layout_constraintEnd_toStartOf="#+id/button6"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintWidth_percent="0.667"
/>
<Button
android:id="#+id/button6"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button 6"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/button5"
app:layout_constraintWidth_percent="0.333"
/>
</android.support.constraint.ConstraintLayout>
Result
Well if it helps someone
the key is here app:layout_constraintHorizontal_weight="1" and
the best thing about constraint layout is that it supports circular dependency and here this is what I have done using exactly that.
For first child
app:layout_constraintEnd_toStartOf="#+id/textInputSecondChild"
For second child
app:layout_constraintLeft_toRightOf="#+id/textInputFirstChild"
here is the complete demo
<android.support.design.widget.TextInputLayout
android:id="#+id/textInputParent"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<EditText
android:id="#+id/editTextParent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/state" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="#+id/textInputFirstChild"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toStartOf="#+id/textInputSecondChild"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textInputParent">
<EditText
android:id="#+id/editTextChildOne"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/pin_code" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="#+id/textInputSecondChild"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="#+id/textInputFirstChild"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textInputParent">
<EditText
android:id="#+id/editTextChildSecond"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/country" />
</android.support.design.widget.TextInputLayout>
You shoul read about weighted chains. An example of code is here.
<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="wrap_content"
>
<TextView
android:id="#+id/figure_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
app:layout_constraintEnd_toStartOf="#id/figure_2"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
tools:text="1"
/>
<TextView
android:id="#+id/figure_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
app:layout_constraintEnd_toStartOf="#id/figure_3"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toEndOf="#id/figure_1"
tools:text="2"
/>
<TextView
android:id="#+id/figure_3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
app:layout_constraintEnd_toStartOf="#id/figure_4"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toEndOf="#id/figure_2"
tools:text="3"
/>
<TextView
android:id="#+id/figure_4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toEndOf="#id/figure_3"
tools:text="4"
/>
</android.support.constraint.ConstraintLayout>
So, set android:layout_width="0dp", app:layout_constraintHorizontal_weight="1" and link every view with neighbours like:
app:layout_constraintStart_toEndOf="#id/figure_2"
app:layout_constraintEnd_toStartOf="#id/figure_4"
Once you have your chained items, you can still use weights on them like relative layout to keep them evenly spaced. The example below shows how to keep them evenly spaced with different size textViews.
<TextView1
app:layout_constraintHorizontal_weight="1" />
<TextView2
app:layout_constraintHorizontal_weight="1" />
<TextView3
app:layout_constraintHorizontal_weight="1" />
<TextView4
app:layout_constraintHorizontal_weight="1" />

Categories

Resources