Prelude
For practice, I'm attempting to copy Apple's iMessage.
I'm using nested LinearLayouts for the message bubbles and the input bar, however the problem is when the keyboard pops up. I have it set to use adjustResize
, but different screen aspect ratios mess everything up when using LinearLayout weights.
Problem
The same weight on different screens:
Code
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android = "http://schemas.android.com/apk/res/android"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:background = "@color/bg"
android:focusableInTouchMode = "true">
<LinearLayout
android:orientation = "vertical"
android:layout_width = "match_parent"
android:layout_height = "match_parent">
<ListView
android:id = "@ id/history"
android:layout_width = "match_parent"
android:layout_height = "0dp"
android:layout_weight = "8"
android:divider = "@color/bg"/>
<LinearLayout
android:orientation = "horizontal"
android:layout_width = "match_parent"
android:layout_height = "0dp"
android:paddingHorizontal="15dp"
android:paddingVertical="5dp"
android:layout_weight="1"
>
<ImageButton
android:id = "@ id/imageButton"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:scaleType = "fitXY"
android:layout_gravity = "center"
android:padding = "20dp"
android:adjustViewBounds = "true"
android:background = "@drawable/ic_photo_camera"
android:contentDescription = "@string/camera"
android:layout_weight = "1" />
<LinearLayout
android:orientation = "horizontal"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:layout_gravity="center"
android:background = "@drawable/input_bg"
android:layout_weight = "6">
<EditText
android:id = "@ id/editText"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:minHeight="48dp"
android:layout_weight="5"
android:layout_gravity="center"
android:inputType = "text"
android:ems = "10"
android:hint = "@string/imessage"
android:paddingHorizontal = "10dp"
android:textColor="@color/fg_white"
android:textColorHint="@color/fg_dark"
android:text = "" />
<ImageButton
android:id="@ id/sendButton"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:layout_weight="1"
android:layout_gravity = "center"
android:scaleType = "centerInside"
android:adjustViewBounds = "true"
android:background = "@null"
android:scaleX = "1.5"
android:scaleY = "1.5"
android:src = "@drawable/send_arrow"
android:contentDescription = "@string/send" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
Question
How can I make a flexible input field that moves up and down when the keyboard opens without distoring? I've tried adjustPan
but it isn't really a good solution.
Other layouts I have tried:
- GridLayout, hides the input field under the keyboard
- FrameLayout, places the input field on top of the ListView (messages)
CodePudding user response:
I think your problem is caused by using weights everywhere. Not only it causes your elements to change size depending on screen size, it can also cause performance problems.
Here's a simpler layout, that should look good regardless of screen size. Notice how only elements that need to fill all available space have weight - ListView
vertically and EditText
with its container horizontally. Images need only enough space to display themselves, so wrap_content
is used. Same with bottom LinearLayout
vertically. After their sizes are calculated, remaining space will be filled according to the weights.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android = "http://schemas.android.com/apk/res/android"
android:orientation = "vertical"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:background = "@color/bg"
android:focusableInTouchMode = "true">
<ListView
android:id = "@ id/history"
android:layout_width = "match_parent"
android:layout_height = "0dp"
android:layout_weight = "1"
android:divider = "@color/bg"/>
<LinearLayout
android:orientation = "horizontal"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:paddingHorizontal="15dp"
android:paddingVertical="5dp">
<ImageButton
android:id = "@ id/imageButton"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:scaleType = "fitXY"
android:layout_gravity = "center"
android:padding = "20dp"
android:adjustViewBounds = "true"
android:background = "@drawable/ic_photo_camera"
android:contentDescription = "@string/camera" />
<LinearLayout
android:orientation = "horizontal"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:layout_gravity="center"
android:background = "@drawable/input_bg"
android:layout_weight = "1">
<EditText
android:id = "@ id/editText"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:minHeight="48dp"
android:layout_weight="1"
android:layout_gravity="center"
android:inputType = "text"
android:ems = "10"
android:hint = "@string/imessage"
android:paddingHorizontal = "10dp"
android:textColor="@color/fg_white"
android:textColorHint="@color/fg_dark"
android:text = "" />
<ImageButton
android:id="@ id/sendButton"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_gravity = "center"
android:scaleType = "centerInside"
android:adjustViewBounds = "true"
android:background = "@null"
android:scaleX = "1.5"
android:scaleY = "1.5"
android:src = "@drawable/send_arrow"
android:contentDescription = "@string/send" />
</LinearLayout>
</LinearLayout>
</LinearLayout>