Could someome explain me why android:layout_marginBottom doesn't work in a Spinner?:
<?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">
<Spinner
android:id="#+id/spinner2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginBottom="20dp"/>
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/spinner2" />
</androidx.constraintlayout.widget.ConstraintLayout>
It doesn't matter if I use android:layout_marginBottom or android:layout_margin. However, If I use android:layout_margin it adds top, right and left margin. Why the only margin that does't work is the bottom?
Thanks.
The problem is not about Spinner specifically - if you use two TextViews the behavior stays the same.
Some observations on "why" and "how":
the Spinner top and start is constrained to the top and start of the parent ViewGroup. Since you don't specify a bottom (or end) constraint, a bottom margin is meaningless
the TextView on the other hand has a top constraint - if you let it have a top margin, this will have the desired effect.
Now you could say "well, then I'll just add the bottom constraint to the Spinner". Unfortunately this is not enough (and here I really don't know why the ConstraintLayout solver decides to ignore the margin...)
If you want to set a margin to the Spinner, then the two Views have to belong to a complete vertical chain:
parent top <- Spinner <-> TextView -> parent bottom
<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">
<Spinner
android:id="#+id/spinner2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#+id/textView"
android:layout_marginBottom="20dp"
app:layout_constraintVertical_bias="0"
app:layout_constraintVertical_chainStyle="packed"/>
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/spinner2"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
connect constrain from the button to view or parent then it will affect
$ app:layout_constraintBottom_toBottomOf="" `
You need to constraint the spinner to bottom:
1st method:
app:layout_constraintBottom_toBottomOf="parent"
2nd method:
constraint the spinner to bottom by drag it until the bottom of your root view
Related
In a ConstraintLayout, I have 2 TextView's side-by-side, and I want the right one to wrap text when it becomes too long so that it stays on the right of the left TextView, and doesn't overflow the container. Here is the code I have now:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10sp">
...
<TextView
android:id="#+id/buildingTypeLabel"
style="#style/FormLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5sp"
android:paddingBottom="5sp"
android:text="#string/reference_view_building_type"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="#id/dateLabel"
tools:text="Type de bâtiment" />
<TextView
android:id="#+id/buildingType"
style="#style/FormValue"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:ellipsize="none"
android:maxLines="100"
android:scrollHorizontally="false"
app:layout_constraintBaseline_toBaselineOf="#id/buildingTypeLabel"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toEndOf="#+id/buildingTypeLabel"
app:layout_constraintTop_toBottomOf="#id/date"
tools:text="Bâtiments gouvernementaux" />
...
</androidx.constraintlayout.widget.ConstraintLayout>
But instead of putting text text on 2 lines in the right TextView, it overflows on the right:
Note that I have tried to add app:layout_constrainedWidth="true" to the right TextView, but it doesn't change anything.
How can I strictly enforce the right and left contraints of that TextView and have it wrap text to have a smaller width when needed?
Try to change to layout_constraintEnd_toEndOf instead layout_constraintRight_toRightOf :)
Use ellipsize= "end" for the textview on the right that is extending text outside of the device screen.
Use Guidelines
Guidelines are part of the constraint layout api.
Documentation are here ->
https://developer.android.com/reference/androidx/constraintlayout/widget/Guideline
This is how you can define your guideline in xml.
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline_start"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintGuide_begin="?dialogPreferredPadding" />
Guidlines can act as a differentiating factor between the two text views that you want to segregate .
Refer to this stackoverflow answer for much better understanding
What is difference between Barrier and Guideline in Constraint Layout?
The above link will also introduce you to barriers which is also part of constraint layout api which can also help you solve the above issue.
Below you can find the solution:
<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="wrap_content"
android:padding="10sp">
<TextView
android:id="#+id/buildingTypeLabel"
style="#style/FormLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingTop="5sp"
android:paddingBottom="5sp"
android:text="#string/reference_view_building_type"
app:layout_constraintEnd_toStartOf="#id/buildingType"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/dateLabel"
tools:text="Type de bâtiment" />
<TextView
android:id="#+id/buildingType"
style="#style/FormValue"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:maxLines="100"
app:layout_constraintBaseline_toBaselineOf="#id/buildingTypeLabel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/buildingTypeLabel"
app:layout_constraintTop_toBottomOf="#id/date"
tools:text="Bâtiments gouvernementaux\n\nlef,le,flelf,le,fle," />
</androidx.constraintlayout.widget.ConstraintLayout>
My layout includes:
<?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"
tools:context=".MainActivity">
<Button
android:id="#+id/btnFindPOIs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:text="Find POIs"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnGetLocation" />
<TextView
android:id="#+id/txtPoiDetails"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnFindPOIs" />
</androidx.constraintlayout.widget.ConstraintLayout>
When the content of TextView extends beyond one line it correctly flows to a second line but the text extends right to the edge of the screen ignoring the 16dp left and right margins.
Layout Margin affects the View object, in this case a TextView. Not the actual text inside the object. So it will still go right up against the object's edge.
I would recommend using padding, it will directly affect the text. You may also want to consider adding gravity to the object?
I would also recommend using layout weights on these views or you are going to have resizing issues!
android:paddingStart="16dp"
Cheers!
I have 2 views in a layout - TextView and Button. TextView is aligned/anchored to the left side and the button is to the right side.
What I'm trying to achieve is the natural "wrap behavior" of the Button. When TextView will be wide enough so that there won't be space for the button (in the same line), it should move below the TextView, while still anchored to the right.
Here are 3 scenarios for the layout which I want to achieve:
I was trying to make this with FlexBoxLayout, but the button appears on the left side after wrapping.
<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:flexDirection="row"
app:flexWrap="wrap"
app:justifyContent="space_between"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text text"
android:gravity="start"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
android:text="Button"
/>
</com.google.android.flexbox.FlexboxLayout>
So how can I do that? It doesn't need to be FlexBox, I can use any layout, even 3rd party.
Use justifyContent="flex_end" in the parent and set layout_flexGrow to the children like this works for me.
<com.google.android.flexbox.FlexboxLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="300dp"
android:layout_height="wrap_content"
app:flexDirection="row"
app:flexWrap="wrap"
app:justifyContent="flex_end">
<TextView
android:id="#+id/textview2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="blah blah"
app:layout_flexGrow="1" />
<TextView
android:id="#+id/textview3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="( . )( . )"
app:layout_flexGrow="0" />
</com.google.android.flexbox.FlexboxLayout>
No need for a 3rd party layout.
ConstraintLayout should be more than enough - with a small tweak in code.
Your TextView will have straightforward constraints, set to parent layout (start, top, end).
<?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"
xmlns:tools="http://schemas.android.com/tools">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Text text text text text text" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/text" />
</android.support.constraint.ConstraintLayout>
In the code, just check the width of the TextView and compare it with the width of the parent (basically check it should overlap with the button).
If it does change(you will have to do this in code but this is the principle):
app:layout_constraintTop_toTopOf="#+id/text"
to
app:layout_constraintTop_toBottomOf="#+id/text"
If you need to do this dynamically ConstraintLayout has neat feature "Keyframe animations" that creates awesome looking animations when you are changing constraints.
Doesn't seem like there is a way to do it with Flexbox. I would just do it programmatically when you've inflated the resource (in onCreateView() or something like that). The parent of both of the views would be a RelativeLayout, with the Button aligned to the TextView top when the widths combined don't exceed the width of the RelativeLayout, and aligned to the bottom of the TextView when the widths are larger than that.
I have an arbitrary length textview+icon (icon+text) that needs centering on the screen. On the same row, there is a button aligned to the right side of the screen. (X)
| icon+text | X |
Using a LinearLayout I can center it with the view, but the button on the right shifts it left.
With a relative layout, I can achieve what I want but if the text is too long the button overlaps the text.
What's the right way to do this? I haven't used constraintLayout before, would that solve it?
I suggest you to use a constraint layout,
Example:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".YourActivity">
<TextView
android:id="#+id/my_text_view"
android:text="My Long Text That must not overlap the button"
android:layout_width="0dp"
android:gravity="center"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#+id/my_btn"
app:layout_constraintTop_toTopOf="#+id/my_btn"
app:layout_constraintBottom_toBottomOf="#+id/my_btn"/>
<Button
android:id="#+id/my_btn"
android:layout_marginTop="16dp"
android:text="My Nice Button "
android:layout_marginEnd="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#id/my_text_view"
app:layout_constraintEnd_toEndOf="parent"/>
</android.support.constraint.ConstraintLayout>
Example Output:
You can set it like this,
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.2"
android:drawableLeft="#mipmap/ic_launcher"
android:text="Click" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:gravity="center"
android:text="TextView" />
</LinearLayout>
just use a Relative Layout.
Center your Textview
and put toRightOf=txtViewsName on the button.
//UPDATED Forcing Widths in DP to ensure text is always centered and never overlaps button.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="#mipmap/ic_launcher"
android:maxWidth="230dp"
android:layout_centerHorizontal="true"
android:ellipsize="end"
android:text="My text to show test abcdefghyijkldkf here" />
<Button
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Button" />
</RelativeLayout>
You will need to adjust the button width and textview maxwidth to match your design, and confirm on preview all resolutions, but dp should cover you pretty well in this case.
NOTE*
This simply answers your issue, but does not do any funny behavior, i.e. if text grows too much ignore center command and start moving to the left, this does not do that. If that is your desire, please update your question.
//Centering Text in left view and using weight to ensure text area takes proper percentage of the space (based on your comments, not the layout you are looking for, but I'll leave it in case it helps someone else).
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="10">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="7"
android:drawableLeft="#mipmap/ic_launcher"
android:gravity="center"
android:text="My text to show here" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="Button" />
</LinearLayout>
for best practice i think ConstraintLayout is the best solution for designing and yes of course it helps you for what are you looking for.
for more info check this Build a Responsive UI with ConstraintLayout and this
ConstraintLayout.
Since your ImageButton on right has a fixed width (let's say 40dp for the purpose of this example) you can achieve the desired result by adding a margin of the same width at the end of your TextView to ensure that they're not overlapping. To keep the TextView centered on the screen you have to add the same margin at the start as well:
<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="wrap_content">
<TextView
android:id="#+id/textview"
android:text="TextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="#+id/button"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/textview"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
If you want to center the text within the TextView use android:gravity="center":
If the ImageButton's width was wrap_content then this approach wouldn't work, because there is no way to constraint the end of the TextView both to the end of the parent (so it's centered on the screen) and to the start of the ImageButton (so they don't overlap if the text gets long) at the same time.
In the end I ended up using RelativeLayout per Sam's suggestion with maxWidth and margin set on the TextView.
<android.support.constraint.ConstraintLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="14"
android:layout_gravity="bottom"
android:background="#drawable/object_detailed_information_bar"
android:padding="#dimen/object_detailed_information_bar_padding">
<ImageView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:id="#+id/object_type_icon_image_view"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:src="#drawable/restaurant_marker_icon"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/object_name_text_view_margin_start_or_left"
android:layout_marginStart="#dimen/object_name_text_view_margin_start_or_left"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="#id/object_type_icon_image_view">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/object_name_text_view"
android:scrollHorizontally="true"
android:lines="1" />
</HorizontalScrollView>
</android.support.constraint.ConstraintLayout>
I positioned the TextView wrapped by ScrollHorizontalView to be the right of the ImageView using app:layout_constraintLeft_toRightOf="#id/object_type_icon_image_view". But it caused also unexcepted behaviour. Text stored in TextView can be scrolled but it's cut off by few letters. When i delete this line app:layout_constraintLeft_toRightOf="#id/object_type_icon_image_view", text it's fully shown while scrolling. Is there any way to fix that issue?
Screens:
android:text="123456789123456789123456789123456789123456789123456789"
Before scroll when positioned to the right of ImageView
After scroll when positioned to the right of ImageView - it's cut off
Before scroll without positioning
After scroll without positioning - it's ok
Short answer:
Change the width of your HorizontalScrollView to 0dp and constrain its right-hand edge to the parent:
android:layout_width="0dp"
app:layout_constraintRight_toRightOf="parent"
Explanation:
Right now, your HorizontalScrollView is using wrap_content for its width. This makes it attempt to be as long as the text, but the parent (the ConstraintLayout) won't allow its children to have a width larger than itself. So your HorizontalScrollView winds up being the same width as the ConstraintLayout.
However, you've positioned the HorizontalScrollView such that it has been moved slightly to the right. This means that there's part of the view that is invisible; the ConstraintLayout is clipping the HorizontalScrollView.
To fix this, you need to make sure that the HorizontalScrollView is as wide as the space between the right edge of the image and the right edge of the parent. You already have a left constraint on the HorizontalScrollView, so you need to add a right constraint. Once both sides are constrained, you can use a width of 0dp to mean "match constraints"; now the HorizontalScrollView will size itself to the available space.
<?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">
<ImageView
android:id="#+id/object_type_icon_image_view"
android:layout_width="200dp"
android:layout_height="0dp"
android:src="#color/link_blue"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<HorizontalScrollView
android:id="#+id/horizontalScrollView"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#color/red"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/object_type_icon_image_view"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="#+id/object_name_text_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Horizontal Scroll View"
android:textSize="25sp"
android:gravity="center"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="16dp" />
</HorizontalScrollView>
</android.support.constraint.ConstraintLayout>
Do you need this?