ImageView doesn't center on ConstraintLayout - android

I can't move the image more to the left side no matter what I'm doing. It should be nicely centered but it's not...
image
<ImageView
android:id="#+id/grid"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="#drawable/back3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/turn"
app:srcCompat="#drawable/back3"
android:layout_gravity="center"/>
Any ideas?

If the parent view is wider than the image, you need to add this to ImageView:
android:scaleType="fitCenter"
or some other appropriate value for the attribute.

When you chain your view to two points using start/end constraints, it stays in the center of those constraints by default. But have the ability to shift it's position toward end or start the layout attribute responsible for this is layout_constraintHorizontal_bias
As #Robert mentioned, you can remove that attribute or set it to 0.5
<ImageView
android:id="#+id/grid"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="#drawable/back3"
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/turn"
app:srcCompat="#drawable/back3"
android:layout_gravity="center"/>
Also I suggest you to use AppCompatImageView instead

Related

Make ViewPager Fill The Remaining Space In a ConstraintLayout

I have the following XML code , I couldn't make 'summaryViewPager' fill the remaining space vertically, until the bottom of the screen :
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.card.MaterialCardView
android:id="#+id/mainCardView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:background="#666266"
android:padding="10dp"
app:cardCornerRadius="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:layout_marginLeft="3dp"
android:layout_marginTop="2dp"
android:text="#string/category"
android:textColor="#FFBA93"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="#+id/cardView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:background="#666266"
android:padding="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/mainCardView">
<Button
android:id="#+id/shareButton"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:background="#drawable/ic_share"
app:layout_constraintEnd_toStartOf="#+id/copyButton"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/seenImageView"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="3dp"
android:layout_marginLeft="3dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:contentDescription="#string/todo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#+id/favoriteButton"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/unseen" />
</com.google.android.material.card.MaterialCardView>
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/summaryViewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/cardView2" />
</androidx.constraintlayout.widget.ConstraintLayout>
The above code doesn't show the PageViewer at all below cardView2 , however when I set android:layout_height="500dp it does show PageViewer, but it doesn't fill the whole screen.
Initial Thoughts
I copy pasted your Layout into Android Studio 4.x, replaced all #string references with "something", and all #drawables with an existing one (from #android:drawable/) so my layout would render.
From what I see, it looks correct:
I noticed some inconsistencies in your Layout.
CardView Number 1 (top)
Careful with Padding on a CardView (don't know your min/max API so, not sure if this applies to you).
Your CardView has no constrain for its BOTTOM, it's left to "whatever size you compute after wrapping" (Height = wrap, Bottom_To = null).
This ^ means that for the CardView to have a height, all its innerwidgets must compute their sizes, so the top card view knows how much size + margin + padding it needs. It doesn't depend on OTHER widgets (that are not children) because its constrains are all to the parent. (rather it only needs its parent).
CardView Number 2 (bottom)
This cardView wraps all its dimensions but has the same issue as the one above, it doesn't constraint its height (except to be pinned at the bottom of the previous one, CardView 1). Again, this is fine, so as long as nobody depends on this (which is not true). This one has to wait on more widgets to know its size, because it has to wait on the CardView1 to know how much space is left, and also needs to know how much its children need. It's not too hard because both (the ImageView and the Button) have fixed sizes (20 and 30 dp respectively) + margins/padding.
The children of a MaterialCardView cannot/should not/must not use constraints because a CardView is not a ConstraintLayout, rather a glorified FrameLayout, which can only hold ONE child (or if it has more, it will put them on on top of the other). So all those constraints (for the shareButton and seenImageView) are ignored.
The solution to the above, is to have an inner ConstraintLayout as the sole child of a CardView, and inside this inner CL, put all your children and their constraints. The inner ConstraintLayout should have its width/height as either wrap_content or match_parent so they use the constraints of the parent. Since htey have fixed sizes, this is not an issue. (and if they didn't it wouldn't be an issue, but would need another measure pass).
Regardless of this, this second CardView is able to calculate its height, because its children are reporting a size of 20+30 (overlapped) + 15 margin top (image) so.. all this combined is likely 45dp~ of height (since they overlap only the biggest numbers apply here).
All the constraints are ignored for these two children.
ViewPager (bottom)
Finally we reach the VPager. This viewPager is match_parent for its width (since you have constraints to the start/end, you should just use 0dp). And it has wrap_content for its height.
layout_height=wrap_content -> this is a problem here. Because the viewPager doesn't (at the time of layout pass/measure) yet know what its contents are going to be. So you probably want this to be 0dp and let the ViewPager use all available space after the above has been calculated.
The marginTop you have here, will not work as it is, because the CardView 1 and 2 have no bottom constrain, so this one would have to create yet another layout/measure pass after it's all said and done to be able to apply a margin (that's how it works).
Ok Enough Rant - what can you do?
I'd "fix" the layout by adding the correct constraints and -if needed- use a VerticalChain and biasing for all widgets.
I'd fix the middle (Cardview 2) contents by wrapping the textview and imageView in a ConstraintLayout.
I'd remove left/right and replace with start/end (unless you target API 16 or below).
I'd set the ViewPager to 0dp on both dimensions.
The children of your CardView2 refer to copyButton and favoriteButton but these don't exist in the Layout you pasted, so I assume you have more buttons there).
Full Version (modified)
And in case you wonder, here's what I did ( I added a color to the VP's background so it was easier to "see").
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.card.MaterialCardView
android:id="#+id/mainCardView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
app:layout_constraintVertical_chainStyle="packed"
android:background="#666266"
android:padding="10dp"
app:cardCornerRadius="20dp"
app:layout_constraintBottom_toTopOf="#id/cardView2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:layout_marginTop="2dp"
android:text="Category"
android:textColor="#FFBA93"
android:textSize="20sp"
android:textStyle="bold" />
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="#+id/cardView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:background="#666266"
android:padding="10dp"
app:layout_constraintBottom_toTopOf="#id/summaryViewPager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/mainCardView">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/innerCardView2Root"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="#+id/shareButton"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="5dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="5dp"
android:background="#android:drawable/ic_menu_share"
app:layout_constraintEnd_toStartOf="#+id/seenImageView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/seenImageView"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="3dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="5dp"
android:contentDescription="#null"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/shareButton"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#android:drawable/ic_menu_search" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/summaryViewPager"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="2dp"
android:background="#color/colorSecondary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/cardView2" />
</androidx.constraintlayout.widget.ConstraintLayout>

Custom Layout is not being centered inside a listview using constraintLayout

I'm trying to center the items of my listview which are a custom view to the center of a constraint layout but they only show at the left side.
I tried setting the horizontal bias of both the constraint and the list view to 50 and to 100 but the listView still doesn't show the Items in the center or anywhere else other than at the start. I tried using layout_centerhorizontal="true" but that does not work either. Bare in mind that the listview is being inflated inside a fragment which is inside a ViewPager.
UPDATE:
I fixed it by wrapping the custom_item xml inside a linear layout which filled the entire screen horizontally and added horizontal center gravity to the item.
Here is my xml:
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/parentConstraint_tutor_fragment_loged"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="32dp"
android:layout_marginBottom="8dp"
android:visibility="visible"
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.0">
<ListView
android:id="#+id/tutorListView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:divider="#null"
android:dividerHeight="0dp"
android:listSelector="#android:color/transparent"
android:overScrollMode="never"
android:scrollbars="none"
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.0"/>
</androidx.constraintlayout.widget.ConstraintLayout>
And here is the custom_Item:
<?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="323dp"
android:layout_height="68dp"
android:layout_gravity="center_horizontal"
android:background="#drawable/tutor_entry_panel_phones_selector">
<ImageView
android:id="#+id/tutorIcon_cell"
android:layout_width="35dp"
android:layout_height="33dp"
android:layout_marginStart="12dp"
android:layout_marginLeft="12dp"
android:scaleType="fitCenter"
android:tint="#color/BlueColor"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/login_tutor_icon" />
<TextView
android:id="#+id/userLogin_nameTextV"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_marginEnd="22dp"
android:layout_marginRight="22dp"
android:gravity="center"
android:textColor="#color/BlueColor"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/deleteIconPhones"
app:layout_constraintStart_toEndOf="#+id/tutorIcon_cell"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/deleteIconPhones"
android:layout_width="32dp"
android:layout_height="36dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I just need the custom view inside the listview to be in the center of the constraint layout. here is a Screenshot of the current state:
https://ibb.co/88KVQvq
desired state will be with the custom_item in the middle and not in the beginning of the constraintLayout:
https://ibb.co/XbtWJkw
custom_item snapshot:
https://ibb.co/rkDXmGs
Blueprint view of the viewpager in which this fragment is contained (Im trying to get the custom_item centered inside the viewpager's fragment):
https://ibb.co/XVR02Kq
If it is a custom_listView then Do change in the custom_layout.xml - (Whatever you gave the name of the layout) and check it again.
First of all, all these parameters in <ConstraintLayout ...> element are unnecessary:
android:layout_width="0dp"
android:layout_height="0dp"
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.0"
They don't have any meaning. Those parameters are used on elements inside ConstraintLayout, not on Layout itself. Layout fills all available space (in case of activity, it is whole screen), whatever layout are you using. Generally, just use match_parent/wrap_content in width/height, and that's it.
Secondly, based on your screen I cannot say where the ViewPager is located. It looks like ViewPager itself is left aligned in whole activity, but I am not sure. If it is, than it is the reason why everything squashed to left side. You can activate Developer Options on your device, then find and activate option Show Layout Bounds, than you will see on your screen borders of all rendered elements and see if this is the case.
Additionally, your item does not have very proper layout. If you want to chain these three elements, all of them should have all four layout_constraintXxx_toYyyOf elements. You can find it described here. I am not sure that this is the cause of your problem, but certainly is something that might cause the issue. Also, unless you really need to use ConstraintLayout, I would advise to use here LinearLayout, or even just plain text/button with drawableStart and drawableEnd set. It is documented on TextView class (Button is just a subclass of a TextView.)

TextView going out of screen with constraintLayout

I am using ConstraintLayout to create below xml in my application.
As you can see my first item is fine, But in the second one, some parts of my textView are not on the screen!
This is my XML code:
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/ly_user"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
app:layout_constraintRight_toRightOf="parent"
android:id="#+id/im_user_icon"
android:layout_width="#dimen/default_message_icon_size"
android:layout_height="#dimen/default_message_icon_size"
android:src="#drawable/user_pacific"/>
<ImageView
app:layout_constraintTop_toBottomOf="#+id/im_user_icon"
app:layout_constraintRight_toLeftOf="#+id/im_user_icon"
android:id="#+id/im_user_arrow"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="#drawable/arrow_bg1"/>
<View
android:id="#+id/view_user_guidLine"
android:layout_width="1dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="#id/im_user_arrow"
app:layout_constraintRight_toRightOf="#id/im_user_arrow"/>
<TextView
app:layout_constraintTop_toBottomOf="#+id/im_user_icon"
app:layout_constraintRight_toLeftOf="#+id/view_user_guidLine"
android:id="#+id/tv_user_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="right"
android:padding="8dp"
android:minWidth="#dimen/default_message_textarea_width"
android:minHeight="#dimen/default_message_textarea_height"
android:background="#drawable/bg_right_text"
android:textColor="#android:color/white"/>
</android.support.constraint.ConstraintLayout>
I Know I can fix this problem to adding below line to the textView, But I need my textView be wrapContent.
app:layout_constraintLeft_toLeftOf="parent"
You can set your TextView's width to wrap_content, but to prevent it from expanding outside of screen you need to add the left constraint as well and use app:layout_constrainedWidth="true" to enforce constraints.
Now, to make the TextView stick to the right, you need to add app:layout_constraintHorizontal_bias="1", which will align it to its right constraint.
So all in all, these are the changes needed for the TextView:
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="1"
android:layout_width="wrap_content"
Add these following line in your code in your TextView
app:layout_constraintWidth_percent="0.6"
first line layout_constraintWidth_percent is 60 percent of your phone screen width you can change it according to your need.
Accepted answered works but on my side I use android:layout_width="0dp" because my TextView is in the middle of two elements.
<TextView
android:id="#+id/my_id_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/long_text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/second_vertical_divider_view"
app:layout_constraintStart_toEndOf="#+id/first_vertical_divider_view"
app:layout_constraintTop_toTopOf="parent" />
Accepted answer didn't helped in my case. Alternative solution can look like that:
<ConstraintLayout>
<TextView
android:id="#+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
app:layout_constraintEnd_toStartOf="#+id/option_info"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_max="wrap" />
<ImageView
android:id="#+id/option_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_info"
app:layout_constraintBottom_toBottomOf="#+id/title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/title"
app:layout_constraintTop_toTopOf="#+id/title" />
</ConstraintLayout>
The idea is to prevent one view pushing another while expanding by creating a chain and add some constraint params to hold influenced view in view's border.
Hope it still will help somebody!

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>

Can't keep views from overlapping even when I use layout_margin

I can't figure out how to render my listItems correctly. Everything seems fine until the text title is too long. Looking at the pics below, I have the Title anchored on the left side of the listItem View and to the right of the imageView. I've even tried anchoring the right side to the right edge of the entire view but with no success. If the user enters a title too long the views overlap.
I want the title to be centered between the imageview and the left side of the entire listItem view. I have provided pics of how this all renders. Any help would be greatly appreciated. When the title gets long enough, it wraps the text which is fine. At this point I'd even settle for the trailing ... but I would prefer to have the text wrap. I just don't want to overlap the imageview. I have also posted the xml code
<?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="wrap_content"
android:orientation="vertical"
android:padding="5dp"
android:id="#+id/list_item_container">
<TextView
android:id="#+id/match_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textSize="16sp"
tools:text="Match Name"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="16dp"
app:layout_constraintRight_toLeftOf="#+id/imageView"
android:layout_marginRight="8dp"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"/>
<TextView
android:id="#+id/match_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Match Date"
android:textAlignment="center"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintRight_toLeftOf="#+id/imageView"
android:layout_marginRight="8dp"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="#+id/match_name"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"/>
<ImageView
android:id="#+id/imageView"
android:layout_width="60dp"
android:layout_height="45dp"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_marginEnd="8dp"
android:layout_weight="1"
app:srcCompat="#drawable/ic_more_vert_black_24dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
android:layout_marginRight="68dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"
app:layout_constraintVertical_bias="0.484"/>
<TextView
android:id="#+id/match_id_hidden"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:visibility="invisible"
tools:layout_editor_absoluteY="67dp"
tools:layout_editor_absoluteX="24dp"/>
</android.support.constraint.ConstraintLayout>
Inside the ConstraintLayout try to always use "0dp" for your heights and widths and always set the app:layout_constraint..._to...Of for all 4 sides for all your views. Examine the outcome and then fine tune to get the expected result. Do this in the XML instead of in the visual editor; in my experience it is quicker and it avoids the layout_editor_absolute... settings.
Set android:layout_width="0dp" for both your TextViews. In a ConstraintLayout, a value of "0dp" basically means match the constraints. A value of "wrap_content" doesn't take constraints into account when measuring the views, just when positioning them.

Categories

Resources