English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Implementazione di Android di ListView con caricamento di più dati in cima (PulmListView)

Pensiero

Oggi vi mostro come implementare un ListView con caricamento in più verso l'alto. Link GitHub:PulmListView, benvenuti a fork && star.

Prima di tutto, portiamo chiarezza di mente, se vogliamo implementare un ListView con caricamento in più verso l'alto, dobbiamo implementare le funzioni necessarie, tra cui:
1. Un ListView personalizzato, e questo ListView può giudicare se è già alla fine.
 2. Un FooterView personalizzato, utilizzato per la presentazione dell'UI durante il caricamento in più di ListView.
 3. Collegare FooterView e ListView, inclusa la giudiazione del momento di caricamento, la visualizzazione e l'occultamento di FooterView.
 4. Fornire un'interfaccia di caricamento in più, per facilitare la callback dell'implementazione effettiva del caricamento in più.
 5. Fornire un metodo di callback per il completamento del caricamento, utilizzato per aggiungere i dati più recenti dell'utente e aggiornare i segnaposto di stato e l'UI. 

Per le cinque funzioni menzionate sopra, analizziamo singolarmente i relativi metodi di implementazione.

Funzione 1(ListView personalizzato)

Possiamo implementare una PulmListView personalizzata tramite l'ereditarietà di ListView.

public class PulmListView extends ListView {
  public PulmListView(Context context) {
    this(context, null);
  }
  public PulmListView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }
  public PulmListView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    // Inizializzazione
    init();
  }
}

Non è sufficiente implementare i tre costruttori di ListView, dobbiamo far sì che ListView possa giudicare se si è scollati sull'ultimo elemento.

Giudicare se ci si è scollato sull'ultimo elemento, possiamo implementare OnScrollListener per ListView. Il codice è il seguente:

private void init() {
  super.setOnScrollListener(new OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
      // Chiamata all'OnScrollListener impostato dall'utente
      if (mUserOnScrollListener != null) {
        mUserOnScrollListener.onScrollStateChanged(view, scrollState);
      }
    }
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
      // Chiamata all'OnScrollListener impostato dall'utente
      if (mUserOnScrollListener != null) {
        mUserOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
      }
      // firstVisibleItem è la posizione dell'elemento primo visibile sulla schermata
      // visibleItemCount è il numero di elementi visibili attualmente sulla schermata
      // totalItemCount è il numero totale degli elementi contenuti nella ListView
      int lastVisibleItem = firstVisibleItem + visibleItemCount;
      if (!mIsLoading && !mIsPageFinished && lastVisibleItem == totalItemCount) {
        if (mOnPullUpLoadMoreListener != null) {
          mIsLoading = true;
          mOnPullUpLoadMoreListener.onPullUpLoadMore();
        }
      }
    }
  });
}

Dal commento del codice si può sapere che attraverso (firstVisibleItem + visibleItemCount) si può ottenere il numero di elementi visualizzati attualmente sullo schermo. Se il numero di elementi visualizzati attualmente è uguale al numero totale degli elementi della ListView, allora si può considerare che la ListView è stata scollata fino in fondo.

Funzione 2(FooterView personalizzato)

Qui possiamo implementare un FooterView piuttosto semplice, ossia il layout dell'UI per la visualizzazione di più elementi. Ad esempio, possiamo mostrare un ProgressBar e una riga di testo, ecco il codice specifico:

/**
 * Layout per la visualizzazione di più elementi, personalizzabile.
 */
public class LoadMoreView extends LinearLayout {
  public LoadMoreView(Context context) {
    this(context, null);
  }
  public LoadMoreView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }
  public LoadMoreView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
  }
  private void init() {
    LayoutInflater.from(getContext()).inflate(R.layout.lv_load_more, this);
  }
}

File di layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/id_load_more_layout"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="horizontal"
  android:gravity="center"
  android:layout_margin="@dimen/loading_view_margin_layout">
  <ProgressBar
    android:id="@+id/id_loading_progressbar"
    android:layout_width="@dimen/loading_view_progress_size"
    android:layout_height="@dimen/loading_view_progress_size"
    android:indeterminate="true"
    style="?android:progressBarStyleSmall"/>
  <TextView
    android:id="@+id/id_loading_label"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/page_loading"/>
</LinearLayout>

Funzione 3(Collegamento ListView e FooterView)

Prima di tutto, dobbiamo salvare FooterView in una variabile nella ListView e istanziarla nel costruttore.

private View mLoadMoreView;
private void init() {
  mLoadMoreView = new LoadMoreView(getContext());
}

Secondo, dobbiamo controllare la visualizzazione e la nascita di FooterView. Consideriamo il momento di visualizzazione e nascita di FooterView:
• Occasione di visualizzazione: ListView si trova nella parte inferiore e ci sono ancora più dati da caricare.
• Occasione di nascita: ListView completa l'operazione di caricamento di più dati. 

Per determinare se ci sono ancora dati da caricare, dobbiamo definire una variabile booleana mIsPageFinished per indicare se il caricamento dei dati è terminato.
Per garantire che venga eseguito solo una volta il processo di caricamento dei dati nello stesso momento, quindi dobbiamo definire una variabile booleana mIsLoading per indicare se è già in stato di caricamento dei dati.

Ecco chiaro il momento di visualizzazione e nascita di FooterView, ci sono anche variabili di controllo dello stato, quindi il codice è abbastanza facile da implementare.

Mostra l'occasione:

private void init() {
  mIsLoading = false; // Durante l'inizializzazione, non è in stato di caricamento
  mIsPageFinished = false; // Durante l'inizializzazione, viene impostato come predefinito che ci sono più dati da caricare
  mLoadMoreView = new LoadMoreView(getContext()); // Istanzia FooterView
  super.setOnScrollListener(new OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
      // Chiamata all'OnScrollListener impostato dall'utente
      if (mUserOnScrollListener != null) {
        mUserOnScrollListener.onScrollStateChanged(view, scrollState);
      }
    }
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
      // Chiamata all'OnScrollListener impostato dall'utente
      if (mUserOnScrollListener != null) {
        mUserOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
      }
      int lastVisibleItem = firstVisibleItem + visibleItemCount;
      // Quando si trova alla fine della ListView e ci sono più dati da caricare senza alcun caricamento in corso, esegui l'operazione di caricamento in più
      if (!mIsLoading && !mIsPageFinished && lastVisibleItem == totalItemCount) {
        if (mOnPullUpLoadMoreListener != null) {
          mIsLoading = true; // Imposta lo stato di caricamento in corso a true
          showLoadMoreView(); // Mostra la layout di caricamento in più
          mOnPullUpLoadMoreListener.onPullUpLoadMore(); // Chiamata all'interfaccia di callback di caricamento in più impostata dall'utente
        }
      }
    }
  });
}
private void showLoadMoreView() {
  // Qui si imposta l'id del layout radice del caricamento ulteriore come id_load_more_layout, per facilitare la personalizzazione del layout di caricamento ulteriore dell'utente.
  if (findViewById(R.id.id_load_more_layout) == null) {
    addFooterView(mLoadMoreView);
  }
}

Momento di occultamento:

/**
 * metodo di callback chiamato alla fine del caricamento di più elementi.
 *
 * @param isPageFinished Se la paginazione è finita
 * @param newItems    Dati caricati in paginazione
 * @param isFirstLoad  Se è la prima volta che si carica i dati (usato per configurare la framework di aggiornamento in discesa, per evitare che la pagina si illumini)
 */
public void onFinishLoading(boolean isPageFinished, List<?> newItems, boolean isFirstLoad) {
  mIsLoading = false; // Marchio che attualmente non ci sono programmi di caricamento ulteriore in esecuzione
  setIsPageFinished(isPageFinished); // Impostare il flag di fine della paginazione e rimuovere FooterView
}
private void setIsPageFinished(boolean isPageFinished) {
  mIsPageFinished = isPageFinished;
  removeFooterView(mLoadMoreView);
}

Funzione 4(Interfaccia di callback per l'implementazione del caricamento ulteriore in alto)

Questo è abbastanza semplice, definiamo un'interface per facilitare il callback dell'implementazione reale del caricamento ulteriore dell'utente.

/**
 * Interfaccia di callback per il caricamento ulteriore in alto
 */
public interface OnPullUpLoadMoreListener {
  void onPullUpLoadMore();
}
private OnPullUpLoadMoreListener mOnPullUpLoadMoreListener;
/**
 * Impostare l'interfaccia di callback per il caricamento ulteriore in alto.
 * @param l Interfaccia di callback per il caricamento ulteriore in alto
 */
public void setOnPullUpLoadMoreListener(OnPullUpLoadMoreListener l) {
  this.mOnPullUpLoadMoreListener = l;
}

Funzione 5(Callback di fine del caricamento ulteriore)

Per mantenere le raccolte di dati nel PulmListView, è necessario personalizzare un Adapter, utilizzare una lista per memorizzare la raccolta di dati nell'Adapter e fornire metodi per aggiungere e rimuovere elementi.

Adapter personalizzato:

/**
 * Adapter astratto.
 */
public abstract class PulmBaseAdapter<T> extends BaseAdapter {
  protected List<T> items;
  public PulmBaseAdapter() {
    this.items = new ArrayList<>();
  }
  public PulmBaseAdapter(List<T> items) {
    this.items = items;
  }
  public void addMoreItems(List<T> newItems, boolean isFirstLoad) {
    if (isFirstLoad) {
      this.items.clear();
    }
    this.items.addAll(newItems);
    notifyDataSetChanged();
  }
  public void removeAllItems() {
    this.items.clear();
    notifyDataSetChanged();
  }
}

Perché in metodo addMoreItems viene aggiunto un variabile isFirstLoad?

È perché il caricamento di più elementi di solito deve essere utilizzato insieme all'aggiornamento in discesa. Durante il processo di aggiornamento in discesa, viene coinvolta la raccolta di dati ListView clear e poi addAll. Senza il parametro isFirstLoad, per aggiornare la raccolta di dati ListView dell'utente durante l'aggiornamento in discesa, deve essere diviso in due passaggi:
1.removeAllItems e poi notifyDataSetChanged.
 2.addMoreItems e poi notifyDataSetChanged. 

Due volte consecutive di notifyDataSetChanged possono causare uno schermo che sbatte, quindi è stata proposta una funzione isFirstLoad. Quando i dati vengono caricati per la prima volta, viene prima cancellato tutto il dato, poi aggiunto tutto e infine notificato.

Con un adapter personalizzato, è possibile scrivere una funzione di callback per la fine del caricamento di più elementi:

/**
 * metodo di callback chiamato alla fine del caricamento di più elementi.
 *
 * @param isPageFinished Se la paginazione è finita
 * @param newItems    Dati caricati in paginazione
 * @param isFirstLoad  Se è la prima volta che si carica i dati (usato per configurare la framework di aggiornamento in discesa, per evitare che la pagina si illumini)
 */
public void onFinishLoading(boolean isPageFinished, List<?> newItems, boolean isFirstLoad) {
  mIsLoading = false;
  setIsPageFinished(isPageFinished);
  // Aggiungere i dati aggiornati
  if (newItems != null && newItems.size() > 0) {
    PulmBaseAdapter adapter = (PulmBaseAdapter) ((HeaderViewListAdapter) getAdapter()).getWrappedAdapter();
    adapter.addMoreItems(newItems, isFirstLoad);
  }
}

Ecco cosa devi notare, quando si aggiunge FooterView o HeaderView, non possiamo ottenere il nostro adapter personalizzato tramite listview.getAdapter(), dobbiamo seguire i seguenti passaggi:

PulmBaseAdapter adapter = (PulmBaseAdapter) ((HeaderViewListAdapter) getAdapter()).getWrappedAdapter();

Riferimento
 1.PagingListView

Questo è tutto il contenuto dell'articolo, spero che sia utile per la tua apprendimento, e spero che tu sostenga fortemente il tutorial urla.

Dichiarazione: il contenuto di questo articolo è stato prelevato da Internet, il copyright è dell'autore originale, il contenuto è stato contribuito autonomamente dagli utenti di Internet e caricato autonomamente, il sito web non possiede il diritto di proprietà, non è stato elaborato manualmente e non assume alcuna responsabilità legale correlata. Se trovi contenuti sospetti di violazione del copyright, invia un'e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare, fornendo prove pertinenti. Una volta verificata, il sito eliminerà immediatamente il contenuto sospetto di violazione del copyright.

Ti potrebbe interessare