ListView in ScrollView - small bug

2019-03-06 02:31发布

问题:

I'd like to have a listview in scrollview. This method is doing it almost perfect: https://stackoverflow.com/a/3495908/2811653

There is a bug when I enter more text in a row than fits in one line:

1: http://abload.de/img/screenshot_2013-10-311jq5t.jpg

2: http://abload.de/img/screenshot_2013-10-31lvrad.jpg

Scrolling down to the button works fine BUT as you see in the second screenshot the P is not displayed correctly :-(

In the Utility class the height is not calculated correctly when I fill the first row of listview like that.

Does anyone know how to fix it?

(Hint: the main point is that I want to scroll to the button which is below the listview. I don't want the button always to be displayed (so no weight=1))

Code:

package com.example.tmpapplication;

import android.app.ListActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;

public class MainActivity extends ListActivity {

static final String[] data=new String[]
{
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
        "B",
        "C",
        "D",
        "E",
        "F",
        "G",
        "H",
        "I",
        "J",
        "K",
        "L",
        "M",
        "N",
        "O",
        "P"
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    setListAdapter(new ArrayAdapter<String>(this, R.layout.list, data));

    ListView listView=(ListView) findViewById(android.R.id.list);
    Utility.setListViewHeightBasedOnChildren(listView);
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}
}

class Utility {
public static void setListViewHeightBasedOnChildren(ListView listView) {
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null) {
        // pre-condition
        return;
    }

    int totalHeight = 0;
    for (int i = 0; i < listAdapter.getCount(); i++) {
        View listItem = listAdapter.getView(i, null, listView);
        listItem.measure(0, 0);
        totalHeight += listItem.getMeasuredHeight();
    }

    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight + (listView.getDividerHeight() *  (listAdapter.getCount() - 1));
    listView.setLayoutParams(params);
    }
}

XML: activity_main.xml

<ScrollView  xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:orientation="vertical"
>

<ListView
    android:id="@android:id/list"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >
</ListView>

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Button"
    >
</Button>

list.xml:

<?xml version="1.0" encoding="utf-8"?>

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:hint="text"
    android:padding="10dp"
    android:textSize="20sp"
/>

回答1:

Put your listview in a relative layout and your button in another layout. listview is itself scrollable so you don't need to put your listview in a scrollview. It is useless.

by putting the button in another layout, you will be able to scroll listview easily, and your button will be visible below the layout



回答2:

Try this solution that I posted here.

If you do not want the ListView itself to scroll and just want the ListView's height to be such that all elements are shown, then you can create a subclass of ListView to accomplish this.

public class ListViewForEmbeddingInScrollView extends ListView {
    public ListViewForEmbeddingInScrollView(Context context) {
        super(context);
    }

    public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 4, MeasureSpec.AT_MOST));
    }
}

Manipulating the heightMeasureSpec to be AT_MOST with a very large size (Integer.MAX_VALUE >> 4) causes the ListView to measure all of its children up to the given (very large) height and set its height accordingly.

There is much discussion about this problem here including a lot of discussion as to whether or not is is appropriate to even do this. I don't have enough reputation to post my answer there but this is better than any of the solutions in that link. Perhaps someone with more reputation will run across this and post a solution on that other question that links back to this one.