I have the following ConstraintLayout in my Android application:
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white">
<ImageView
android:id="#+id/image_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/icon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
<TextView
android:id="#+id/instructions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/spacing_large"
android:text="#string/instruction"
app:layout_constraintTop_toBottomOf="#id/support_ic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
<Button
android:id="#+id/call_button"
android:layout_marginTop="#dimen/spacing_large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null"
android:text="#string/phone"
android:textSize="18sp"
android:textColor="#drawable/button"
app:layout_constraintTop_toBottomOf="#+id/instructions"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
<EditText
android:id="#+id/message_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:lines="8"
android:hint="#string/support_message_hint"
android:textColorHint="#color/text_hint"
android:inputType="textCapSentences|textMultiLine"
android:background="#color/background_gray"
android:padding="#dimen/spacing_small"
android:textColor="#color/black"
app:layout_constraintBottom_toTopOf="#+id/send_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:gravity="top|left"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintVertical_weight="1"
/>
<Button
android:id="#+id/send_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/support_send"
android:background="#color/button_blue"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout>
When I open the keyboard, the view adjusts and the bottom two widgets (the button and the editText) move with the keyboard. My problem however, is that whenever this happens, the #id/call_button Button lays on top of the editText. I do not want this. I want the editText to overlay the button when the keyboard is open.
Is there any way to make the editText take precedent when overlapping other widgets in this scenario? I tried adding editText.bringToFront() in my onCreate method, but that didn't do anything.
Also, I am trying to avoid nesting the bottom two widgets (the button and the editText) inside of their own layout. I want them all to remain in the same ConstraintLayout. Thank you for the help ahead of time.
I added android:elevation="4dp" to the editText's xml and it worked.
Material Design guidelines specify that Buttons use elevation in both their pressed (8dp elevation) and upressed (2dp elevation) states. https://material.io/guidelines/material-design/elevation-shadows.html#elevation-shadows-elevation-android
Which view you see when two are stacked on top of each other at the same elevation is dependent on the ordering of those views in your layout (e.g. why you expected the views written later to overlay the views written earlier), but elevation takes precedence over this.
As you've found, you can add elevation to your other views to make them "higher" than your button, but this is a bit ugly and might have some unwanted side-effects. I think a better choice would be to set the manifest attribute android:windowSoftInputMode="adjustPan" on your activity. This will cause your activity's view to slide up when the keyboard opens, rather than resizing.
Related
I was looking to create a view like this:
It has the behavior of a button, so I used a ConstraintLayout and placed the image and the TextView ('some text here') on top of the button using constraints (the other text and icon is implemented as button text and icon respectively).
The xml is as follows (inside the constraint layout):
<com.google.android.material.button.MaterialButton
android:id="#+id/btn_plan_change"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingHorizontal="10dp"
android:paddingVertical="30dp"
android:text="start now"
android:textAlignment="viewEnd"
app:icon="#drawable/ic_chevron_right_black_24dp"
app:iconGravity="end"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/iv_plan_change"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginHorizontal="10dp"
android:layout_marginVertical="25dp"
android:background="#drawable/circle_background"
android:backgroundTint="?attr/colorPrimary"
android:elevation="2dp"
android:padding="10dp"
android:src="#drawable/ic_money"
app:layout_constraintBottom_toBottomOf="#id/btn_plan_change"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="#id/btn_plan_change"
app:layout_constraintTop_toTopOf="#+id/btn_plan_change" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/tv_plan_change"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_margin="10dp"
android:elevation="2dp"
android:gravity="center_vertical"
android:lineSpacingExtra="5dp"
android:text="some text here"
app:layout_constraintBottom_toBottomOf="#+id/btn_plan_change"
app:layout_constraintStart_toEndOf="#+id/iv_plan_change"
app:layout_constraintTop_toTopOf="#+id/btn_plan_change" />
As you can see, I have used an elevation of 2dp on both the ImageView and the TextView to keep it on the same elevation as the button, but on pressing the button, both of them go behind the button and can't be seen.
I have experimented with animating translationZ of both both views on button press and release, but it doesn't work so well (sometimes animates later than button, sometimes goes behind it).
I would love to have a working implementation.
I have an issue with my App on Android Studio.
I want to know how can I put on the bottom of my layout (in a fixed position) without ruining the structure on various smartphones. I'm using a Linear Layout and the elements to put at the bottom are :
Edit-text (comments area) + Button "Send comment" in the right of the Edit-Text. Thank you.
Ideal approach is to use a ConstraintLayout, because it will give you a lot of options to do that. Using a LinearLayout if the linear layout height is match parent. You can set the item property of gravity=bottom.
Sample Code of constraint layout
<androidx.constraintlayout.widget.ConstraintLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="#+id/editText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="16dp"
android:background="#drawable/bg_input"
android:hint="Taper votre message"
android:padding="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/button"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:background="#drawable/bg_button"
android:text="Send"
android:textColor="#android:color/white"
app:layout_constraintBottom_toBottomOf="#+id/editText"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/editText" />
</androidx.constraintlayout.widget.ConstraintLayout>
Maybe you can use a new Layout called ConstraintLayout. You have to put this new layout at the same level as your linear layout and it will not destroy your work.
I have a dialog widget with navigation bar contains title and close button. I want to put the title in centre of the device, and put the close button in the end of layout. However when the title is long, then it will overlap with the close button. Here is my code:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:maxLines="1"
android:ellipsize="end"
android:text="Title" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="Close" />
</androidx.constraintlayout.widget.ConstraintLayout>
Any workaround to achieve this?
Thank you.
Normally, to center text, you would constrain the start and end of the text to the end point of the centering region. In this case, since the text should be centered on the screen, you would attach the start to the parent start and the end to the parent end. This works unless the centered text exceeds the empty center region and overlaps the "Close" TextView. Unfortunately, there is no way to make these constraints and tell the centered view to avoid overlapping the TextView on the right.
To make it work, I would introduce another TextView that is a duplicate of the "Close" TextView, make it invisible and attached to the top and start of the parent. This will create a region between the two TextViews where the text can be centered. To ensure that the text does not overlap the end TextView, specify app:layout_constrainedWidth="true" on the centered view. Something like this:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/space"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Close"
android:visibility="invisible"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:text="This is some very long text that should stretch across the device and ellipsize."
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toStartOf="#+id/textView2"
app:layout_constraintStart_toEndOf="#+id/space"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Close"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Barrier
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="left"
tools:layout_editor_absoluteX="306dp"
tools:layout_editor_absoluteY="62dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
which will show in the designer like this for long text:
and like the following for short text:
There are other ways to do this that would involve some coding, but this is an XML-only solution which, IMO, is preferable.
I want to hide some part of the content under a scrim (like in drawer layout).
The MaterialComponents buttons that are under this scrim view are receiving clicks to the scrim view, and that is a major problem.
content scrim view:
<FrameLayout
android:id="#+id/scrim"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
android:background="#color/transparent"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
button that steals clicks:
<com.google.android.material.button.MaterialButton
android:id="#+id/add_at_start"
android:theme="#style/ButtonArrowShapedLeft"
style="#style/ButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="Add"
android:visibility="gone"
tools:visibility="visible"
app:icon="#drawable/ic_add_black_24dp"
app:layout_constraintStart_toStartOf="#+id/container"
app:layout_constraintTop_toBottomOf="#+id/container" />
I already established that the problem lies within the button being elevated.
If I set the elevation of the scrim even to 2dp, the button receives no clicks, despite the fact it has probably more dp of elevation than the scrim view.
But this does not solve my problem, it actually makes it worse, because the scrim view now covers everything on the screen, even the content that is way later in layout hierarchy.
I know I can just disable the buttons when the content scrim is visible, but this just doesn't seem right and the buttons feeling entitled to stealing clicks just because of some ludicrous elevation actually angries me enough to seek help.
try this :
<com.google.android.material.button.MaterialButton
android:id="#+id/add_at_start"
android:theme="#style/ButtonArrowShapedLeft"
style="#style/ButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="Add"
android:visibility="gone"
android:clickable="true"
tools:visibility="visible"
app:icon="#drawable/ic_add_black_24dp"
app:layout_constraintStart_toStartOf="#+id/container"
app:layout_constraintTop_toBottomOf="#+id/container" />
Simple question:
What is the exact algorithm used by ConstraintLayout in order to know which View is drawn first and which View is drawn last?
In RelativeLayout, the last View in the XML file is drawn last, hence it will be on top of everything, obscuring the Views which where drawn earlier.
Why does not ConstraintLayout carry the same function (at least, apparently)?
The following code results in the Button being displayed on top of the included View.
<Button
android:id="#+id/calculate"
android:layout_width="183dp"
android:layout_height="76dp"
android:layout_marginBottom="5dp"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:text="C A L C U L A T E"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" />
<include
android:id="#+id/help_window"
layout="#layout/help_window"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginTop="0dp"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/include4" />
</android.support.constraint.ConstraintLayout>
Alright. I solved this now.
Apparently buttons are treated seperately. With a buildt in elevation to alwyas be on top.
solution is to remove this elevation, write this in the xml file in your button:
android:stateListAnimator="#null"