CodeLab : ListView dengan SwipeRefreshLayout dan LoadMore Deskripsi Adakalanya ketika kita menginginkan aplikasi dapat melakukan load data secara bertahap (per-10 data misalnya) nah ini sudah menjadi case umum dimana hampir semua aplikasi yang berhubungan dengan data yang banyak dan ada di webservice / API pasti akan menampilkan proses ini. Menarik ListView kebawah untuk meload datadata terbaru (PullToRefresh) atau ketika ListView sudah pada baris paling bawah saat pengguna melakukan scroll secara vertical, aplikasi akan meload data lagi (LoadMore). Setelah mempelajari implementasi pada ListView di CodeLab sebelumnya sekarang kita akan fokus pada bagaimana menambahkan fungsionalitas PullToRefresh dengan SwipeRefreshLayout dan LoadMore dengan membuat Custom ListView.
Output :
Langkah – langkah : 1. Buat project dengan nama SwipeRefreshandLoadMore dengan nama package yang dikehendaki (disini saya menggunakan com.sidiq.codelab.swiperefreshandloadmorelistview) kemudian klik next hingga finish. Tunggu sampai projectnya siap digunakan. 2. Buka build.gradle (Module: app) dan modifikasi code pada bagian dependecies menjadi seperti dibawah ini : dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.android.support:support-v4:22.0.+' }
setelah selesai silakan Sync Gradle. Kita menggunakan compability lib support v4 karna SwipeRefreshLayout berada di library tersebut. 3. Sekarang kita akan membuat custom Listview dengan langkah-langkah sebagai berikut : a. Buat file xml baru untuk tampilan loadmore dari ListView dengan cara : Klik kanan pada layout New Layout resource file dan beri nama loadmore_view.xml. Silakan lengkapi codenya seperti berikut :
b. Pada package utama silakan buat class Java baru untuk Custom ListView dengan cara klik kanan pada package utama New Java Class beri nama LoadMoreListView.java dan lengkapi code-nya sebagai berikut : package com.sidiq.codelab.customswiperefreshandloadmorelistview; import import import import import import import import import
android.content.Context; android.util.AttributeSet; android.util.Log; android.view.LayoutInflater; android.view.View; android.widget.AbsListView; android.widget.ListAdapter; android.widget.ListView; android.widget.RelativeLayout;
/** * Created by Sidiq on 04/08/2015. */ public class LoadMoreListView extends ListView implements AbsListView.OnScrollListener { private static final String TAG = LoadMoreListView.class .getSimpleName(); private OnScrollListener mOnScrollListener; private LayoutInflater mInflater; private View mFooterView; private View mLoadMoreStatusView; private OnLoadMoreListener
mOnLoadMoreListener;
private boolean mIsLoadingMore = false; private int mCurrentScrollState; public LoadMoreListView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public LoadMoreListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } @Override public void setAdapter(ListAdapter adapter) { mFooterView = (RelativeLayout) mInflater.inflate(R.layout.loadmore_view, this, false); mLoadMoreStatusView = mFooterView.findViewById(R.id.load_more_progress_bar); addFooterView(mFooterView);
setLoading(false); super.setAdapter(adapter); } private void init(Context context) { mInflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); super.setOnScrollListener(this); } public void setLoadMoreStatusView(View v, int statusViewId) { removeFooterView(mFooterView); mFooterView = v; mLoadMoreStatusView = mFooterView.findViewById(statusViewId); addFooterView(mFooterView); } public void setLoadMoreStatusView(View v) { removeFooterView(mFooterView); mFooterView = v; mLoadMoreStatusView = mFooterView.findViewById(R.id.load_more_progress_bar); addFooterView(mFooterView); } /** * Set the listener that will receive notifications every time the list * scrolls. * * @param l * The scroll listener. */ @Override public void setOnScrollListener(AbsListView.OnScrollListener l) { mOnScrollListener = l; } /** * Register a callback to be invoked when this list reaches the end (last item * be visible) * * @param onLoadMoreListener * The callback to run. */ public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) { mOnLoadMoreListener = onLoadMoreListener; }
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (mOnScrollListener != null) { mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } if (visibleItemCount == totalItemCount) { if (mLoadMoreStatusView != null) { mLoadMoreStatusView.setVisibility(View.GONE); } return; } if (mOnLoadMoreListener != null) { boolean loadMore = firstVisibleItem + visibleItemCount >= totalItemCount; if (!mIsLoadingMore && loadMore && mCurrentScrollState != SCROLL_STATE_IDLE) { setLoading(true); onLoadMore(); } } } public void onScrollStateChanged(AbsListView view, int scrollState) { mCurrentScrollState = scrollState; if (mOnScrollListener != null) { mOnScrollListener.onScrollStateChanged(view, scrollState); } } public void setLoading(boolean loading) { Log.d(TAG, "setLoading: " + loading); mIsLoadingMore = loading; mLoadMoreStatusView.setVisibility(loading ? View.VISIBLE : View.GONE); } public void onLoadMore() { Log.d(TAG, "onLoadMore"); if (mOnLoadMoreListener != null) { mOnLoadMoreListener.onLoadMore(); } } public void onLoadMoreComplete() { setLoading(false); }
public interface OnLoadMoreListener { public void onLoadMore(); } }
pada code diatas kita memanipulasi beberapa fungsi dasar dari ListView untuk bisa melakukan action ketika posisi scroll sudah menyentuh bagian bawah layar. 4. Pada MainActivity.java silakan lengkapi codenya menjadi seperti berikut : package com.sidiq.codelab.customswiperefreshandloadmorelistview; import import import import import import import
android.os.AsyncTask; android.support.v4.widget.SwipeRefreshLayout; android.support.v7.app.AppCompatActivity; android.os.Bundle; android.view.Menu; android.view.MenuItem; android.widget.ArrayAdapter;
import java.util.LinkedList; public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener{ private private private private private private
LoadMoreListView lvItem; SwipeRefreshLayout swipeMain; LinkedList<String> list; ArrayAdapter<String> adapter; int MaxPage = 5; int currentPage = 0;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lvItem = (LoadMoreListView)findViewById(R.id.lv_item); swipeMain = (SwipeRefreshLayout)findViewById(R.id.swipe_main); list = new LinkedList<>(); populateDefaultData(); //listener untuk loadmore lvItem.setOnLoadMoreListener(new LoadMoreListView.OnLoadMoreListener() { @Override public void onLoadMore() { if (currentPage < MaxPage) { new FakeLoadmoreAsync().execute(); } else { lvItem.onLoadMoreComplete(); } } });
swipeMain.setOnRefreshListener(this); } private void populateDefaultData(){ String[] androidVersion = new String[]{ "Not Apple", "Not Blackberry", "Cupcake", "Donut", "Eclair", "Froyo", "Gingerbread", "Honeycomb", "Ice cream sandwich", "Jelly Bean", "Kitkat", "Lollipop", "M Preview", "N (Coming soon on 2016)" }; for (int i = 0; i < androidVersion.length; i++){ list.add(androidVersion[i]); } adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, android.R.id.text1, list); lvItem.setAdapter(adapter); } @Override public void onRefresh() { new FakePullRefreshAsync().execute(); } //Background proses palsu untuk melakukan proses delay dan append data di bagian bawah list private class FakeLoadmoreAsync extends AsyncTask
{ @Override protected Void doInBackground(Void... voids) { try{ Thread.sleep(4000); }catch (Exception e){} return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); populateLoadmoreData(); currentPage +=1; } } private void populateLoadmoreData() { String loadmoreText = "Added on loadmore"; for (int i = 0; i < 10; i++){ list.addLast(loadmoreText); } adapter.notifyDataSetChanged(); lvItem.onLoadMoreComplete();
lvItem.setSelection(list.size() - 11); } //Background proses palsu untuk melakukan proses delay dan append data di bagian atas list private class FakePullRefreshAsync extends AsyncTask{ @Override protected Void doInBackground(Void... voids) { try{ Thread.sleep(4000); }catch (Exception e){} return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); populatePullRefreshData(); } } private void populatePullRefreshData() { String swipePullRefreshText = "Added after swipe layout"; for (int i = 0; i < 5; i++){ list.addFirst(swipePullRefreshText); } swipeMain.setRefreshing(false); adapter.notifyDataSetChanged(); lvItem.setSelection(0); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
Cara kerja dari code diatas sebagai berikut : 1. Data default akan ditampilkan terlebih dahulu 2. Jika user scroll ke bawah dan ListView sudah mencapai bagian paling bawah dari batas layar maka fungsi load more akan dijalankan. Dan setelah data ditambahkan dibagian paling bawah dari list maka adapter akan direfresh dengan menggunakan perintah : notifyDataSetChanged() 3. Jika user menarik listview ketika ada di posisi paling atas maka fungsi Pull To Refresh akan dijalankan. Sama seperti dengan load more namun bedanya Pull To Refresh akan menambahkan data dibagian atas dari list dan kemudian adapter akan direfresh dengan menggunakan perintah : notifyDataSetChanged()
5. Silakan running project diatas pada device android atau emulator rekan-rekan 6. Code dapat didownload di : https://github.com/sidiqpermana/CustomSwipeRefreshAndLoadMoreListView