I want to show an icon in the top right corner of an image. Also, it should be slightly offset. And finally, the combination of both should be scalable, so that doubling the total width results in the image as well as the icon having thwice the original width. Of course, the aspect ration should be kept so that the height doubles as well.
As the description of that actually simple problem is quite complex, here's an artful drawing illustrating the subject :)
So, let's say I have a RecyclerView with a GridLayout where each image tile has a width of 200dp. Then, the gray area should have a width and height of 200dp, the orange icon has a width and height of 50dp, the offset of the icon to the blue image's border is 25dp and so on.
And if I decide to double the number of columns in my GridLayout, the gray area has a width and height of 100dp etc.
Here's what I tried so far:
I started out with a FrameLayout which works fine for the simplest cases but becomas problematic as soon you want to specify dimensions with percentages.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="50dp"
android:adjustViewBounds="true"
app:srcCompat="#drawable/blueShip200x200" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_marginRight="25dp"
android:layout_marginTop="25dp"
app:srcCompat="#drawable/new50x50" />
</FrameLayout>
Then, I learned about the PercentFrameLayout that has been introduced with the support library, recently - and has already been deprecated: https://developer.android.com/reference/android/support/percent/PercentFrameLayout.html
So now the advice is to use ConstraintLayout instead (see link above) where you can use helper guidelines that allow you to define their position with percentages.
Fortunately, the docs give an example how to replace the PercentFrameLayout which works great if the gray box has a fixed width and height:
<android.support.constraint.ConstraintLayout
android:layout_width="200dp"
android:layout_height="200dp">
<android.support.constraint.Guideline
android:id="#+id/left_image_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".25" />
<android.support.constraint.Guideline
android:id="#+id/right_image_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".75" />
<android.support.constraint.Guideline
android:id="#+id/top_image_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".25" />
<android.support.constraint.Guideline
android:id="#+id/bottom_image_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".75" />
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="#+id/bottom_image_guideline"
app:layout_constraintLeft_toLeftOf="#+id/left_image_guideline"
app:layout_constraintRight_toRightOf="#+id/right_image_guideline"
app:layout_constraintTop_toTopOf="#+id/top_image_guideline"
app:srcCompat="#drawable/blueShip200x200" />
<android.support.constraint.Guideline
android:id="#+id/left_icon_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".625" />
<android.support.constraint.Guideline
android:id="#+id/right_icon_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".875" />
<android.support.constraint.Guideline
android:id="#+id/top_icon_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".125" />
<android.support.constraint.Guideline
android:id="#+id/bottom_icon_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".375" />
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="#+id/bottom_icon_guideline"
app:layout_constraintLeft_toLeftOf="#+id/left_icon_guideline"
app:layout_constraintRight_toRightOf="#+id/right_icon_guideline"
app:layout_constraintTop_toTopOf="#+id/top_icon_guideline"
app:srcCompat="#drawable/new50x50" />
</android.support.constraint.ConstraintLayout>
But if you do not specifiy fixed dimensions... it doesn't.
Adapting the following lines from the FrameLayout example (layout_width, layout_height, adjustViewBounds) results in the ConstraintLayout getting a height of 0.
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="#+id/bottom_image_guideline"
app:layout_constraintLeft_toLeftOf="#+id/left_image_guideline"
app:layout_constraintRight_toRightOf="#+id/right_image_guideline"
app:layout_constraintTop_toTopOf="#+id/top_image_guideline"
app:srcCompat="#drawable/blueShip200x200" />
I hope it's possible to solve this problem non-programmatically with some changes to the layout file. Basically, it's just adjustViewBounds that is not working with the ImageView's width and height set to match_constraint (0dp).
Also, if possible, I'd like to stick with ConstraintLayout. Maybe one can work around the problem using LinearLayouts with Spaces and layout_weight - I haven't tried that yet.
Thanks!
you can create a layout using a constraint layout.
first you split the layout into 5x5 using some views as a guide.
the key is to use the horizontal and vertical weights.
<!--GUIDE LINE-->
<TextView
android:id="#+id/guide_1"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#color/primary_light"
android:text="25%"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="25"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/guide_2"
app:layout_constraintTop_toBottomOf="#+id/guide_2"
app:layout_constraintVertical_weight="25" />
<TextView
android:id="#+id/guide_2"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#color/primary_light"
android:text="37.5%"
app:layout_constraintBottom_toTopOf="#id/guide_1"
app:layout_constraintHorizontal_weight="37.5"
app:layout_constraintLeft_toRightOf="#id/guide_1"
app:layout_constraintRight_toLeftOf="#id/guide_3"
app:layout_constraintTop_toBottomOf="#id/guide_3"
app:layout_constraintVertical_weight="37.5" />
<TextView
android:id="#+id/guide_3"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#color/primary_light"
android:text="12.5%"
app:layout_constraintBottom_toTopOf="#id/guide_2"
app:layout_constraintHorizontal_weight="12.5"
app:layout_constraintLeft_toRightOf="#id/guide_2"
app:layout_constraintRight_toLeftOf="#id/guide_4"
app:layout_constraintTop_toBottomOf="#id/guide_4"
app:layout_constraintVertical_weight="12.5" />
<TextView
android:id="#+id/guide_4"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#color/primary_light"
android:text="12.5%"
app:layout_constraintBottom_toTopOf="#id/guide_3"
app:layout_constraintHorizontal_weight="12.5"
app:layout_constraintLeft_toRightOf="#id/guide_3"
app:layout_constraintRight_toLeftOf="#id/guide_5"
app:layout_constraintTop_toBottomOf="#id/guide_5"
app:layout_constraintVertical_weight="12.5" />
<TextView
android:id="#+id/guide_5"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#color/primary_light"
android:text="12.5%"
app:layout_constraintBottom_toTopOf="#id/guide_4"
app:layout_constraintHorizontal_weight="12.5"
app:layout_constraintLeft_toRightOf="#id/guide_4"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_weight="12.5" />
after you create the guide, you can put the images you want with the guide line...
the two views would be something like the following.
<TextView
android:text="MAIN ICON"
android:textColor="#color/icons"
android:gravity="center"
android:textSize="60sp"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="#id/guide_2"
app:layout_constraintBottom_toBottomOf="#id/guide_2"
app:layout_constraintTop_toTopOf="#id/guide_3"
app:layout_constraintRight_toRightOf="#id/guide_3"
android:background="#color/primary"/>
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="#id/guide_4"
app:layout_constraintRight_toRightOf="#id/guide_4"
app:layout_constraintBottom_toBottomOf="#id/guide_3"
app:layout_constraintLeft_toLeftOf="#id/guide_3"
android:background="#color/accent"
android:text="NEW"
android:gravity="center"
android:textSize="40sp"
android:textColor="#color/icons"/>
FIxing dimension of small image will help you attain that kind of UI. Please look into code below
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="25dp"
android:paddingRight="25dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:id="#+id/image"
app:layout_constraintBottom_toBottomOf="parent"
app:srcCompat="#drawable/blue200" />
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
app:layout_constraintTop_toTopOf="#+id/image"
app:layout_constraintRight_toRightOf="#+id/image"
app:srcCompat="#drawable/new50x50" />
</android.support.constraint.ConstraintLayout>
What you want to accomplish can be done with some recent additions to ConstraintLayout. I did the following with version 1.1.0-beta3. See the documentation here.
With later releases of ConstrainLayout, we can now specify the width and height of a view as a percentage of the containing view's width/height. The blue box is sized at 50% of the width/height of the gray area and centered.
The orange box is sized at 25% of the container's width and height. It is centered on the top right corner of the blue box by setting its start and end sides to the end of the blue box and its top and bottom to the top.
The layout will accommodate all sizes but, as you mention, the aspect ratios must be respected.
<android.support.constraint.ConstraintLayout
android:layout_width="200dp"
android:layout_height="200dp">
<ImageView
android:id="#+id/boat"
android:layout_width="0dp"
android:layout_height="0dp"
android:adjustViewBounds="true"
android:src="#drawable/boat"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_default="percent"
app:layout_constraintHeight_percent="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.5" />
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:src="#drawable/new_square"
app:layout_constraintBottom_toTopOf="#id/boat"
app:layout_constraintEnd_toEndOf="#id/boat"
app:layout_constraintHeight_default="percent"
app:layout_constraintHeight_percent="0.25"
app:layout_constraintStart_toEndOf="#id/boat"
app:layout_constraintTop_toTopOf="#id/boat"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0..25" />
</android.support.constraint.ConstraintLayout>
Here are the images I used:
Related
I am trying in a constraint layout to make two buttons take the same size as the one with more text.
This is what I have
This is what I want
Playing with the height attribute of the buttons, setting it to "0" you can get one button to follow the other, but the other does not do the same
here is the code
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/tools_ly_first_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/margin_bubble_answer_buttons"
android:layout_marginEnd="#dimen/margin_bubble_answer_buttons"
android:layout_marginBottom="2dp"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="#+id/tools_btn_1"
app:layout_constraintStart_toEndOf="#+id/tools_btn_1"
tools:visibility="visible">
<Button
android:id="#+id/tools_btn_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#drawable/btn_round_confirmation_yes"
android:fontFamily="#font/calibri_regular"
android:textAllCaps="false"
android:textColor="#color/white"
android:layout_marginEnd="1dp"
android:textSize="14sp"
android:padding="#dimen/padding_bubble_answer_buttons_text"
tools:text="Perfect asdasdas."
app:layout_constraintEnd_toStartOf="#+id/tools_btn_2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#id/tools_ly_first_buttons"
app:layout_constraintBottom_toBottomOf="#id/tools_ly_first_buttons"/>
<Button
android:id="#+id/tools_btn_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#drawable/btn_round_confirmation_yes"
android:fontFamily="#font/calibri_regular"
android:textAllCaps="false"
android:textColor="#color/white"
android:padding="#dimen/padding_bubble_answer_buttons_text"
android:layout_marginStart="1dp"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/tools_btn_1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="Perfect Perfect square trition. Perfect Perfect square trition. Perfect Perfect square trition. Perfect Perfect square trition. Perfect Perfect square trition. Perfect Perfect square trition." />
</androidx.constraintlayout.widget.ConstraintLayout>
You can do this by wrapping the two buttons into a LinearLayout (or another ConstraintLayout) and setting their heights both to match_parent while setting the height of the container view to wrap_content.
If your ConstraintLayout is already a container to be nested in other views, than the extra nesting is not necessary. Just set the button heights to match_parent and they will fill the container.
<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"
tools:context=".MainActivity">
<LinearLayout
android:id="#+id/button_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
android:id="#+id/btnLeft"
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="Short Text"
android:layout_weight="1.0"
android:layout_margin="4dp"
/>
<Button
android:id="#+id/btnRight"
android:text="Long Text Taking Up Many Many Many Lines of Space and More than One Line Definitely"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:layout_margin="4dp"
/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Here's what this produces - doesn't matter which button has the long text.
Note
In the XML you shared, the parent ConstraintLayout appears to be constrained to one of its child views (tools_btn_1). This is probably not valid.
On some screens the text and image overlap. In that case I want to move the text upwards.
I place a TextView at a percentage position using a guideline. This is the preferred position of the text. Under it is an image with layout_width="match_parent" and ratio preserved. Depending on the screen aspect ratio, the image will become high enough to overlap with the text. In that case, I want the text to move upwards. So I want a "minimum constraint" of like 8dp between the text and image.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineGoldenRatio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.381966" />
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Keep me from overlapping"
app:layout_constraintTop_toTopOf="#+id/guidelineGoldenRatio"
app:layout_constraintBottom_toTopOf="#+id/guidelineGoldenRatio"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="#drawable/ic_supercat_popular" />
</androidx.constraintlayout.widget.ConstraintLayout>
You can use a Barrier widget. Set the barrier's diection to "Top" and set the reference ids to your image and the guideline. (If you can't reference the guideline, constrain a Space widget to the guideline and set the Space widget's id in the referenced ids of the barrier.)
Now constrain the text to the barrier with an 8dp margin. The text will now float with the barrier which will always be 8dp above the higher of the guideline and image.
Based on Cheticamp's answer:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineGoldenRatio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.381966" />
<androidx.constraintlayout.widget.Barrier
android:id="#+id/barrier"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:barrierDirection="top"
app:constraint_referenced_ids="imageView, guidelineGoldenRatio" />
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Keep me from overlapping"
android:textSize="30dp"
app:layout_constraintBottom_toTopOf="#+id/barrier"
app:layout_constraintTop_toTopOf="#+id/barrier"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:adjustViewBounds="true"
android:paddingTop="18dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="#drawable/ic_supercat_popular" />
</androidx.constraintlayout.widget.ConstraintLayout>
Note: the minimum distance between text and image goes into image padding. This padding should also compensate for half text height (when centering text vertically around guideline).
How about binding TextView to the Image, and setting padding simply? The image would be always screen-wide, and having a height that depends on the screen type - but the text would be always 8dp over the image.
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Keep me from overlapping"
android:paddingBottom="8dp"
app:layout_constraintBottom_toTopOf="#+id/guidelineGoldenRatio"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="#drawable/ic_supercat_popular" />
I am trying to set up a layout for a counting app, which has a large circular button slightly above the centre of the screen and a counter display below it. I'm having trouble keeping the circle circular, entirely on the screen, and not overlying the other view in all situations.
The setup I'm currently using is a ConstraintLayout with two TextViews. The button TextView uses an xml oval as its background, and is set to be circular with the "layout_constraintDimensionRatio" attribute set to one. In portrait mode the width is set to 80% of the available space, and all is well when the screen is fairly standard in normal use.
The problem occurs if the available screen dimensions for the app are more square so that the vertical dimension is smaller than the horizontal dimension. In this case the width is still set first so my circle covers the other view or partially slips off screen.
Currently in the landscape layout I have the timer off to one side. Ideally in the landscape layout I would keep the button centred and the counter to the right, but to stop increasing the size of the button if there is not enough space for the timer.
I think that ideally I would set the layout up to check whether the horizontal or the vertical space is shorter initially, then set the smaller dimension first. Is this possible? Or perhaps is there a better approach to achieving my desired layout?
Any help would be really appreciated,
Thank you,
Katie
This is the default xml layout:
<?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="#android:color/white"
tools:context=".ui.CounterFragment">
<ImageView
android:id="#+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="#string/content_description_background_image"
android:scaleType="fitStart"
android:src="#drawable/dog_image_jpg_light"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1"
tools:visibility="visible" />
<TextView
android:id="#+id/timer_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/timer_display"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/guidelineHorizontal" />
<TextView
android:id="#+id/counter_button"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#drawable/circle_selector"
android:contentDescription="#string/counter_button_content_description"
android:text="#string/counter_text"
app:layout_constraintBottom_toTopOf="#+id/timer_display"
app:layout_constraintDimensionRatio="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.375"
app:layout_constraintWidth_percent=".8" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineVertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.75" />
</androidx.constraintlayout.widget.ConstraintLayout>
This is the landscape layout:
<?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="#android:color/white"
tools:context=".ui.CounterFragment">
<ImageView
android:id="#+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="#string/content_description_background_image"
android:scaleType="fitStart"
android:src="#drawable/dog_image_jpg_light"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1"
tools:visibility="visible" />
<TextView
android:id="#+id/timer_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/timer_display"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/counter_button"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/counter_button"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#drawable/circle_selector"
android:contentDescription="#string/counter_button_content_description"
android:text="#string/counter_text"
app:layout_constraintBottom_toBottomOf="#id/guidelineHorizontal"
app:layout_constraintDimensionRatio="1"
app:layout_constraintEnd_toStartOf="#id/guidelineVertical87"
app:layout_constraintHeight_percent="0.8"
app:layout_constraintStart_toEndOf="#id/guidelineVertical12"
app:layout_constraintTop_toTopOf="#id/guidelineHorizontal" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineVertical75"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.75" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineVertical12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.125" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineVertical87"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.875" />
</androidx.constraintlayout.widget.ConstraintLayout>
As you suggest, the primary issue with your layout is the percentage width/height set at 80% and driving the rest of the layout. You are losing control of the circle height and nothing keeps it from growing to cover other views.
Take a look at ConstraintLayout chains. They are a powerful tool and will let you tie your views together so they don't trounce one another. They will help you solve the overlay problem.
You will still want to set the width of the circle to 80% of the width or height depending on the orientation of the device. I assume that you want the side margins to be such that the circle can be 80% of the view but will allow the circle to be smaller if it needs to fit the screen and not overlap the other views. One way to do this is to define two Space widgets that are 10% of the layout width and 10% high. Place one in the upper left corner of the layout and the other in the lower right. Constrain the circle to these Space widgets on the left, top and right. Place the circle in a vertical chain with the TextView below.
Here is a mock up of what it would look like. You will have to work with your layout to get it right, but these are some concepts that should help. (Is seems to me that this can also be done without the Space widgets, but that solution is not occurring to me right now. I'll post back if it dawns on me.)
The XML follows the GIF.
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white">
<TextView
android:id="#+id/timer_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/timer_display"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/counter_button" />
<TextView
android:id="#+id/counter_button"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#drawable/circle"
android:text="#string/counter_text"
app:layout_constraintBottom_toTopOf="#+id/timer_display"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="#+id/spaceBottomRight"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#+id/spaceStart"
app:layout_constraintTop_toBottomOf="#+id/spaceStart"
app:layout_constraintVertical_bias="0.375"
app:layout_constraintVertical_chainStyle="packed" />
<Space
android:id="#+id/spaceBottomRight"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.10"
app:layout_constraintWidth_percent="0.10" />
<Space
android:id="#+id/spaceStart"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintHeight_percent="0.10"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.10" />
</androidx.constraintlayout.widget.ConstraintLayout>
I'm having a bit of a problem with ConstraintLayout in Android.
Observe the following illustration:
I would like to draw your attention to the row of three views across the middle: the TextView, and the two Buttons.
The dotted vertical and horizontal lines are fixed guidelines (expressed in terms of percentage of screen height/width), and are used to constrain these views to.
The TextView is constrained in all 4 directions as you can see.
The Button on the far right is constrained in 3 directions: top, bottom, and right... and has an aspect ratio constraint on it of 1:1.
Now, the Button in the middle is only constrained on top and bottom, and also has an aspect ratio applied of 1:1.
Everything is great so far... but what if we want to keep everything exactly the same except center the middle button such that it has equal space to its right and to its left?
One might expect that simply applying horizontal constraints to its nearest neighbors would do the trick... but no.
This is the result:
So... the size of the button is increasing for some reason. Why?
It seems to me that Android Studio is applying the 1:1 aspect ratio rule (in this case) by saying "height is a function of width..." that is, width is calculated first (based on the newly applied constraints) and therefore takes precedence.
If it had simply done it the other way around and said "width = height" with height taking precedence... (the same way it was doing prior to those final constraints being applied), then everything would be fine.
So... in other words, how can you center a "middle" view between two other "right" and "left" views and still maintain:
1) All three views have matching heights since they are bound by the same horizontal constraints.
2) The left view is in a fixed position.
3) The right view has a 1:1 aspect ratio and is not allowed to separate from its right-side guideline (fixed position).
?
EDIT: I have made the following XML snippet for anyone that wants to play with it:
(Remember the three rules above. Have fun!)
<?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="com.example.boober.deletethis.MainActivity">
<android.support.constraint.Guideline
android:id="#+id/guidelineH1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.45" />
<android.support.constraint.Guideline
android:id="#+id/guidelineH2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.55" />
<android.support.constraint.Guideline
android:id="#+id/guidelineV1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.50" />
<TextView
android:id="#+id/textView"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#color/colorPrimary"
android:text="1"
android:textAlignment="center"
android:gravity="center_vertical"
app:layout_constraintBottom_toTopOf="#+id/guidelineH2"
app:layout_constraintEnd_toStartOf="#+id/guidelineV1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/guidelineH1" />
<Button
android:id="#+id/button"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="3"
app:layout_constraintBottom_toTopOf="#+id/guidelineH2"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/guidelineH1" />
<Button
android:id="#+id/button2"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="2"
app:layout_constraintBottom_toTopOf="#+id/guidelineH2"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="#+id/guidelineH1"
tools:layout_editor_absoluteX="219dp" />
</android.support.constraint.ConstraintLayout>
Updated:
<?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">
<android.support.constraint.Guideline
android:id="#+id/guidelineH1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.45" />
<android.support.constraint.Guideline
android:id="#+id/guidelineH2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.55" />
<android.support.constraint.Guideline
android:id="#+id/guidelineV1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.50" />
<TextView
android:id="#+id/textView"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#color/colorPrimary"
android:gravity="center_vertical"
android:text="1"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="#+id/guidelineH2"
app:layout_constraintEnd_toStartOf="#+id/guidelineV1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/guidelineH1" />
<Button
android:id="#+id/button"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="3"
app:layout_constraintBottom_toTopOf="#+id/guidelineH2"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/guidelineH1" />
<android.support.constraint.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/guidelineH2"
app:layout_constraintEnd_toStartOf="#+id/button"
app:layout_constraintStart_toEndOf="#+id/textView"
app:layout_constraintTop_toTopOf="#+id/guidelineH1">
<Button
android:id="#+id/button2"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
I used constraintLayout and layout_constraintDimensionRatio="1:1"
(width is wrap_content, height is 0dp (match_constraint))
As a result, I expected width and height to be 1:1, but it's not working.
What is wrong?
I attached code and screenshot.
<?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">
<TextView
android:id="#+id/t1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:background="#android:color/holo_blue_bright"
android:gravity="center"
android:text="Hello World!11"
app:layout_constraintDimensionRatio="1:1" />
</android.support.constraint.ConstraintLayout>
screenshot
I quote android developer site about Constraintlayout.
https://developer.android.com/reference/android/support/constraint/ConstraintLayout.html#DimensionConstraints
Ratio :: 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_constraintDimentionRatio to a given ratio. For
example:
<Button android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1" />
will set the height of the button to be the same as its width.
but it was not working.
You forget to add your constraints
<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">
<TextView
android:id="#+id/t1"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:background="#android:color/holo_blue_bright"
android:gravity="center"
android:text="Hello World!11"
app:layout_constraintDimensionRatio="1" />
</android.support.constraint.ConstraintLayout>
0dp is only applied to the child views of ConstraintLayout.
Any view should apply the attribute rules of its parent.
As off version 1.1.0 this has changed.
You can now define:
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintDimensionRatio="W,1:1"
app:layout_constraintDimensionRatio="H,1:1"
Check the link below to find all the documentation regarding DimensionConstraints:
Link to the docs
In my case I have a problem like i have to fill my layout inside container with A4 size paper ratio.
Problem
I am getting A4 size resume pages as images from backend so i have to append those images in Viewpager in which i am using ImageView to display those images.
Solution
I went through Constraint layout document in which Ratio section is there. So i can use layout_constraintDimensionRatio for solving my problem.
So my xml that is used to Display the whole Layout is following, in my case i have used app:layout_constraintDimensionRatio="1:1.27" as with:height ratio but the actual ratio is app:layout_constraintDimensionRatio="1:1.41"
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/orange">
<!-- divider line which i used as restricting my A4 size container height-->
<View
android:id="#+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/headline_title_color"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias=".85"/>
<!-- A4 size Image View-->
<ImageView
android:id="#+id/resumeContainer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="12dp"
android:layout_marginTop="16dp"
android:layout_marginRight="12dp"
android:layout_marginBottom="16dp"
android:background="#color/green"
android:text="#string/change"
android:src="#drawable/banner"
app:layout_constraintBottom_toTopOf="#id/divider"
app:layout_constraintDimensionRatio="1:1.27"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<!-- for Bottom two buttons -->
<com.bold.job.utils.CustomButton
android:id="#+id/preview"
style="#style/tertiaryButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:onClick="preview"
android:text="#string/preview_resume"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#id/guideline"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="#id/divider"
/>
<android.support.constraint.Guideline
android:id="#+id/guideline"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<com.bold.job.utils.CustomButton
android:id="#+id/preview2"
style="#style/tertiaryButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:onClick="preview"
app:layout_constraintLeft_toRightOf="#id/guideline"
app:layout_constraintRight_toRightOf="parent"
android:text="#string/preview_resume"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="#id/divider"
/>
</android.support.constraint.ConstraintLayout>
Please notice the last line, adding constraints around the edges makes the constraint work.
You can also use the design view in Studio, and drag and drop the constraints between objects.
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Available chats" />
<ListView
android:id="#+id/listChats"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#+id/textView"/>