I have a ViewHolder with the header on top and that header becomes visible in a specific case. In most other cases, the header is set as GONE. The problem is that when a header is set as GONE, its height is still calculated and other views are spread differently (with more space between).
Here is a layout blueprint:
Blueprint explanation:
The header is constrained to top, left and right.
Two views below are in packed chain, constrained to a header on top, ImageView to the right and parent to the left and bottom.
And here is a screenshot from the layout inspector with highlighted header view which is set as GONE:
According to documentation, the header view, when set to GONE should be shrunk to point with constraints from other views still applied to it, but the header should not occupy layout space and affect the height of the ConstraintLayout as it is set as wrap_content.
In this inspector screenshot, it's not clear what happened actually. The header is not visible, a bottom view is obviously constrained to parent top, but the header is still shown in the inspector as full width with specified height.
I'm not sure if this is a bug or I should force ConstraintLayout to re-measure itself.
XML UPDATE:
<?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">
<TextView
android:id="#+id/list_item_step_conversion_tv_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#color/gray_very_light"
android:padding="#dimen/activity_vertical_margin"
android:text="#string/favorites"
android:textColor="#android:color/black"
android:textSize="#dimen/default_text_size"
android:textStyle="bold"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="#+id/list_item_step_conversion_tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="#color/gray_dark"
android:textSize="#dimen/medium_text_size"
app:layout_constraintBottom_toTopOf="#+id/list_item_step_conversion_tv_description"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/list_item_step_conversion_iv_favorite"
app:layout_constraintTop_toBottomOf="#+id/list_item_step_conversion_tv_header"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Bicycling - light (10-11.9 mph)"/>
<TextView
android:id="#+id/list_item_step_conversion_tv_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="16dp"
android:layout_marginTop="4dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="#android:color/black"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="#+id/list_item_step_conversion_tv_title"
app:layout_constraintRight_toLeftOf="#+id/list_item_step_conversion_iv_favorite"
app:layout_constraintTop_toBottomOf="#+id/list_item_step_conversion_tv_title"
tools:text="182 steps/minute"/>
<ImageView
android:id="#+id/list_item_step_conversion_iv_favorite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="0dp"
android:layout_marginRight="24dp"
android:layout_marginTop="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/list_item_step_conversion_tv_header"
app:srcCompat="#drawable/ic_not_liked"/>
</android.support.constraint.ConstraintLayout>
UPDATE 2
After additional observations, this problem occurs only after a call to notifyDataSetChanged in RecyclerView.Adapter. Here is a screenshot of layout state before and after the click to the favorite icon to one of the items.
Screenshots explanation:
On the left side, ViewHolder with visible header view is on position: 2. Items above are displayed correctly.
After click on favorite icon (item with value 242), ViewHolder on position: 1 is the one with visible header view, while the ViewHolder on position: 2 have header view set as GONE. I was expecting for ViewHolder height to decrease and have the same height as ViewHolder on position: 0.
Having in mind that this ViewHolder had header set to VISIBLE in previous state, it might have something with recycling, not sure.
I've solved this issue by calling view.requestLayout()* in the end of my adapter's #getView, after the usual call to binding.executePendingBindings().
*I'm using an old-school Adapter right now, so you should search for the RecyclerView.Adapter's equivalent, probably #onBindViewHolder()
It seems like the layout is actually correct -- disregard the frame of the gone object in the inspector, when a widget is marked as gone we don't lay it out again, as it will simply be skipped (in Studio we do, to provide an easier way to see what's going on, but there's no point doing that on the real device).
Which version of ConstraintLayout are you using? I seem to get the correct behavior here:
After marking the first element to gone:
What worked for me was set the inital visibilty of an object to "gone" and change its visibity via code.
Some like this:
My xml:
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvMyobject"
style="#style/myStyle"
tools:text="#string/dummy_text"
android:textAlignment="center"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/anyotherobject"
android:visibility="gone"
/>
My activity:
if (isSomethingToShow) {
tvMyobject.setVisibility(View.VISIBLE);
tvMyobject.setText(R.string.my_string_to_show);
}
Related
I have a widget that, no matter what constraints I place upon it and other widgets, including the addition of barriers, always positions itself at the top of the layout.
This is a fairly simple arrangement of two rows of two elements each, not aligned column wise. The first element in each row is a TextView label, the second an input (Spinner).
There is also a lone TextView title above the first row stretching all the way across. By my understanding and previous experience with constraint layout, this shouldn't require a barrier between the rows, and that was my initial version.
This is the design view, where the selected element ("Credentials") is supposed to be in the second row but instead appears above the first row, over top of the title TextView ("PKIX"):
Actual result in the emulator looks much the same. The selected "Credentials" element is the fourth of five elements in the XML layout below. All of the other elements are in the right place.
<?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">
<TextView
android:id="#+id/addsrv_pkix_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#drawable/bottomborder"
android:text="PKIX"
android:textAlignment="center"
android:layout_marginHorizontal="10sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#+id/addsrv_trust_lbl"
/>
<TextView
android:id="#+id/addsrv_trust_lbl"
android:text="Trust"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#+id/addsrv_trust_spin"
app:layout_constraintTop_toBottomOf="#+id/addsrv_pkix_title"
app:layout_constraintBaseline_toBaselineOf="#+id/addsrv_trust_spin"
app:layout_constraintBottom_toTopOf="#+id/addsrv_cred_lbl"
/>
<Spinner
android:id="#+id/addsrv_trust_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#+id/addsrv_trust_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_pkix_title"
app:layout_constraintBottom_toTopOf="#+id/addsrv_cred_spin"
/>
<TextView
android:id="#+id/addsrv_cred_lbl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:paddingHorizontal="10sp"
android:text="Credentials"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#+id/addsrv_cred_spin"
app:layout_constraintTop_toBottomOf="#+id/addsrv_trust_lbl"
app:layout_constraintBaseline_toBaselineOf="#+id/addsrv_cred_spin"
/>
<Spinner
android:id="#+id/addsrv_cred_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#+id/addsrv_cred_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_trust_spin"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
I'm perplexed. The addsrv_cred_lbl TextView ("Credentials") is:
Start aligned with parent.
End aligned with the addsrv_cred_spin spinner, which appears correctly positioned;
this alignment is reciprocated to create a horizontal chain. They are also baseline
aligned.
Top aligned with the bottom of the TextView above it, addsrv_trust_lbl.
This alignment is also reciprocated.
There's no bottom alignment yet (there's another row to go); bottom aligning it with the parent makes no difference unless I bottom align the spinner from the same row, in which case the result goes from bad to worse.
Since this did not work, I tried to use a barrier between the rows. If I use it as a "top", with the second row widgets as the constraint referents, the barrier appears at the top, above the title, regardless of what constraints are used to position it below the first row. Used as a "bottom", with the first row widgets referenced and the second row chained below it (which is more logical), things are a little bit better in that the barrier appears in the right place -- but the "Credentials" widget is still up top.
The design view of this looks exactly the same as the previous one except the barrier is visible below the first row. In the XML, I aslo added optimizationLevel="none" after having read this can help with misbehaving barriers (but it made no difference). There's also a few stylistic elements added back here (such as font size) I removed for brevity before.
<?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"
app:layout_optimizationLevel="none"
>
<TextView
android:id="#+id/addsrv_pkix_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#drawable/bottomborder"
android:backgroundTint="#color/tbar"
android:text="PKIX"
android:textAlignment="center"
android:textSize="#dimen/addsrv_bigfont"
android:textColor="#color/titleText"
android:layout_marginHorizontal="10sp"
app:layout_constraintBottom_toTopOf="#+id/addsrv_trust_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="#+id/addsrv_trust_lbl"
android:text="Trust"
android:textSize="#dimen/addsrv_fontsz"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#+id/addsrv_trust_spin"
app:layout_constraintTop_toBottomOf="#+id/addsrv_pkix_title"
app:layout_constraintBaseline_toBaselineOf="#+id/addsrv_trust_spin"
app:layout_constraintBottom_toTopOf="#+id/addsrv_bar1"
app:layout_constraintHorizontal_chainStyle="packed"
/>
<Spinner
android:id="#+id/addsrv_trust_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#+id/addsrv_trust_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_pkix_title"
app:layout_constraintBottom_toTopOf="#+id/addsrv_bar1"
/>
<androidx.constraintlayout.widget.Barrier
android:id="#+id/addsrv_bar1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="addsrv_trust_lbl,addsrv_trust_spin"
app:layout_constraintBottom_toTopOf="#+id/addsrv_cred_lbl"
/>
<TextView
android:id="#+id/addsrv_cred_lbl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
android:text="Credentials"
android:textSize="#dimen/addsrv_fontsz"
app:layout_constraintBaseline_toBaselineOf="#+id/addsrv_cred_spin"
app:layout_constraintEnd_toStartOf="#+id/addsrv_cred_spin"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_bar1" />
<Spinner
android:id="#+id/addsrv_cred_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#+id/addsrv_cred_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_bar1"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
Am I correct in observing that some of the constraints on addsrv_cred_lbl are being completely ignored? Doesn't topToBottom mean that the top of the widget is aligned with the bottom of the other? Instead, it seems simply to mean that they will be connected with a squiggly, potentially curved and convoluted line in the design view, and the spacial relation of the two widgets is arbitrary, such that the semantic logic might as well be inverted, "top = bottom, bottom = top", etc.
Please note that I do not want to use absolute values to position anything. If the only way to get this to work is to do that, constraint layout seems a complete waste of time even in this simple case, and I'd rather just stack some liner layouts.
The problem is that Spinner doesn't have a baseline. You were trying to tie it to the baseline of the item inside the Spinner is my guess - ConstraintLayout can't reach children of its children.
You can check it via the design tab with a right click. TextViews will show an option "Show baseline" but the Spinner doesn't.
Also snippet from the doc
Align the text baseline of a view to the text baseline of another
view.
That's what baselines are for, if you want two TextViews connect together so they don't have the height where the text starts messed up.
I think there is a tiny flaw in your approach to the chain. You were setting the top constraint of both elements in each row to the bottom of the previous row(or title in the first row). Even if the Spinner would have a baseline, this would make the label off-centered in relation to the Spinner(slightly higher because the baseline of a text is higher than the actual bottom of the view).
I think the best approach in these types of layouts is to have one guiding element(which is also the element of the chain) that represents the row and let other elements be positioned in relation to it.
<?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">
<TextView
android:id="#+id/addsrv_pkix_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="PKIX"
android:textAlignment="center"
android:layout_marginHorizontal="10sp"
app:layout_constraintVertical_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#+id/addsrv_trust_spin"
/>
<TextView
android:id="#+id/addsrv_trust_lbl"
android:text="Trust"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#+id/addsrv_trust_spin"
app:layout_constraintTop_toTopOf="#+id/addsrv_trust_spin"
app:layout_constraintBottom_toBottomOf="#+id/addsrv_trust_spin"
/>
<Spinner
android:id="#+id/addsrv_trust_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#+id/addsrv_trust_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_pkix_title"
app:layout_constraintBottom_toTopOf="#+id/addsrv_cred_spin"
/>
<TextView
android:id="#+id/addsrv_cred_lbl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
android:text="Credentials"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#+id/addsrv_cred_spin"
app:layout_constraintTop_toTopOf="#+id/addsrv_cred_spin"
app:layout_constraintBottom_toBottomOf="#+id/addsrv_cred_spin"
/>
<Spinner
android:id="#+id/addsrv_cred_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#+id/addsrv_cred_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_trust_spin"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
NOTE: I added the last bottom constraint to the parent and "spread" to the chain for demonstration but also know that if you don't have the bottom of the last view constrained to something - it's not a chain.
Working with ConstraintLayout is easy if you obey few simple rules:
Create one chain. That means Views hooking to each other reciprocally, all the way.
Now that you have a working chain, you can manipulate it with layout_constraintVertical_bias and layout_constraintVertical_chainStyle. If changing those does nothing, it means your chain is broken.
hook remaining Views to ones laid out by the chain
every control must have 4 constraints: top, bottom, start and end
do not create competing chains and try to force them into working together.
Spinner cannot have baseline, only TextView and its descendants have it. Spinner is AdapterView, so it can contain whatever you can imagine.
BTW: don't use #+id to refer to existing ids. Plus means creating new id, so if you make a typo it will create new id that refers to nothing instead of error "there's no such id".
Here's an example: top label and Spinners form the main chain and side labels are positioned each to their 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:id="#+id/addsrv_pkix_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10sp"
android:background=""
android:text="PKIX"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="#id/addsrv_trust_spin"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintVertical_chainStyle="packed"
/>
<TextView
android:id="#+id/addsrv_trust_lbl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
android:text="Trust"
app:layout_constraintBottom_toBottomOf="#id/addsrv_trust_spin"
app:layout_constraintEnd_toStartOf="#id/addsrv_trust_spin"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#id/addsrv_trust_spin"
app:layout_constraintVertical_bias="1.0"
/>
<Spinner
android:id="#+id/addsrv_trust_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="#id/addsrv_cred_spin"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/addsrv_trust_lbl"
app:layout_constraintTop_toBottomOf="#id/addsrv_pkix_title"
app:layout_constraintVertical_bias="0.0"
/>
<TextView
android:id="#+id/addsrv_cred_lbl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
android:text="Credentials"
app:layout_constraintBottom_toBottomOf="#id/addsrv_cred_spin"
app:layout_constraintEnd_toStartOf="#id/addsrv_cred_spin"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#id/addsrv_cred_spin"
app:layout_constraintVertical_bias="1.0"
/>
<Spinner
android:id="#+id/addsrv_cred_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/addsrv_cred_lbl"
app:layout_constraintTop_toBottomOf="#id/addsrv_trust_spin"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
In a constraint layout, I have a textview, with an imageview next to it:
But sometimes the text in the textview can be very long and sometimes span more than one line. In these cases, the imageview get pushed outside the view:
Even addind a constraint between the imageview and the view container, the imageview gets pushed outside the view.
The goal is to always have the image right next to the text and if it grows, the image starts getting pushed to the side as long is not going outside the view. When it touches the boundaries of the view, it should stay there while the text wraps to the next line.
This code block just shows the case of the second picture:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/textView" android:layout_marginTop="8dp"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp"
tools:text="This is a cat with a lot more text next to it so pay attention "/>
<ImageView
android:layout_width="30dp"
android:layout_height="30dp" tools:srcCompat="#tools:sample/avatars[3]"
android:id="#+id/imageView"
app:layout_constraintStart_toEndOf="#+id/textView" android:layout_marginStart="8dp"
android:layout_marginTop="8dp" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0"/>
</androidx.constraintlayout.widget.ConstraintLayout>
I've tried usgin barriers and guidelines, but they really do not serve for this case. The textview needs to be wrap_content since its size is variable and it is preferable to use constraint layout, that's why I did not used another one. Chains also did not work here.
You can use a packed chain with a bias of 0 to make it start-aligned and then set app:layout_constrainedWidth="true" for both views so that their constraints are respected when wrapping content.
<?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/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="Text goes here"
android:textSize="24sp"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toStartOf="#id/image"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/textView"
app:layout_constraintTop_toTopOf="parent"
tools:src="#tools:sample/avatars" />
</android.support.constraint.ConstraintLayout>
The problem is that you are setting textview's wrap_content. Doing so will let the textview decide its own width, ignoring layout constraints such as margins.
You need to set width to 0dp which is interpreted as match_constraint in constraint layout, it allows the layout to decide textview's width which means that textview will be given as much width as necessary after margins and other layout constraints are applied.
Now to your desired effect, first remove all constraints from both views. Select both of them, then right click and select chain option from the options menu. Then Pack them horizontally. This would form a chain.
Why do we need chain?
Because you want the imageview to right of textview and textview to left of image view, this kind of two way constraint cannot be added because TextView won't draw till imageview is drawn and imageview is waiting for textview to draw.
Chain will help you tackle this problem.
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.)
Im facing an issue with ConstraintLayout.
I have a view which has 3 textviews T1, T2 and T3.
Precondition: T1,T2 is having 4dp margin top.
Problem:
T3 needs to be top should be aligned to topmost view.
Condition is T1 will be visible or gone based on certain condition.
If T1 is visible the margintop will be 8dp and when T1 is not visible T2 will have 12dp margintop.
<?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/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="T1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:text="T2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView" />
<TextView
android:id="#+id/textView10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:text="T3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/textView" />
</android.support.constraint.ConstraintLayout>
Is this possible by XML or I need to configure programmatically?
You can't achieve this only with XML, what you did is create a screen using constraint layout. If you want to add some logic to change the position of some view under certain conditions you will have to write it programmatically.Here is a good thread about the subject.
I don't know exactly your use case,but you can achieve this setting view to invisible instead of gone.
View.GONE This view is invisible, and it doesn't take any space for layout purposes.
View.INVISIBLE This view is invisible, but it still takes up space for layout purposes.
You can use layout_goneMarginTop to have a different margin when your view is GONE.
You can also use SequenceLayout for better flexibility on managing your layout. Use visibilityElement on each Span you want to be gone when your related view is gone.
Can't understand how to implement simple thing.
I need layout of 2 views with next behaviour:
button should be to right of text when text is short
when text is long it ellipsizes and button always visible and full-width
now I get that button is going out of screen
You can achieve this using ConstraintLayout. Here's a template:
<?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">
<TextView
android:id="#+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Hello world"
android:maxLines="1"
android:ellipsize="end"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintWidth_default="wrap"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/button"
app:layout_constraintBottom_toBottomOf="parent"/>
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="HELLO WORLD"
app:layout_constraintLeft_toRightOf="#+id/text"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBaseline_toBaselineOf="#+id/text"/>
</android.support.constraint.ConstraintLayout>
The initial setup is:
Create a horizontal chain including the text and the button
Set the chain style to "packed" so that there's no space between the views
Set the horizontal bias to 0 so that the packed views hug to the left
The magic comes with the TextView's width and the app:layout_constraintWidth_default attribute. By setting the width to 0dp and the "default width" to wrap, we're telling Android to give the view as much space as it needs to hold its contents as long as it fits the constraints. When the text is really long, the constraints will keep it from pushing the button off the right side of the screen.