I'd like to be able to open the keyboard without my layout resizing. I don't want to use adjustNothing
, because I need one of my bottom views to raise up with the keyboard. I'd also prefer not to use adjustPan
, because that raises the entirety of the layout off of the screen which is kind of ugly.
So, I wrapped my layout ( ConstraintLayout
) in a ScrollView
like so:
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.mypackage.MyViewModel"/>
</data>
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="none">
<!-- I don't want anything in this ConstraintLayout to move or resize when I open the keyboard, hence why I wrapped it in a ScrollView. -->
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/scene_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/scene"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:adjustViewBounds="true"
android:background="@color/black"
android:scaleType="fitCenter"
android:src="@drawable/grumpy"/>
</FrameLayout>
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".7"/>
<View
android:id="@+id/status_bar"
android:layout_width="0dp"
android:layout_height="48dp"
android:background="@color/colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/guideline"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="48dp"
android:clipToPadding="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/status_bar"/>
</android.support.constraint.ConstraintLayout>
</ScrollView>
<!-- The bottom sheet contains a 48dp high peekable area (a bar with an EditText) that I need to raise with the keyboard. -->
<include
android:id="@+id/bottom_sheet"
layout="@layout/bottom_sheet"
app:viewModel="@{viewModel}"/>
</android.support.design.widget.CoordinatorLayout>
This works fine for the first two times I bring up the keyboard. Here's the bizarre problem I'm having. Every THIRD time I bring up the keyboard, my layout resizes and squishes together as if the ScrollView
isn't even there. This occurs consistently every THIRD time I open the keyboard like so:
1) Open keyboard. Layout remains same size.
Close keyboard.
2) Open keyboard. Layout remains same size.
Close keyboard.
3) Open keyboard. *LAYOUT RESIZES/SQUISHES TOGETHER!*
Close keyboard.
The above cycle repeats as I continue to open/close the keyboard.
Any ideas how to solve this? Why does the layout resize every third time I open the keyboard?
Actually, if you use match_parent
as the size of ScrollView
child, it will also resize when keyboard will appear and fit the ScrollView
size.
To understand how ScrollView
work, you can think about a Browser. On every link you go, if the page doesn't fit your browser windows, you will see scrollbar to let you navigate in the page. ScrollView
are the same, you just need to give them the size you want to occupy on the screen (like the browser window) and you can put everything in it (like the website page), even if it's bigger than the ScrollView
size.
According to this, your ConstraintLayout
need a fixed size. It could be wrap_content
if you only want the user to access all the component in it. This is not your case. You want it to keep his original size, that is, as I can see in your code, also the size of your first CoordinatorLayout
.
The only way I found to fix an inner ConstraintLayout
to the original view size is by code.
Let's simplify your xml for the exemple :
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:id="@+id/parentView"
android:layout_height="match_parent">
<ScrollView
android:id="@+id/scrollViewItem"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.constraint.ConstraintLayout
android:id="@+id/childView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--ALL YOUR ITEMS-->
</android.support.constraint.ConstraintLayout>
</ScrollView>
</android.support.design.widget.CoordinatorLayout>
You need to fix childView size at loading of the screen. On the onCreate
, you can add this code :
private int first = 0;
public class ConstaintLayoutCanScroll extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
first = childView.getMeasuredHeight();
final CoordinatorLayout parentView = findViewById(R.id.parentView);
parentView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (first < parentView.getMeasuredHeight()) {
ConstraintLayout childView = findViewById(R.id.childView);
childView.setMinHeight(parentView.getMeasuredHeight());
first = childView.getMeasuredHeight();
}
return true;
}
});
}
}
I use a listener because at OnCreate
, the size is not already init. first
is here because onPreDraw
isn't called only once by android. It's an variable of the class that I fix to 0 by default.
Using match_parent
as the size of ScrollView
child isn't ideal. You should rather use fixed size or wrap_content
. In your current setup the ConstraintLayout
tries to set its height to the ScrollView's
height and this changes according to keyboard being displayed or not.
You could try to set your ConstraintLayout
to a fixed height as soon as it is displayed on the screen.
To test if that approach works, you can try to set eg android:layout_height="400dp"
on your ConstraintLayout
and see if the "cycle" you mentioned will be happening or not. If that works, you can move on to using a real dimension of the ConstraintLayout
matching the size of the screen.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.