Danh sách vô tận Android


232

Làm cách nào tôi có thể tạo danh sách khi bạn đến cuối danh sách tôi được thông báo để tôi có thể tải thêm các mục?


9
Tôi khuyên dùng EndlessAd CHƯƠNG của CommonWare: github.com/commonsguy/cwac-endless . Tôi tìm thấy nó từ câu trả lời này cho một câu hỏi khác: stackoverflow.com/questions/4667064/ ,.
Tyler Collier

Tôi cần điều tương tự..có thể giúp đỡ ai không? .. stackoverflow.com/questions/28122304/ trên

Câu trả lời:


269

Một giải pháp là thực hiện một OnScrollListenervà thực hiện các thay đổi (như thêm các mục, v.v.) ListAdaptervào trạng thái thuận tiện trong onScrollphương thức của nó .

Sau đây ListActivityhiển thị danh sách các số nguyên, bắt đầu bằng 40, thêm các mục khi người dùng cuộn đến cuối danh sách.

public class Test extends ListActivity implements OnScrollListener {

    Aleph0 adapter = new Aleph0();

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setListAdapter(adapter); 
        getListView().setOnScrollListener(this);
    }

    public void onScroll(AbsListView view,
        int firstVisible, int visibleCount, int totalCount) {

        boolean loadMore = /* maybe add a padding */
            firstVisible + visibleCount >= totalCount;

        if(loadMore) {
            adapter.count += visibleCount; // or any other amount
            adapter.notifyDataSetChanged();
        }
    }

    public void onScrollStateChanged(AbsListView v, int s) { }    

    class Aleph0 extends BaseAdapter {
        int count = 40; /* starting amount */

        public int getCount() { return count; }
        public Object getItem(int pos) { return pos; }
        public long getItemId(int pos) { return pos; }

        public View getView(int pos, View v, ViewGroup p) {
                TextView view = new TextView(Test.this);
                view.setText("entry " + pos);
                return view;
        }
    }
}

Rõ ràng bạn nên sử dụng các luồng riêng biệt cho các hành động chạy dài (như tải dữ liệu web) và có thể muốn chỉ ra tiến trình trong mục danh sách cuối cùng (như các ứng dụng thị trường hoặc gmail làm).


3
huh, điều này sẽ kích hoạt tăng kích thước bộ điều hợp nếu bạn ngừng cuộn ở giữa màn hình? nó chỉ nên tải 10 cái tiếp theo khi thực sự đạt đến đáy danh sách.
Matthias

9
Tôi nhận thấy rất nhiều ví dụ như thế này khi sử dụng BaseAd CHƯƠNG. Muốn đề cập rằng nếu bạn đang sử dụng cơ sở dữ liệu, hãy thử sử dụng SimpleC bổngAd CHƯƠNG. Khi bạn cần thêm vào danh sách, cập nhật cơ sở dữ liệu của bạn, nhận một con trỏ mới và sử dụng SimpleC bổngAd CHƯƠNG # changeCoder cùng với notifyDataSetChanged. Không yêu cầu phân lớp và nó hoạt động tốt hơn BaseAd CHƯƠNG (một lần nữa, chỉ khi bạn đang sử dụng cơ sở dữ liệu).
lợ

1
Sau khi gọi notifyDataSetChanged (), nó sẽ đứng đầu danh sách, làm thế nào tôi có thể ngăn chặn nó?
vẽ

2
Một lưu ý - Tôi đã sử dụng phương pháp này, nhưng cần thêm một kiểm tra khi thấyCount là 0. Với mỗi danh sách, tôi nhận được một cuộc gọi lại với onScroll trong đó FirstVisible, viewerCount và TotalCount đều bằng 0, về mặt kỹ thuật đáp ứng điều kiện, nhưng không khi tôi muốn tải thêm.
Eric Mill

5
Một vấn đề khác với mã này là điều kiện firstVisible + visibleCount >= totalCountđược đáp ứng nhiều lần với nhiều cuộc gọi đến người nghe. Nếu chức năng tải thêm là một yêu cầu web, (rất có thể là như vậy), hãy thêm một kiểm tra xem có yêu cầu nào đang diễn ra hay không. Mặt khác, hãy kiểm tra xem TotalCount không bằng tổng số trước đó, bởi vì chúng tôi không cần nhiều yêu cầu cho cùng một số mục trong danh sách.
Subin Sebastian

94

Chỉ muốn đóng góp một giải pháp mà tôi đã sử dụng cho ứng dụng của mình.

Nó cũng dựa trên OnScrollListenergiao diện, nhưng tôi thấy nó có hiệu suất cuộn tốt hơn nhiều trên các thiết bị cấp thấp, vì không có phép tính tổng số có thể nhìn thấy / tổng số nào được thực hiện trong các hoạt động cuộn.

  1. Hãy để bạn ListFragmenthoặc ListActivitythực hiệnOnScrollListener
  2. Thêm các phương thức sau vào lớp đó:

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        //leave this empty
    }
    
    @Override
    public void onScrollStateChanged(AbsListView listView, int scrollState) {
        if (scrollState == SCROLL_STATE_IDLE) {
            if (listView.getLastVisiblePosition() >= listView.getCount() - 1 - threshold) {
                currentPage++;
                //load more list items:
                loadElements(currentPage);
            }
        }
    }
    

    nơi currentPagelà trang của nguồn dữ liệu của bạn mà nên được thêm vào danh sách của bạn, và thresholdlà số lượng các mục danh sách (tính từ cuối cùng) mà nên, nếu có thể nhìn thấy, kích hoạt quá trình tải. Ví dụ, nếu bạn đặt thresholdthành 0, người dùng phải cuộn đến cuối danh sách để tải thêm các mục.

  3. (tùy chọn) Như bạn có thể thấy, "kiểm tra tải thêm" chỉ được gọi khi người dùng dừng cuộn. Để cải thiện khả năng sử dụng, bạn có thể tăng và thêm một chỉ báo tải vào cuối danh sách thông qua listView.addFooterView(yourFooterView). Một ví dụ cho chế độ xem chân trang như vậy:

    <?xml version="1.0" encoding="utf-8"?>
    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/footer_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="10dp" >
    
        <ProgressBar
            android:id="@+id/progressBar1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_gravity="center_vertical" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/progressBar1"
            android:padding="5dp"
            android:text="@string/loading_text" />
    
    </RelativeLayout>
    
  4. (tùy chọn) Cuối cùng, xóa chỉ báo tải đó bằng cách gọi listView.removeFooterView(yourFooterView)nếu không có thêm mục hoặc trang.


Tôi đã thử điều này nhưng nó không hoạt động cho ListFragment. Làm thế nào nó có thể được sử dụng nó trong ListFragment.
zeeshan

Chà, tôi cũng sử dụng nó ListFragmentmà không gặp vấn đề gì - chỉ cần làm theo từng bước ở trên và bạn sẽ ổn thôi;) Hoặc bạn có thể cung cấp bất kỳ thông báo lỗi nào không?
saschoar

Những gì bạn có thể đã bỏ lỡ được giải thích trong câu trả lời SO này: stackoverflow.com/a/6357957/1478093 -getListView().setOnScrollListener(this)
TBieniek

7
lưu ý: việc thêm và xóa chân trang trên listview có vấn đề (chân trang không hiển thị nếu setAd CHƯƠNG được gọi trước khi thêm chân trang), cuối cùng tôi đã sửa đổi khả năng hiển thị của chế độ xem chân trang mà không xóa nó.
dvd

Những gì phải được thêm vào trong loadElements (currentPage) ??? Ý tôi là tôi gọi AsyncTask của tôi hoặc một chủ đề?
android_developer

20

Bạn có thể phát hiện cuối danh sách với sự trợ giúp của onScrollListener , mã làm việc được trình bày bên dưới:

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    if (view.getAdapter() != null && ((firstVisibleItem + visibleItemCount) >= totalItemCount) && totalItemCount != mPrevTotalItemCount) {
        Log.v(TAG, "onListEnd, extending list");
        mPrevTotalItemCount = totalItemCount;
        mAdapter.addMoreData();
    }
}

Một cách khác để làm điều đó (bên trong bộ chuyển đổi) như sau:

    public View getView(int pos, View v, ViewGroup p) {
            if(pos==getCount()-1){
                addMoreData(); //should be asynctask or thread
            }
            return view;
    }

Xin lưu ý rằng phương thức này sẽ được gọi nhiều lần, vì vậy bạn cần thêm một điều kiện khác để chặn nhiều cuộc gọi của addMoreData().

Khi bạn thêm tất cả các thành phần vào danh sách, vui lòng gọi notifyDataSetChanged () bên trong bộ điều hợp của bạn để cập nhật Chế độ xem (nó sẽ được chạy trên luồng UI - runOnUiThread )


7
Đó là thực tế xấu để làm những thứ khác hơn là trả lại một cái nhìn trong getView. Ví dụ: bạn không được đảm bảo rằng posngười dùng sẽ xem. Nó có thể chỉ đơn giản là công cụ đo ListView.
Thomas Ahle

Tôi muốn tải thêm vật phẩm sau khi cuộn 10 vật phẩm. nhưng tôi nhận thấy rằng tải bắt đầu trước khi mục thứ 10 hiển thị có nghĩa là trên mục thứ 9. Vậy làm thế nào để dừng việc này?
Atul Bhardwaj

4

Tại Ognyan Bankov GitHubtôi tìm thấy một giải pháp đơn giản và làm việc!

Nó giúp việc sử dụng Volley HTTP librarylàm cho việc kết nối mạng cho các ứng dụng Android trở nên dễ dàng hơn và quan trọng nhất là nhanh hơn. Volley có sẵn thông qua kho AOSP mở.

Các mã đã cho thấy:

  1. ListView được điền bởi các yêu cầu phân trang HTTP.
  2. Sử dụng NetworkImageView.
  3. Phân trang ListView "vô tận" với đọc trước.

Để thống nhất trong tương lai, tôi đã rẽ nhánh repo của Bankov .


2

Đây là một giải pháp cũng giúp bạn dễ dàng hiển thị chế độ xem tải ở cuối ListView trong khi tải.

Bạn có thể xem các lớp học ở đây:

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/rcper/ListViewWithLoadingIndicatorHelper.java để sử dụng nó các tính năng mà không cần mở rộng từ SimpleListViewWithLoadingTheicator.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java - Trình nghe bắt đầu tải dữ liệu khi người dùng bắt đầu tải dữ liệu sắp chạm đến đáy của ListView.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.java - EndView Bạn có thể sử dụng lớp này trực tiếp hoặc mở rộng từ nó.


1

Có thể hơi muộn nhưng giải pháp sau đây đã xảy ra rất hữu ích trong trường hợp của tôi. Theo một cách nào đó, tất cả những gì bạn cần làm là thêm vào ListView của bạn Footervà tạo cho nó addOnLayoutChangeListener.

http://developer.android.com/reference/android/widget/ListView.html#addFooterView(android.view.View)

Ví dụ:

ListView listView1 = (ListView) v.findViewById(R.id.dialogsList); // Your listView
View loadMoreView = getActivity().getLayoutInflater().inflate(R.layout.list_load_more, null); // Getting your layout of FooterView, which will always be at the bottom of your listview. E.g. you may place on it the ProgressBar or leave it empty-layout.
listView1.addFooterView(loadMoreView); // Adding your View to your listview 

...

loadMoreView.addOnLayoutChangeListener(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) {
         Log.d("Hey!", "Your list has reached bottom");
    }
});

Sự kiện này kích hoạt một lần khi một footer trở nên hữu hình và hoạt động như một lá bùa.


0

Chìa khóa của vấn đề này là phát hiện sự kiện tải thêm, bắt đầu yêu cầu không đồng bộ dữ liệu và sau đó cập nhật danh sách. Ngoài ra một bộ chuyển đổi với chỉ báo tải và trang trí khác là cần thiết. Trong thực tế, vấn đề rất phức tạp trong một số trường hợp góc. Chỉ cần OnScrollListenerthực hiện là không đủ, vì đôi khi các mục không lấp đầy màn hình.

Tôi đã viết một gói cá nhân hỗ trợ danh sách vô tận RecyclerViewvà cũng cung cấp triển khai trình tải không đồng bộ AutoPagerFragment, giúp lấy dữ liệu từ nguồn nhiều trang rất dễ dàng. Nó có thể tải bất kỳ trang nào bạn muốn vào một RecyclerViewsự kiện tùy chỉnh, không chỉ trang tiếp theo.

Đây là địa chỉ: https://github.com/S chếTower / AutoPagerRecyclerManager


Liên kết bị hỏng.
DSlomer64


0

Tôi đã làm việc trong một giải pháp khác rất giống với giải pháp đó, nhưng, tôi đang sử dụng footerViewđể cung cấp khả năng cho người dùng tải xuống nhiều yếu tố hơn khi nhấp vào footerView, tôi đang sử dụng một "menu" được hiển thị ở trên ListViewvà dưới cùng của Chế độ xem chính, "menu" này ẩn phía dưới ListView, vì vậy, khi listViewcuộn đang cuộn menu biến mất và khi trạng thái cuộn không hoạt động, menu sẽ xuất hiện lại, nhưng khi người dùng cuộn đến cuối listView, tôi "hỏi" biết nếu footerViewđược hiển thị trong trường hợp đó, menu sẽ không xuất hiện và người dùng có thể thấy footerViewđể tải thêm nội dung. Đây là mã:

Trân trọng.

listView.setOnScrollListener(new OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // TODO Auto-generated method stub
        if(scrollState == SCROLL_STATE_IDLE) {
            if(footerView.isShown()) {
                bottomView.setVisibility(LinearLayout.INVISIBLE);
            } else {
                bottomView.setVisibility(LinearLayout.VISIBLE);
            } else {
                bottomView.setVisibility(LinearLayout.INVISIBLE);
            }
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {

    }
});

0

Tôi biết đó là một câu hỏi cũ và thế giới Android chủ yếu chuyển sang RecyclerViews, nhưng với bất kỳ ai quan tâm, bạn có thể thấy thư viện này rất thú vị.

Nó sử dụng BaseAd CHƯƠNG được sử dụng với ListView để phát hiện khi danh sách đã được cuộn đến mục cuối cùng hoặc khi nó được cuộn ra khỏi mục cuối cùng.

Nó đi kèm với một dự án ví dụ (chỉ có 100 dòng mã Activity) có thể được sử dụng để nhanh chóng hiểu cách thức hoạt động của nó.

Cách sử dụng đơn giản:

class Boy{

private String name;
private double height;
private int age;
//Other code

}

Một bộ chuyển đổi để giữ các đối tượng Boy sẽ trông như sau:


public class BoysAdapter extends EndlessAdapter<Boy>{




        ViewHolder holder = null;


        if (convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(parent
                    .getContext());

            holder = new ViewHolder();

            convertView = inflater.inflate(
                    R.layout.list_cell, parent, false);


            holder.nameView = convertView.findViewById(R.id.cell);

            // minimize the default image.
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        Boy boy = getItem(position);

        try {
            holder.nameView.setText(boy.getName());

            ///Other data rendering codes.

        } catch (Exception e) {
            e.printStackTrace();
        }

        return super.getView(position,convertView,parent);

}

Lưu ý cách phương thức getView của BoysAd CHƯƠNG trả về một cuộc gọi đến getViewphương thức của siêu lớp EndlessAd CHƯƠNG . Đây là 100% thiết yếu.

Bây giờ để tạo bộ điều hợp, hãy làm:

   adapter = new ModelAdapter() {
            @Override
            public void onScrollToBottom(int bottomIndex, boolean moreItemsCouldBeAvailable) {

                if (moreItemsCouldBeAvailable) { 
                    makeYourServerCallForMoreItems();
                } else {
                    if (loadMore.getVisibility() != View.VISIBLE) {
                        loadMore.setVisibility(View.VISIBLE);
                    }
                }
            }

            @Override
            public void onScrollAwayFromBottom(int currentIndex) { 
                loadMore.setVisibility(View.GONE);
            }

            @Override
            public void onFinishedLoading(boolean moreItemsReceived) { 
                if (!moreItemsReceived) {
                    loadMore.setVisibility(View.VISIBLE);
                }
            }
        };

Các loadMoremục là một nút hoặc yếu tố ui khác có thể nhấp vào để lấy dữ liệu hơn từ url. Khi được đặt như được mô tả trong mã, bộ điều hợp biết chính xác khi nào sẽ hiển thị nút đó và khi nào nên tắt nó. Chỉ cần tạo nút trong xml của bạn và đặt nó như hiển thị trong mã bộ điều hợp ở trên.

Thưởng thức.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.