Android 当ListView的大小更改时保留ListView的最后一个可见项

Android 当ListView的大小更改时保留ListView的最后一个可见项,android,listview,layout,Android,Listview,Layout,我想要的是简单的,至少我认为会很简单。 我只想要一个窗口,其中一个EditText位于屏幕底部,其余空间填充ListView。 不幸的是,它没有像我预期的那样工作。我想要的是下图。在XML中有什么简单的方法可以做到这一点,或者我应该为此编写一些特殊的代码吗? 我有问题的Android源代码 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.co

我想要的是简单的,至少我认为会很简单。 我只想要一个窗口,其中一个EditText位于屏幕底部,其余空间填充ListView。 不幸的是,它没有像我预期的那样工作。我想要的是下图。在XML中有什么简单的方法可以做到这一点,或者我应该为此编写一些特殊的代码吗?

我有问题的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 >

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

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

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

    ....

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

您需要设置选择位置。。。但是——奇怪的是,我真的不明白为什么——你需要用post()来做


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

我也需要此功能。这是我的尝试,但效果不太好——滚动有点不稳定(并不总是在应该的地方结束),旋转屏幕时会干扰滚动位置的保持

@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);
        }
    }
};

我想您可能想在显示键盘之前使用

这里有两种解决方案:

  • 在编辑文本时,单击
  • 感谢OnScrollListener(及其onScroll函数)监听您的ListView

然后在编辑文本焦点后,使用跳转到此项目(或索引-2或索引-3)。

您可以通过xml:

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

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

您可以在AndroidManifest.xml中使用android:WindowsOfInputMode=“adjustPan”,如下所示

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

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

您想要什么

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

带键盘的最后可见项

具有较大输入的最后可见项

以下是我是如何做到的。

总结

  • 在列表视图中设置android:stackFromBottom=“true”android:transcriptMode=“alwaysScroll”
  • 在活动中设置android:WindowsOfInputMode=“adjustPan”
  • 调用适配器.notifyDataSetChanged()添加新聊天时,列表视图将始终滚动到最后一个位置
  • 在EditText for Growth文本框中设置android:inputType=“textMultiLine”&android:maxLines=“4”
细节

活动


聊天视图



假设您知道列表数据何时发生更改,您可以通过将列表选择设置为最后一行,手动告诉列表滚动到底部。大概是这样的:

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);    
    }
});

我为Android创建了一个布局引擎,允许你监听键盘隐藏和可见的状态变化(以及许多其他核心功能)。该图书馆可在以下网址获得:

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

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

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

通过添加到清单
android:windowSoftInputMode=“adjustResize”
中的
Activity
声明和
ListView
声明
android:transcriptMode=“normal”
,我实际上获得了与您所需的相同的行为。更改键盘和方向。

按照以下步骤操作
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);
-------------------- 1.更新AndroidManifest.xml文件中的活动,如下所示 2.用下面的方法设置列表视图。 mListView.setTranscriptMode(ListView.TRANSCRIPT\u MODE\u ALWAYS\u SCROLL); mListView.setStackFromBottom(true);

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

只需重写ListView#onSizeChanged(intw,inth,intoldw,intoldh)的方法即可 如下图所示: 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);
    }
}

不,请仔细看我的照片。我特别提到,它不是最后一个项目,而是最后一个“可见”项目。看到图片最左边的部分,你会得到你想要的。我给出的解决方案使文本字段成为列表中的最后一项。如果不可见,因为用户没有向下滚动到列表的末尾,那么它就不可见了……您找到方法了吗?我正在寻找完全相同的行为。您希望最后一个项目的行为如何,捕捉使其完全可见还是保持当前状态(如一半,只有几个像素等)?我认为捕捉到完全可见可能是最整洁的。我的应用程序是一个任务列表,使用编辑框应该在上一个可见任务的正下方添加一个新任务。(在输入文本后,我会将新项目向上滚动到视图中。)不幸的是,这不能满足我的需要。列表最初将滚动到底部,但当软键盘出现时,其行为与没有此标志时的行为相同。我已经尝试过调整平移,但这会将操作栏滚动到视图之外,并使在键盘可见的情况下滚动列表变得很尴尬。不幸的是,转录模式也没有用——我不希望它滚动到列表的底部。(我认为OP已经很好地解释了这一点,这就是为什么我在他的帖子中添加了一个悬赏而不是开始我自己的帖子。)我需要最后一个可见项在键盘出现时保持最后一个可见项。嗯。。棘手的是,您可以尝试检测软键盘的高度,并手动调整listview的高度,将其设置为最后可见的位置(如果可能,请使用setSelecti)
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);    
    }
});
@Override
public void onKeyboardShown() {
    //animate up
}

@Override
public void onKeyboardHidden() {
    //animate down
}
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);
@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);
    }
}