【问题标题】:How to update ListView entries and let the user continue and scrolling the listview values?如何更新 ListView 条目并让用户继续并滚动 listview 值?
【发布时间】:2019-05-29 17:38:18
【问题描述】:

我正在尝试在用户滚动列表时更新 listView 列表,并为用户提供继续和滚动新条目的选项,但没有成功,我需要帮助。

在我的应用程序中,我有一个聊天记录,我正在 SQLite 中保存聊天记录。当用户进入聊天时,应用程序只读取最后 25 条消息,并在列表底部显示最新消息。 为此,我在 XML 中使用以下选项:

    android:transcriptMode="alwaysScroll"
    android:stackFromBottom="true"

它工作正常。 现在,当用户开始向上滚动并检查聊天历史记录时,当他到达列表顶部时,我正在访问数据库并检索另外 25 条消息并将它们添加到列表顶部,我我呼吁: chatAdaptor.notifyDataSetChanged();

但是当用户试图向上滚动时,什么都不会显示,只有在再次向下和向上滚动后才会显示新条目。

我尝试使用 setSelection 和 smoothScrollToPosition 设置列表视图的位置,但它并没有真正起作用。

它如何用新条目更新列表并让用户选择继续并向上滚动?

这里是相关代码:

<ListView
    android:id="@+id/chatList"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="bottom"
    android:layout_margin="2dp"
    android:layout_weight="1"
    android:transcriptMode="alwaysScroll"
    android:stackFromBottom="true"
    android:background="@drawable/frame_tab"></ListView>


public void showChatLines() {

    chatLinesView = chatTextDialog.findViewById(R.id.chatList);

    chatAdaptor = new GenericAdapter<ChatLine>(activity, chatLines) {
        @Override
        public View getMyView(int position, View convertView, ViewGroup parent, ChatLine chatLine) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View view = inflater.inflate(R.layout.chat_line, null);

            TextView chatLineText = view.findViewById(R.id.chatLine);
            chatLineText.setText(chatLine.messageText);
            TextView chatLineTime = view.findViewById(R.id.chatLineTime);
            chatLineTime.setText(chatLine.displayDateTime);
            TextView chatLineUserName = view.findViewById(R.id.userName);
            chatLineUserName.setText(chatLine.userDisplayName);
            chatLineUserName.setTextColor(activity.getColor(Constants.colors[getColorBy(chatLine.userName)]));

            LinearLayout chatLineLayout = view.findViewById(R.id.chatLineLayout);
            LinearLayout.LayoutParams chatLineLayoutParams = (LinearLayout.LayoutParams) chatLineLayout.getLayoutParams();
            CardView chatLineBackground = view.findViewById(R.id.chatLineBackground);
            LinearLayout.LayoutParams chatLineBackgroundParams = (LinearLayout.LayoutParams) chatLineBackground.getLayoutParams();
            LinearLayout chatLineSubLayout = view.findViewById(R.id.chatLineSubLayout);
            FrameLayout.LayoutParams chatLineSubLayoutParams = (FrameLayout.LayoutParams) chatLineSubLayout.getLayoutParams();

            if (chatLine.userName.equals(logonUserName)) {
                CardView charLineCard = view.findViewById(R.id.chatLineBackground);
                charLineCard.setCardBackgroundColor(activity.getColor(R.color.focusedColor));
                ((ViewGroup) chatLineUserName.getParent()).removeView(chatLineUserName);
            } else {
                chatLineLayoutParams.gravity = Gravity.RIGHT;
                chatLineLayout.setLayoutParams(chatLineLayoutParams);
                chatLineSubLayoutParams.gravity = Gravity.RIGHT;
                chatLineSubLayout.setLayoutParams(chatLineSubLayoutParams);
                chatLineBackgroundParams.gravity = Gravity.RIGHT;
                chatLineBackground.setLayoutParams(chatLineBackgroundParams);
            }

            if (position==0 & fromLine!=0) {
                getNextChatLinesFromDb(position);
            }
            return view;
        }
    };

    chatLinesView.setAdapter(chatAdaptor);

}

private void getNextChatLinesFromDb(int position) {
    toLine = fromLine - 1;
    fromLine -= pageSize;
    if (fromLine < 0) {
        fromLine = 0;
    }
    ArrayList<ChatLine> newChatLines = db.getChatLines(chatRoomId, fromLine, toLine);
    chatLines.addAll(0, newChatLines);
    chatAdaptor.notifyDataSetChanged();
}

【问题讨论】:

  • 能否请您发布您的代码?
  • 我已经添加了相关代码。

标签: android android-listview


【解决方案1】:

试试下面的示例代码:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">

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

</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements AbsListView.OnScrollListener{

final static private int ADD_DATA_SIZE = 10;

ArrayList<String> dataList;
ListView listView;
ArrayAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    dataList = new ArrayList<>();
    for(int i=0; i<30; i++){
        dataList.add("Item " + i);
    }
    listView = findViewById(R.id.listView);
    adapter = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_list_item_1, dataList);
    listView.setAdapter(adapter);

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            Toast.makeText(getApplicationContext(), adapterView.getItemAtPosition(i) + " Clicked!", Toast.LENGTH_SHORT).show();
        }
    });
    listView.setOnScrollListener(this);
}

private void addNewData() {
    ArrayList<String> tmpList = new ArrayList<>();
    for(int i=0; i<ADD_DATA_SIZE; i++){
        tmpList.add("Add " + (dataList.size() - 20)/10 + ": Item " + i);
    }
    dataList.addAll(0, tmpList);

    // Try this:
    //listView.setSelection(ADD_DATA_SIZE);
    //adapter.notifyDataSetInvalidated();
    // or this:
    adapter.notifyDataSetChanged();
    listView.setSelection(ADD_DATA_SIZE);

}

@Override
public void onScrollStateChanged(AbsListView absListView, int i) {}

@Override
public void onScroll(AbsListView absListView, int firstVisibleItem,
                     int visibleItemCount, int totalItemCount) {
    if(firstVisibleItem == 0){
        View view = absListView.getChildAt(0);
        if(view != null){
            if (view.getTop() == absListView.getTop()) {
                absListView.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_DISABLED);
                Toast.makeText(getApplicationContext(), "TRANSCRIPT MODE CHANGED TO: "
                        + absListView.getTranscriptMode(), Toast.LENGTH_SHORT).show();
                addNewData();
            }
        }
    } else if (totalItemCount == (firstVisibleItem + visibleItemCount)){
        View view = absListView.getChildAt(visibleItemCount - 1);
        if (view.getBottom() == absListView.getBottom()) {
            absListView.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
            Toast.makeText(getApplicationContext(), "TRANSCRIPT MODE CHANGED TO: "
                    + absListView.getTranscriptMode(), Toast.LENGTH_SHORT).show();
        }
    }
}
}

希望对你有帮助!

【讨论】:

    【解决方案2】:

    我认为这段代码会对你有所帮助:

    // get position of listview
    int index = chatLinesView.getFirstVisiblePosition();
    View v = chatLinesView.getChildAt(0);
    int top = (v == null) ? 0 : v.getTop();
    
    // notify dataset changed or re-assign adapter here
    
    //re-assign the position of listview after setting the adapter again
    chatLinesView.setSelectionFromTop(index, top);
    

    编辑

    int h1 = chatLinesView.getHeight();
    int h2 = chatLinesViewRow.getHeight();
    
    chatLinesView.smoothScrollToPositionFromTop(position, h1/2 - h2/2, duration);
    

    参数 position -> 要滚动到的位置

    offset ---->距离顶部位置的所需距离(以像素为单位) 滚动完成时查看

    duration-> 用于滚动的毫秒数

    【讨论】:

    • 我已经尝试过了,但是替换了 Log.v(TAG, "Scrolled up");我的条件是从数据库中获取新条目,但它仍然无法正常工作。向上滚动在最后一个原始条目处停止,只有在再次向下和向上滚动后才能识别新条目。
    • 实际上发生的事情是当 chatAdaptor.notifyDataSetChanged();被称为 listView 正在跳转到列表的末尾。我试图打电话给 chatLinesView.setStackFromBottom(false);所以在这种情况下,列表视图会跳到列表的顶部。
    • 是的,只需在 setSelectionFromTop 中保留您想要的位置
    • 您的新建议也不起作用....一旦我通知更改,列表视图就会跳到列表视图的末尾。无论如何,我阅读了 setSelectionFromTop 的文档,上面写着“设置所选项目并从 ListView 的顶部边缘定位选择 y 像素。”所以我不认为它可以提供帮助,因为它谈论的是 y 像素....我无法计算,因为聊天中的每个项目都可以有不同的大小。所以你有任何其他想法如何在通知更改后滚动到正确的位置???
    • 新建议的解决方案也不起作用,在我调用通知更改时,listvies 正在跳转到列表的末尾,并且 smoothScrollToPositionFromTop 什么也不做!。有些事情我无法理解。为什么简单的 setSelection 不起作用?我唯一需要的是如何以编程方式将列表视图导航到特定位置??
    猜你喜欢
    • 2019-06-14
    • 2019-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多