当ListView的大小发生变化时,保持ListView的最后一个可见项

时间:2012-02-19 17:43:35

标签: android listview layout

我想要的很简单,至少我认为这很简单。 我只想要一个窗口,其中EditText位于屏幕的底部,其余的空间用ListView填充。 不幸的是,它没有像我预期的那样工作。我想要的是下图。有没有简单的方法在XML中执行此操作,还是应该为此编写一些特殊代码? What I want

我有问题的Android源代码。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
    android:id="@+id/demolist"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
     >
</ListView>
    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:layout_weight="0">
    </EditText>
</LinearLayout >

12 个答案:

答案 0 :(得分:19)

你想要什么

没有键盘的最后一个可见项目

Last Visible Item Without Keyboard

带键盘的最后一个可见项目

Last Visible Item With Keyboard

输入较大的最后一个可见项目

Last Visible Item With larger input

我是这样做的。

摘要

  • 在列表视图中设置 android:stackFromBottom =“true” android:transcriptMode =“alwaysScroll”
  • 在活动中设置 android:windowSoftInputMode =“adjustPan”
  • 在添加新聊天时调用 adapter.notifyDataSetChanged(); ,以便列表视图始终滚动到最后位置
  • 设置 android:inputType =“textMultiLine”&amp; android:maxLines =“4”在EditText中用于增长文本框

详细

<强> 活动

<activity android:name="MainActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan"></activity>

聊天视图

  

<RelativeLayout
    android:id="@+id/chat_header"
    android:layout_width="fill_parent"
    android:layout_height="40dp"
    android:padding="3dp" >

    <Button
        android:id="@+id/btnBackChat"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:layout_alignParentLeft="true"
        android:background="@drawable/back_button" />

    <TextView
        android:id="@+id/txt_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/btnBackChat"
        android:layout_centerHorizontal="true"
        android:textColor="@android:color/white"
        android:textSize="18sp" />

    <ImageView
        android:id="@+id/imgViewProfileChat"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:layout_alignParentRight="true"
        />
</RelativeLayout>

<ListView
    android:id="@+id/listView1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_above="@+id/form"
    android:layout_below="@+id/chat_header"
    android:stackFromBottom="true"
    android:transcriptMode="alwaysScroll"/>

<RelativeLayout
    android:id="@+id/form"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:orientation="vertical" >

    <ImageButton
        android:id="@+id/btnAttach"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:contentDescription="@string/attach"
        android:src="@drawable/attach_icon" />

    <EditText
        android:id="@+id/txtChat"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@+id/btnSend"
        android:layout_toRightOf="@+id/btnAttach"
        android:inputType="textMultiLine"
        android:maxLines="4" />

    <Button
        android:id="@+id/btnSend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:text="@string/send" />
</RelativeLayout>
     

答案 1 :(得分:7)

我想你可能想在显示键盘之前使用AdapterView.getLastVisiblePosition()

这里有两个解决方案:

  • 在EditText上点击
  • 感谢OnScrollListener(及其onScroll函数)监听ListView

然后使用AdapterView.setSelection在EditText焦点后跳转到此项目(或索引-2或索引-3)。

答案 2 :(得分:3)

您可以在AndroidManifest.xml中使用android:windowSoftInputMode="adjustPan",如下所示

 <activity android:name="com.example.SimpleListView"
            android:label="@string/app_name"
            android:windowSoftInputMode="adjustPan" >

这应该产生你想要的输出。官方android documentation

如果您想自动滚动到列表视图的末尾,可以选择为列表视图指定脚本模式(如果您正在处理某些聊天功能)。您也可以查看android:transcriptMode="normal",看看是否合适。

相关的SO answer。官方android doc

<ListView
android:id="@+id/comments"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:transcriptMode="alwaysScroll">

这可以解决你的大多数问题,可能除了最后一个(在图像中)我没有测试过。

答案 3 :(得分:3)

只需覆盖ListView#onSizeChanged(int w,int h,int oldw,int oldh)的方法,如下所示: PS:你的ListView的高度不能随时为0,如果它可能为0,则无效。

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    if (getChildCount() == 0) {
        return;
    }
    final int lastVisiblePosition = getLastVisiblePosition();
    int firstVisiblePosition = getFirstVisiblePosition();

    View last = getChildAt(lastVisiblePosition - firstVisiblePosition);
    int top = last.getTop();
    final int newTop = top + (h - oldh);
    Log.d(getClass().getSimpleName(), "onSizeChanged(" + w + ", " + h + ", " + oldw + ", " + oldh + ")");
    if (mFocusSelector == null) {
        mFocusSelector = new FocusSelector();
    }
    post(mFocusSelector.setup(lastVisiblePosition, newTop));
    super.onSizeChanged(w, h, oldw, oldh);
}

private class FocusSelector implements Runnable {
    private int mPosition;
    private int mPositionTop;

    public FocusSelector setup(int position, int top) {
        mPosition = position;
        mPositionTop = top;
        return this;
    }

    public void run() {
        setSelectionFromTop(mPosition, mPositionTop);
    }
}

答案 4 :(得分:2)

我实际上通过在清单Activityandroid:windowSoftInputMode="adjustResize"声明ListView中添加android:transcriptMode="normal"声明来获得所需的相同行为。对于键盘和方向的更改。

答案 5 :(得分:1)

我也需要这个功能。这是我的尝试,但它不太有用 - 滚动有点不稳定(并不总是在它应该的地方结束)并且它会在旋转屏幕时干扰滚动位置的保留。

@Override
public void onResume() {
    super.onResume();
    getListView().addOnLayoutChangeListener(stickyLastItemHandler);
}

@Override
public void onPause() {
    super.onPause();
    getListView().removeOnLayoutChangeListener(stickyLastItemHandler);
}

View.OnLayoutChangeListener stickyLastItemHandler = new View.OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View v,
            int left, int top, int right, int bottom,
            int oldLeft, int oldTop, int oldRight, int oldBottom) {

        final int heightChange = (bottom - top) - (oldBottom - oldTop);
        if (heightChange != 0) {
            ((AbsListView)v).smoothScrollBy(-heightChange, 1000);
        }
    }
};

答案 6 :(得分:1)

你可以通过xml:

来完成
<ListView
    android:stackFromBottom="true"
    android:layout_height=0dp
    android:layout_weight=1 />

从底部堆叠将使ListView默认向下滚动, 设置ListView的权重将填充父垂直LinearLayout中的所有可能空间。

答案 7 :(得分:1)

我为Android创建了一个布局引擎,允许您监听键盘隐藏和可见状态更改(以及许多其他核心功能)。该库位于http://phil-brown.github.io/AbLE/

只需将jar添加到您的libs目录(如果该文件夹不存在,则创建此文件夹),而不是继承自Activity,继承自AbLEActivity。接下来,覆盖方法onKeyboardShownonKeyboardHidden,在这些方法中,您可以根据需要向上或向下设置内容视图的动画:

@Override
public void onKeyboardShown() {
    //animate up
}

@Override
public void onKeyboardHidden() {
    //animate down
}

答案 8 :(得分:0)

假设您知道列表数据何时发生更改,您可以通过将列表选择设置为最后一行来手动指示列表滚动到底部。像这样:

private void scrollMyListViewToBottom() {
    myListView.post(new Runnable() {
        @Override
        public void run() {
            // Select the last row so it will scroll into view...
            myListView.setSelection(myListAdapter.getCount() - 1) ;
        }
    });
}

或者你也可以试试这个:

ChatAdapter adapter = new ChatAdapter(this);

ListView lview = (ListView) findViewById(R.id.chatList);
lview .setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
lview .setAdapter(adapter);

adapter.registerDataSetObserver(new DataSetObserver() {
    @Override
    public void onChanged() {
        super.onChanged();
        lv.setSelection(adapter.getCount() - 1);    
    }
});

答案 9 :(得分:0)

Follow these steps
--------------------
1. Update your activity in AndroidManifest.xml file like below
<activity
            android:name=".MyListActivity"
            android:windowSoftInputMode="adjustResize" />

2. Set your list view with like below.
mListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
mListView.setStackFromBottom(true);

我希望它能解决你的问题。

答案 10 :(得分:-1)

在ListAdapter中,您可以执行以下操作:

   public View getView(int position, View convertView, ViewGroup parent) {

//buttonMore
if( position >= super.getCount()  )
      return textField ;

    ....

这样,您将始终将列表中的最后一项作为文本字段。

答案 11 :(得分:-1)

你需要设置选择位置...但是 - 以一种奇怪的方式,我真的不明白为什么 - 你需要用post()

来做
public void ScrollToLast() {
    yourList.clearFocus();
    yourList.post(new Runnable() {
        @Override
        public void run() {
            yourList.setSelection(items.size() - 1);
        }
    });
}

所以你可以为你的editText添加一个TextWatcher,你可以在那里调用这个方法......所以你的列表会滚动到底部。