Positioning in ConstraintLayout causes HorizontalScrollView to cut off content - android

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

Related

Why marginBottom isn't working in Spinner?

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

How to avoid ad occupying space of view directed by ConstraintLayout guideline in aspect of other view's space directed by other guideline?

When that ad at the bottom appears, it reduces space of TextView1 but the space of green (#4CAF50) TextView2 remains the same. I want both textviews' space to be percentally the same even after the ad showing up. I mean, guidelines should lift a bit after the banner shows up. I even tried to make editor count from the top to the banner by adding app:layout_constraintBottom_toTopOf="#+id/adView"to the guidelines but it still counts percents from the top to the bottom of ConstraintLayout. How can I prevent that from happening?
<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">
<com.google.android.gms.ads.AdView
android:id="#+id/adView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
app:adSize="BANNER"
app:layout_constraintBottom_toBottomOf="parent"
app:adUnitId="ca-app-pub-3940256099942544/6300978111"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/topGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="#+id/adView"
app:layout_constraintGuide_percent="0.67"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/TextView1"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#color/black"
app:layout_constraintBottom_toTopOf="#+id/adView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#id/bottomGuideline" />
<TextView
android:id="#+id/TextView2"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#4CAF50"
app:layout_constraintBottom_toTopOf="#+id/bottomGuideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#id/topGuideline" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/bottomGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="#+id/adView"
app:layout_constraintGuide_percent="0.85"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Edit: my main goal is to solve this problem with piano keyboard.
The problem is caused by android:layout_height="0dp" while using Guidelines: in this way the black TextView will never up when banner is visible.
Take always the black textview: app:layout_constraintTop_toTopOf="#id/bottomGuideline" and app:layout_constraintBottom_toTopOf="#+id/adView": you are saying to set the top to the top of a guideline ,which never change its position, while the bottom to the bottom of the banner. Plus you set 0dp as height, so if the banner has Visibility GONE the black textView will have the bottom to the bottom of the parent (screen). If the banner is VISIBLE, instead, the textview will get the available space between banner and guideline.
You should give wrap_content instead of 0dp, but you should think to something else instead of guidelines. If TextView content is too low for what you want to achieve, you can always use this attribute android:minHeight="your_value_in_dp" to set a minimum height your TextView will have.

Prevent double spacing between childs inside RecyclerView GridLayout

I have the following ImageView for single image in GridLayout with 2 columns. But it adds double margins at the middle (because both has marginLeft and marginRight). How can I prevent this?
This is the xml:
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
app:srcCompat="#drawable/default_image" />
You can simply split the left & right margin values between the childs and the RecyclerView itself.
Like, if you intend to have 8dp margin on left & right and 8dp in middle, set 4dp left & right margin into childs layout and 4dp to RecyclerView layout.
If you have multiple rows, similar technique can be applied for top & bottom margins too.
Your child ImageView layout:
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
app:srcCompat="#drawable/default_image" />
Your RecylerView gridlayout:
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="4dp"
app:layoutManager="android.support.v7.widget.GridLayoutManager" />
it's convenient to use the RecyclerView‘s addItemDecoration(ItemDecoration decor).it would be better than in xml.
You can simply replace the code with below one:
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
app:srcCompat="#drawable/default_image" />

Centering textview with right aligned button

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.

Placing button that overlaps two views in Android

I would like to place a button like so (overlapping two views, centered):
I tried to solve the issue with a RelativeLayout and a negative margin but somehow I can't overlap the two views. Instead the button always get's placed at the bottom of the image view. Any ideas?
Thanks in advance for the help!
Here my code:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/tour_image"
android:layout_width="match_parent"
android:layout_height="220dp" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_marginBottom="-35dp"
android:layout_marginEnd="16dp">
<Button
android:id="#+id/go_to_map_button"
style="#style/FloatingActionButton.Light"
android:layout_width="70dp"
android:layout_height="70dp"
android:drawableTop="#drawable/ic_directions_walk_color_24dp"
android:paddingTop="12dp"
android:text="#string/tour_button_show_map"
android:textAllCaps="true"
android:textAppearance="#style/p.Small"
android:textColor="#color/primary_main" />
</RelativeLayout>
</RelativeLayout>
The code results in this layout:
In my opinion, the best way to handle this would be to convert your existing top-level RelativeLayout into a ConstraintLayout. Developer guide for ConstraintLayout is available here: https://developer.android.com/training/constraint-layout/index.html
Once you have a top-level ConstraintLayout, you can position a view on the edge of two views by constraining your button's top and bottom to the view edge:
<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">
<View
android:id="#+id/top"
android:layout_width="0dp"
android:layout_height="100dp"
android:background="#caf"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<View
android:id="#+id/bottom"
android:layout_width="0dp"
android:layout_height="100dp"
android:background="#fac"
app:layout_constraintTop_toBottomOf="#+id/top"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<View
android:id="#+id/overlap"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginRight="24dp"
android:background="#fff"
app:layout_constraintTop_toBottomOf="#+id/top"
app:layout_constraintRight_toRightOf="#+id/top"
app:layout_constraintBottom_toBottomOf="#+id/top"/>
</android.support.constraint.ConstraintLayout>
The important part of this code is that the "overlap" view has these two constraints:
app:layout_constraintTop_toBottomOf="#+id/top"
app:layout_constraintBottom_toBottomOf="#+id/top"
These are saying "match my top edge to the other view's bottom edge" and "match my bottom edge to the other view's bottom edge". Obviously that's impossible, since the view has a non-zero height, and so ConstraintLayout will automatically position it so that it is centered on the other view's edge. Further details are available in the developer guide I linked above.

Categories

Resources