Android 上 ListView 的限制高度

我想显示一个按钮下的 ListView。问题是,如果 ListView得到扩展(项目添加...) ,按钮将被推出屏幕。

我尝试了一个有重量的 LinearLayout(就像在 Android: 为什么在视图中没有 maxHeight?中建议的那样) ,但要么是我把重量弄错了,要么就是它根本不起作用。

另外,我在某处找到了使用 RelativeLayout的提示。然后用 android:layout_above参数将 ListView设置在按钮的上方。

问题是,我不知道如何定位按钮后。在我发现的例子中,在 ListView下面的视图是使用 android:layout_alignParentBottom调整的,但是我不想我的按钮粘在屏幕的底部。

除了使用 setHeight 方法和对所需空间的一些计算之外,还有其他的想法吗?


编辑: 我得到了很多有用的答案。

  • Bigstone’s & user639183的解决方案 差不多运行良好。但是,我必须在按钮底部添加一个额外的填充/边距,因为它仍然会被推出屏幕的一半(然后停止)

  • 如果你想把按钮固定在屏幕的底部,Adinia 的回答只是相对布局就可以了。这不是我的本意,但对其他人可能还是有用的。

  • AngeloS 的解决方案是我最后选择的,因为它只是创造了我想要的效果。然而,我对按钮周围的 LinearLayout做了两个小小的改动:

    • 首先,因为我不想在我的布局中有任何绝对值,所以我将 android:layout_height="45px"改为 wrap_content,这样也很好。

    • 其次,由于我希望按钮水平居中,这只能由垂直 LinearLayout支持,所以我将 android:  方向 = “水平”改為“垂直”。

    AngeloS 也在他最初的帖子中说,他不确定 LinearLayout中的 android:layout_weight="0.1"参数是否对 ListView有任何影响; 我只是尝试了一下,确实有效!否则,按钮将再次被推出屏幕。

93047 次浏览

Using LinearLayout, set the height of your ListView and Button to wrap_content and add a weight=1 to ListView. This should work as you want.
And yes, set the layout_gravity of the Button to bottom

Try to use RelativeLayout with button in the bottom. Set the height of the layout as "wrap_content". I haven't tried it. Just idea

RelativeLayout is a solution, if you don't want the button to stay too close to the bottom you can add margins (padding a button would break it because it uses a 9-patch background, and it sets its own padding).

It would be the same if you used a LinearLayout: the way to achieve what you want is to set the ListView to a height=0 and weight=1, and for the button height=wrap_content and weight=0. (setting both to wrap_content, as user639183 said, would not limit ListView's height).

Since there's no MaxHeight attribute, your best bet is either to set the height of the ListView to a set value, or to use wrap_content.

You can probably make this work using nested containers. It's possible that you might need to wrap the Button in a second (inner) container so that it takes up more space, and just align the Button to the top of the inner container.

Possible something like this:

RelativeLayout

-- ListView

-- RelativeLayout

---- Button

Using the different alignment options on the two containers, you should be able to get this to work.

I had this exact issue and to solve it I created two seperate LinearLayouts to house the ListView and Button respectively. From there I put both in another Linear Layout and set that container's android:orientation to vertical. I also set the weight of the the LinearLayout that housed the ListView to 0.1 but I dont know if that has any effect. From there, you can set the height of the bottom container (that has your button) to whatever height you would like.

EDIT this is what i mean:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">


<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0.1"
android:orientation="horizontal">


<ListView
android:id="@+id/ListView01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:dividerHeight="2px"></ListView>
</LinearLayout>


<LinearLayout
android:layout_width="fill_parent"
android:layout_height="45px"
android:background="@drawable/drawable"
android:orientation="horizontal">


<Button
android:id="@+id/moreButton"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:background="@drawable/btn_more2"
android:paddingRight="20px" />


</LinearLayout>

The above solution will fix the button the the bottom of the screen.


To have the button float at the bottom of the list, change the height of ListView01 to wrap_content:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">


<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0.1"
android:orientation="horizontal">


<ListView
android:id="@+id/ListView01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:dividerHeight="2px"></ListView>
</LinearLayout>


<LinearLayout
android:layout_width="fill_parent"
android:layout_height="45px"
android:background="@drawable/drawable"
android:orientation="horizontal">


<Button
android:id="@+id/moreButton"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:background="@drawable/btn_more2"
android:paddingRight="20px" />
</LinearLayout>

On your last edit, you just have to also add android:layout_above="@+id/butt1" in your ListView code.

And to show you(and everybody here who tried an answer earlier) that you really don't need to use more than one RelativeLayout, here is your corrected code:

   <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/bkg">
<TextView
android:id="@+id/textView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="TextView1"
android:layout_alignParentTop="true">
</TextView>
<TextView
android:id="@+id/textView2"
android:layout_below="@+id/textView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="TextView2"
android:layout_centerHorizontal="true">
</TextView>
<Button
android:id="@+id/butt1"
android:text="string/string3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true">
</Button>
<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dip"
android:layout_marginBottom="2dip"
android:drawSelectorOnTop="false"
android:visibility="visible"
android:layout_below="@+id/textView2"
android:layout_above="@+id/butt1" />
</RelativeLayout>

and the result, using some random list:
enter image description here

I solved this problem in code, setting height of listview only if it has more than 5 items in it:

if(adapter.getCount() > 5){
View item = adapter.getView(0, null, listView);
item.measure(0, 0);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, (int) (5.5 * item.getMeasuredHeight()));
listView.setLayoutParams(params);
}

Notice that I set the max height to 5.5 times the height of a single item, so the user will know for sure there is some scrolling to do! :)

I solved this by putting the ListView inside a ScrollView. Lint didn't like it, but by adding a minHeight and setting the fillViewport to true, I have a nice result.

    <ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="1dp"
android:layout_marginRight="1dp"
android:minHeight="100dp"
android:fillViewport="true"
android:fadeScrollbars="false"
android:paddingTop="2dp"
android:orientation="vertical"
android:scrollbarAlwaysDrawVerticalTrack="true" >


<ListView
android:id="@+id/workoutAElistRoutines"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill_vertical"
android:background="@drawable/dialog_inner_border_tan"
android:choiceMode="singleChoice"
android:orientation="vertical"
android:paddingLeft="3dp"
android:paddingRight="3dp" >


</ListView>
</ScrollView>

Found a way to do this without using nested containers, inspired from AngeloS's solution.

I used a LinearLayout with a vertical orientation, that has a ListView and a button. I set the android:layout_weight="0.1" for the ListView.

It manages to get the button stick to the bottom of the list always. And the button does not get pushed off the screen when the list grows.

<ListView
android:id="@+id/notes_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0.1"
/>


<Button
android:id="@+id/create_note_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onCreateButtonClicked"
android:text="@string/create_notes"
/>

This is the cleanest way to do it:

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ListView
android:id="@+id/ListView01"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:dividerHeight="2px">
</ListView>
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/drawable"
>
<Button android:background="@drawable/btn_more2"
android:id="@+id/moreButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:paddingRight="20px"
/>
</LinearLayout>
</LinearLayout>

It is similar to Angelos's solution but you don't need the linearlayout that wraps up the ListView. Also you can use a FrameLayout which is lighter compare to a LinearLayout to wrap up the Button.

Following is what worked for me...

 if(adapter.getCount() > 3){
View item = adapter.getView(0, null, impDateListView);
item.measure(0, 0);
LayoutParams params = impDateListView.getLayoutParams();
params.width = LayoutParams.MATCH_PARENT;
params.height = 3 * item.getMeasuredHeight();
impDateListView.setLayoutParams(params);




}

Note : The params.width =... Needs to be set also...

The above example is when you use TableRow and ListView inside TableRow...

The idea is outlined in the very good solutions by:

They both seem to work perfectly at least on v4.4.3.

I still had to spend some time writing test code to check it out and confirm each method. Below is the self contained, minimal test code required.


Layout is based on Sparkle's solution, as it contains fewer nested layout. Also has been updated to reflect the current LINT checks.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context="MainActivity" >


<ListView
android:id="@+id/listview"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />


<Button
android:id="@+id/btn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Grow List"
tools:ignore="HardcodedText" />


</LinearLayout>

Activity provides the boilerplate code to test the solution for yourself.

public class MainActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


final ListView listview = (ListView)findViewById(R.id.listview);
final ArrayAdapter<String> adapter =
new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
new ArrayList<String>());
adapter.setNotifyOnChange(true);
listview.setAdapter(adapter);


findViewById(R.id.btn).setOnClickListener(new View.OnClickListener()
{


@Override
public void onClick(View v)
{
int count = adapter.getCount();
adapter.add(String.valueOf(count));
listview.setSelection(count);
}
});
}
}

Feel free to add or improve as this is "community wiki".

wrap content in linear layout

in List View add: android:layout_weight="1"

in your Button set fixed height

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">


<ListView
android:id="@+id/my_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
</ListView>


<Button
android:text="Button"
android:layout_width="match_parent"
android:layout_height="50dp"/>


</LinearLayout>

in LinearLayout, just add android:layout_weight="1" to you ListView

If you want the content below the list view to move down as elements are added to the list, try this solution:

Add positive padding to the bottom of the list view and negative padding to the top of the "footer". This will work in a linear layout or a relative layout.

<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="50dp"/>


<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-50dp"/>