Android Sonsuz Listesi


232

Listenin sonuna geldiğinizde, daha fazla öğe yükleyebilmem için bildirildiğim bir listeyi nasıl oluşturabilirim?


9
CommonWare'in EndlessAdapter'ını öneririm: github.com/commonsguy/cwac-endless . Bu cevaptan başka bir soruya buldum: stackoverflow.com/questions/4667064/… .
Tyler Collier

Aynı şeye ihtiyacım var ... herhangi bir yardıma ihtiyacım var mı? .. stackoverflow.com/questions/28122304/…

Yanıtlar:


269

Bir çözüm, yönteminde uygun bir durumda bir uygulama OnScrollListeneryapmak ve değişiklikler (öğeler ekleme gibi) yapmaktır .ListAdapteronScroll

Aşağıda ListActivity, kullanıcı listenin sonuna geldiğinde öğe ekleyerek 40 ile başlayan tam sayıların bir listesi gösterilmektedir.

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

Açıkça uzun süren eylemler için ayrı web dizileri kullanmanız gerekir (web verilerini yüklemek gibi) ve son liste öğesinde (pazar veya gmail uygulamaları gibi) ilerlemeyi belirtmek isteyebilirsiniz.


3
huh, ekranın ortasındaki kaydırma işlemini durdurursanız bağdaştırıcı boyutu artışını tetiklemez mi? yalnızca listenin en altına ulaştığında sonraki 10'u yüklemelidir.
Matthias

9
BaseAdapter kullanarak bunun gibi birçok örnek fark ettim. Bir veritabanı kullanıyorsanız, SimpleCursorAdapter kullanmayı deneyin. Listeye eklemeniz gerektiğinde, veritabanınızı güncelleyin, yeni bir imleç alın ve notifyDataSetChanged ile birlikte SimpleCursorAdapter # changeCursor kullanın. Alt sınıflama gerekmez ve BaseAdapter'ten daha iyi performans gösterir (yine yalnızca bir veritabanı kullanıyorsanız).
Brack

1
NotifyDataSetChanged () öğesini çağırdıktan sonra, listenin en üstüne gider, nasıl önleyebilirim?
çizmek

2
Bir not - Bu yaklaşımı kullandım, ancak visibleCount 0 olduğunda bir kontrol eklemeniz gerekiyordu. Her liste için, firstVisible, visibleCount ve totalCount öğelerinin tümü 0 olan ve teknik olarak koşullu olan, ancak onScroll'a bir geri çağrı alıyorum daha fazla yüklemek istediğimde.
Eric Mill

5
Bu kodla ilgili başka bir sorun, koşulun firstVisible + visibleCount >= totalCountdinleyiciye yapılan birden fazla çağrı ile birden çok kez karşılanmasıdır. Daha fazla yükle işlevi bir web isteğiyse (büyük olasılıkla bu olacaktır), bir isteğin devam edip etmediğini kontrol etmek için başka bir kontrol ekleyin. Öte yandan, listedeki aynı sayıda öğe için birden fazla istek gerekmediği için totalCount'un Önceki toplam sayıya eşit olup olmadığını kontrol edin.
Subin Sebastian

94

Uygulamam için kullandığım bir çözüme katkıda bulunmak istedim.

Ayrıca OnScrollListenerarayüze dayanıyor , ancak kaydırma işlemleri sırasında görünür / toplam sayım hesaplamalarının hiçbiri yapılmadığından, düşük uçlu cihazlarda çok daha iyi bir kaydırma performansına sahip olduğunu buldum.

  1. Bırakın ListFragmentya da ListActivityuygulayınOnScrollListener
  2. Bu sınıfa aşağıdaki yöntemleri ekleyin:

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

    nerede currentPagelistenize eklenmelidir sizin veri kaynağı sayfası ve thresholdgörünür eğer yükleme sürecini geliştirici olmalıdır (ucundan sayılır) liste öğelerinin sayısıdır. Eğer ayarlarsanız thresholdiçin 0, örneğin, kullanıcı daha fazla öğe yüklemek için listenin en sonuna gitmek için vardır.

  3. (isteğe bağlı) Gördüğünüz gibi, "daha fazla yükleme kontrolü" yalnızca kullanıcı kaydırmayı bıraktığında çağrılır. Kullanılabilirliği artırmak için yoluyla listenin sonuna şişirilebilir ve bir yükleme göstergesi ekleyebilirsiniz listView.addFooterView(yourFooterView). Bu altbilgi görünümü için bir örnek:

    <?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. (isteğe bağlı) Son olarak, listView.removeFooterView(yourFooterView)başka öğe veya sayfa yoksa arayarak yükleme göstergesini kaldırın .


Bunu denedim ama ListFragment için çalışmıyor. ListFragment içinde nasıl kullanılabilir.
zeeshan

Eh, ben ListFragmentde herhangi bir sorun olmadan kullanmak - sadece yukarıdaki adımları izleyin ve iyi olacak;) Veya herhangi bir hata mesajı verebilir misiniz?
saschoar

Kaçırmış olabileceğiniz şey bu SO yanıtında açıklanmıştır: stackoverflow.com/a/6357957/1478093 -getListView().setOnScrollListener(this)
TBieniek

7
not: liste görünümünde altbilgi eklemek ve kaldırmak sorunludur (altbilgi eklenmeden önce setAdapter çağrılırsa altbilgi görünmez), altbilgi görünümünün görünürlüğünü değiştirmeden doğrudan değiştirdim.
DVD

LoadElements (currentPage) içine ne eklenmeli ??? Yani benim AsyncTask veya bir iş parçacığı çağırmak?
android_developer

20

Listenin sonunu onScrollListener yardımıyla tespit edebilirsiniz , çalışma kodu aşağıda sunulmuştur:

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

Bunu yapmanın başka bir yolu (adaptörün içinde) aşağıdaki gibidir:

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

Bu yöntemin birçok kez çağrılacağını unutmayın, bu nedenle birden çok çağrıyı engellemek için başka bir koşul eklemeniz gerekir addMoreData().

Listeye tüm öğeleri eklediğinizde , Görünümü güncellemek için lütfen bağdaştırıcınızın içindeki notifyDataSetChanged () öğesini çağırın ( UI iş parçacığında çalıştırılmalıdır - runOnUiThread )


7
Bir görünümü geri döndürmekten başka şeyler yapmak kötü bir uygulamadır getView. Örneğin pos, kullanıcının görüntülediği garanti edilmez . Sadece ListView ölçüm şeyleri olabilir.
Thomas Ahle

10 öğe kaydırıldıktan sonra daha fazla öğe yüklemek istiyorum. ancak 9. öğenin yüklenmesi 10. öğe görünmeden önce başladığını fark ettim.
Atul Bhardwaj

4

At Ognyan Bankov GitHubı basit ve çalışma çözüm buldu!

Bu yararlanan Volley HTTP libraryAndroid daha hızlı, en önemlisi daha kolay uygulamaları ve için ağ yapar. Voleybolu açık AOSP deposu aracılığıyla edinilebilir.

Verilen kod şunları gösterir:

  1. HTTP sayfalandırılmış istekleri tarafından doldurulan ListView.
  2. NetworkImageView Kullanımı.
  3. "Sonsuz" ReadView ile ListView sayfalama.

Gelecekteki tutarlılık için Bankov'un deposunu çatalladım .


2

Yükleme sırasında ListView öğesinin sonunda bir yükleme görünümü göstermeyi kolaylaştıran bir çözüm.

Sınıfları burada görebilirsiniz:

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.java - Kullanmayı mümkün kılmak için yardımcı özellikleri SimpleListViewWithLoadingIndicator genişletmeden.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java - Kullanıcı veri yüklemeye başlayan dinleyici ListView'in altına ulaşmak üzere.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.java - EndlessListView. Bu sınıfı doğrudan kullanabilir veya sınıftan uzatabilirsiniz.


1

Biraz geç olabilir ama aşağıdaki çözüm benim durumumda çok faydalı oldu. Bir şekilde yapmanız gereken tek şey ListView a'nıza eklemek Footerve oluşturmaktır addOnLayoutChangeListener.

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

Örneğin:

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

Bu etkinlik, bir altbilgi görünür olduğunda bir kez tetiklenir ve bir cazibe gibi çalışır.


0

Bu sorunun anahtarı, daha fazla yükleme olayını algılamak, veriler için zaman uyumsuzluk isteği başlatmak ve listeyi güncellemektir. Ayrıca yükleme göstergeli bir adaptör ve diğer dekoratörler gereklidir. Aslında, bazı köşe vakalarında sorun çok karmaşıktır. Sadece bir OnScrollListeneruygulama yeterli değildir, çünkü bazen öğeler ekranı doldurmaz.

Sonsuz listeyi destekleyen kişisel bir paket yazdım RecyclerViewve aynı zamanda AutoPagerFragmentçok sayfalı bir kaynaktan veri almayı çok kolaylaştıran bir asenkron yükleyici uygulaması sağladım . İstediğiniz herhangi bir sayfayı RecyclerViewyalnızca bir sonraki sayfaya değil, özel bir etkinliğe yükleyebilir .

İşte adresi: https://github.com/SphiaTower/AutoPagerRecyclerManager


Bağlantı koptu.
DSlomer64


0

Ben buna çok benzer başka bir çözüm üzerinde çalışıyorum, ama, ben footerViewkullanıcıya daha fazla öğe indirme imkanı vermek için footerViewkullanıyorum, yukarıda ListViewve altta gösterilen bir "menü" kullanıyorum üst görünümde, bu "menü" öğesinin altını gizler ListView, bu nedenle, listViewmenü kaydırıldığında kaybolur ve kaydırma durumu boştayken, menü tekrar görünür, ancak kullanıcı sonuna geldiğinde listView, footerViewbu durumda gösterilip gösterilmediğini bilmek , menü görünmez ve kullanıcı footerViewdaha fazla içerik yüklemek için görebilirsiniz . İşte kod:

Saygılarımızla.

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

Eski bir soru olduğunu biliyorum ve Android dünyası çoğunlukla RecyclerViews'e taşındı, ancak ilgilenen herkes için bu kütüphaneyi çok ilginç bulabilirsiniz .

Listenin son öğeye ne zaman kaydırıldığını veya son öğeden ne zaman kaydırıldığını tespit etmek için ListView ile kullanılan BaseAdapter kullanır.

Nasıl çalıştığını hızlı bir şekilde anlamak için kullanılabilecek örnek bir proje (ancak 100 satırlık Etkinlik kodu) ile birlikte gelir.

Basit kullanım:

class Boy{

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

}

Boy nesnelerini tutmak için bir adaptör şöyle görünecektir:


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

}

BoysAdapter'ın getView yönteminin EndlessAdapter üst sınıf yöntemine nasıl bir çağrı döndürdüğüne dikkat edin getView. Bu% 100 zorunludur.

Şimdi bağdaştırıcıyı oluşturmak için şunları yapın:

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

loadMoreÖğe bir düğme veya url fazla veri almak için tıklandığında olabilecek diğer ui unsurdur. Kodda açıklandığı gibi yerleştirildiğinde, bağdaştırıcı tam olarak bu düğmenin ne zaman gösterileceğini ve ne zaman devre dışı bırakılacağını bilir. Sadece xml'nizde düğmeyi oluşturun ve yukarıdaki adaptör kodunda gösterildiği gibi yerleştirin.

Zevk almak.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.