Using an internal ListView with a ScrollView should be avoided in Android. Indeed, these layouts have their own scroll and gesture. Solutions are designed to prevent scrolling gestures from the list or to calculate default heights and extensions. But this will do too much work and will not respect the Android template and recommendations.
Instead of replacing the ListView with LinearLayout and save the parent ScrollView , as my old answer pointed out, I found a possible workaround that has the following steps:
- Create Your Own
ListView - Override
onSizeChanged() , which redraws the ListView when the keyboard is opened - Get
lastVisiblePosition and return its height in the previous method - Finally, move the list to the previous
lastVisiblePosition and calculate the offset - Also set a
headerView for the header image container - And you need to update the height of the child before the user opens the keyboard so that you can update the value in
onClickListener EditText
And he needs these layouts:
Work with the layout:
<CoordinatorLayout> <AppBarLayout> ... </AppBarLayout> <RelativeLayout> <CustomListView /> <LinearLayout> ... </LinearLayout> </RelativeLayout> </CoordinatorLayout>
header layout (which will be above the list):
<RelativeLayout> <SimpleDraweeView /> <TextView /> ... </RelativeLayout>
Hum that all ... So, good to go:
Create a ListView :
public class CustomListView extends ListView {
Override onSizeChanged() :
@Override protected void onSizeChanged(int w, final int h, int oldw, int oldh) {
This is all for ListView .
The lastItemHeight variable will be updated when the user clicks on the input (below the list, thanks to setting your container of header images as headerView in your Activity ).
Now let's look at Activity :
Install your own ListView and your Adapter :
// get custom listview element final CustomListView list = (CustomListView) findViewById(R.id.container_list); // example items child ArrayList<String> items = new ArrayList<>(); for (int n=0; n<25; ++n) items.add("Blablabla n."+n); // example adapter ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.item_list_text_simple, android.R.id.text1, items);
Create a headerView and install the Adapter :
// prepare the header content with picture View header = getLayoutInflater().inflate(R.layout.test_header_image, null); // set datas to the header elements (example) Uri uri = Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/fresco-logo.png"); SimpleDraweeView draweeView = (SimpleDraweeView) header.findViewById(R.id.poster_picture); draweeView.setImageURI(uri); // add the header to listview list.addHeaderView(header, null, false); // set the adapter list.setAdapter(adapter);
Open the open program panel with EditText.setOnClickListener :
// when the user clicks on EditText... editMessage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // set a new Thread list.post(new Runnable() { @Override public void run() { // get last position of child int lastPosition = list.getLastVisiblePosition() - 1; // if the list can give the view last child if (list.getChildAt(lastPosition) != null) { // update the height of the last child in custom listview list.lastItemHeight = list.getChildAt(lastPosition).getHeight(); } } }); } });
Whats all for the code! And the last: (Ow .. where is the end?), Here are the layouts:
The basic layout of Activity :
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/comments_coordinator_layout" android:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_height="wrap_content" android:layout_width="match_parent"> <android.support.v7.widget.Toolbar ... /> </android.support.design.widget.AppBarLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="?attr/actionBarSize"> <com.package.name.CustomListView android:id="@+id/container_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@+id/send_message"/> <LinearLayout android:id="@+id/send_message" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="5dp" android:layout_alignParentBottom="true" android:orientation="horizontal" > <EditText ... /> <Button ... /> </LinearLayout> </RelativeLayout> </android.support.design.widget.CoordinatorLayout>
ListView Head Location:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:fresco="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/view_post" android:layout_width="match_parent" android:layout_height="225dp" android:paddingRight="5dp" android:paddingLeft="5dp" android:orientation="horizontal" android:background="#e6e6e6"> <com.facebook.drawee.view.SimpleDraweeView ... /> <TextView ... /> <TextView ... /> <TextView ... /> </RelativeLayout>
OU! I finally finished. I really hope you can have the right behavior. I tested it and it seems to work quite well. Here is another workaround with adjustPan , but you should keep the list starting at the bottom. Whereas this solution holds any child at the bottom of the list when resizing.
I hope you will like it;)