آموزش RecyclerView بی پایان + ProgressBar در برنامه نویسی اندروید
سلام دوستان امیدوارم حالتان خوب باشد در این سری از آموزش برنامه نویسی اندروید به آموزش RecyclerView بی پایان + ProgressBar در برنامه نویسی اندروید می پردازیم قبلتر آموزش RecyclerView بی پایان یا endless قرار داده بودیم ولی امروز کمی آن را تغییر دادیم تا بیشتر کاربردی شود. در ادامه می توانید پیش نمایشی از آن را مشاهده کنید با ما همراه باشید .
باید یکسری کتاب خانه را به پروژه اضافه کنید.
وارد فایل Build.gradle از نوع Module شده سپس در بخش dependencies خط های زیر را اضافه کنید.
1 2 3 4 5 | dependencies { compile 'com.android.support:appcompat-v7:25.1.0' compile 'com.android.support:recyclerview-v7:25.1.0' compile 'com.android.support:cardview-v7:25.1.0' } |
پروژه را sync کنید.
یک فایل در layout خود به نام item_recycler_view_row.xml ایجاد کرده و کدهای زیر را در آن قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" card_view:cardUseCompatPadding="true"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="?android:selectableItemBackground" android:padding="10dp"> <TextView android:id="@+id/txt_email" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@android:color/black" android:textSize="16sp" android:textStyle="bold" /> <TextView android:id="@+id/txt_phone" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/txt_email" android:textColor="@android:color/black" android:textSize="12sp" /> </RelativeLayout> </android.support.v7.widget.CardView> |
کد شکل ظاهری آیتم ها را تنظیم می کند (یعنی آیتم ها به این شکل خواهند بود).
خب باید یک فایل به نام item_loading.xml ایجاد کنیم و کدهای زیر را در آن قرار دهیم.
1 2 3 4 5 6 7 8 9 10 11 | <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <ProgressBar android:id="@+id/progressBar1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" /> </LinearLayout> |
در بالا یک layout قرار گرفته است که در آن یک progressbar قرار گرفته است در زیر آخرین cardview ما inflate می شود و داده های جدید لود می شوند.
در activity_main.xml که layout اصلی ما است کدهای زیر را قرار دهید.
1 2 3 4 5 6 7 8 9 | <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout> |
در بالا RecyclerView برای Render کردن آیتم ها استفاده می شود.
خب باید یک کلاس به نام Contact.java ایجاد کرده و کد های زیر را در آن قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package ir.programchi; public class Contact { private String email; private String phone; public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } } |
کد بالا به getter و setter معروف است.
یک Interface به نام OnLoadMoreListener ایجاد کرده و کدهای زیر را در آن قرار دهید.
1 2 3 4 | package ir.programchi; public interface OnLoadMoreListener { void onLoadMore(); } |
یک کلاس جاوا به نام ContactAdapter.java ایجاد کرده و کدهای زیر را در آن قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | package ir.programchi; import android.app.Activity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.TextView; import java.util.List; public class ContactAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private final int VIEW_TYPE_ITEM = 0; private final int VIEW_TYPE_LOADING = 1; private OnLoadMoreListener onLoadMoreListener; private boolean isLoading; private Activity activity; private List<Contact> contacts; private int visibleThreshold = 5; private int lastVisibleItem, totalItemCount; public ContactAdapter(RecyclerView recyclerView, List<Contact> contacts, Activity activity) { this.contacts = contacts; this.activity = activity; final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); totalItemCount = linearLayoutManager.getItemCount(); lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition(); if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) { if (onLoadMoreListener != null) { onLoadMoreListener.onLoadMore(); } isLoading = true; } } }); } public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) { this.onLoadMoreListener = mOnLoadMoreListener; } @Override public int getItemViewType(int position) { return contacts.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_ITEM) { View view = LayoutInflater.from(activity).inflate(R.layout.item_recycler_view_row, parent, false); return new UserViewHolder(view); } else if (viewType == VIEW_TYPE_LOADING) { View view = LayoutInflater.from(activity).inflate(R.layout.item_loading, parent, false); return new LoadingViewHolder(view); } return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder instanceof UserViewHolder) { Contact contact = contacts.get(position); UserViewHolder userViewHolder = (UserViewHolder) holder; userViewHolder.phone.setText(contact.getEmail()); userViewHolder.email.setText(contact.getPhone()); } else if (holder instanceof LoadingViewHolder) { LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder; loadingViewHolder.progressBar.setIndeterminate(true); } } @Override public int getItemCount() { return contacts == null ? 0 : contacts.size(); } public void setLoaded() { isLoading = false; } private class LoadingViewHolder extends RecyclerView.ViewHolder { public ProgressBar progressBar; public LoadingViewHolder(View view) { super(view); progressBar = (ProgressBar) view.findViewById(R.id.progressBar1); } } private class UserViewHolder extends RecyclerView.ViewHolder { public TextView phone; public TextView email; public UserViewHolder(View view) { super(view); phone = (TextView) view.findViewById(R.id.txt_phone); email = (TextView) view.findViewById(R.id.txt_email); } } } |
کد بالا بعد از گرفتن داده ها آنها را در RecyclerView قرار می دهد و load more را نمایش می دهد.
حالا وارد فایل MainActivity.java شده و کدهای زیر را قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | package ir.programchi; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.widget.Toast; import java.util.ArrayList; import java.util.List; import java.util.Random; public class MainActivity extends AppCompatActivity { private List<Contact> contacts; private ContactAdapter contactAdapter; private Random random; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); contacts = new ArrayList<>(); random = new Random(); for (int i = 0; i < 10; i++) { Contact contact = new Contact(); contact.setPhone(phoneNumberGenerating()); contact.setEmail("Programchi" + i + "@gmail.com"); contacts.add(contact); } RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this)); contactAdapter = new ContactAdapter(recyclerView, contacts, this); recyclerView.setAdapter(contactAdapter); contactAdapter.setOnLoadMoreListener(new OnLoadMoreListener() { @Override public void onLoadMore() { if (contacts.size() <= 20) { contacts.add(null); contactAdapter.notifyItemInserted(contacts.size() - 1); new Handler().postDelayed(new Runnable() { @Override public void run() { contacts.remove(contacts.size() - 1); contactAdapter.notifyItemRemoved(contacts.size()); int index = contacts.size(); int end = index + 10; for (int i = index; i < end; i++) { Contact contact = new Contact(); contact.setPhone(phoneNumberGenerating()); contact.setEmail("DevExchanges" + i + "@gmail.com"); contacts.add(contact); } contactAdapter.notifyDataSetChanged(); contactAdapter.setLoaded(); } }, 5000); } else { Toast.makeText(MainActivity.this, "Loading data completed", Toast.LENGTH_SHORT).show(); } } }); } private String phoneNumberGenerating() { int low = 100000000; int high = 999999999; int randomNumber = random.nextInt(high - low) + low; return "0" + randomNumber; } } |
در بالا یکسری داده sample ابتدا لود شده سپس بعد از اینکه scroll کنید یک ProgresBar نمایش داده می شود و دوباره یکسری داده sample لود می شود.
این آموزش هم به پایان رسید.
موفق و پیروز باشید.
سلام ممنون از آموزش خوبتون
بی زحمت میشه رویداد onclick رو توی adapter براش بنویسید
با تشکر
سلام مهندس خسته نباشید این آموزش بسیار عالی است ولی بنده فکر میکنم سرعت لود ردیف های جدید کم است و طول میکشد راهی ندارد سریعتر شود ؟
سلام و درود
مقدار 5000 رو کمتر کنید تا سرعت لود افزایش پیدا کند. (در بخش postdelay)
موفق باشید.
سلام ممنون از راهنمایی تون یک مشکل دارم که رویداد setOnClickListener برای هر ردیف مشکل دارد و برنامه فورکلوز میدهد و بسته میشود اگه لطف کنید این رویداد را اضافه کنید ممنون میشم با تشکر از شما .
سلام و درود
از آموزش زیر استفاده کنید.
https://programchi.ir/2017/08/03/%d8%a2%d9%85%d9%88%d8%b2%d8%b4-%d8%a7%db%8c%d8%ac%d8%a7%d8%af-%d8%b1%d9%88%db%8c%d8%af%d8%a7%d8%af-%da%a9%d9%84%db%8c%da%a9-%d8%af%d8%b1-recyclerview/
موفق و موید باشید.
سلام
من ی سوال داشتم ، اگه کمکم کنید خیلی ممنون میشم.
من برای این آموزش در بخش row یک checkbox قرار دادم ، تا بتونم آیتم های که نمایش داده شده را یکی یکی به دلخواه انتخاب کنم ، اما بعد انتخاب رندم هر کدوم ، 10 تا ایتم بعدی و 10 تا آیتم قبلی آن هم انتخاب میشه ، یعنی اگر 40 آیتم داشته باشیم ، با انتخاب هر کدوم ، 3 تای دیگه هم فعال می شه ، چکار کنم این اتفاق نیافته؟
ممنون میشم ، من هر لحظه سر می زنم و منتظر پاسخ شما هستم.
با احترام
سلام
رویداد مربوط به checkbox را در چه بخشی تعریف کردید ؟
سلام و درود بی پایان
item_recycler_view_row.xml
در لایوت بالا تعریف کرده ام
سلام ممنون از آموزش خوبتون
من طبق آموزش پیش رفتم و یک فرگمنت ساختم و از Endless RecyclerView توش استفاده کردم جواب گرفتم همه چی درست بود ، اما جای دیگه که تب ساختم توی فرگمنت های تب لایوت وقتی استفاده کردم جای اینکه یک Progressbar نشون داده بشه گاهی 2 تا نشون داده میشه !!
اسکرین شات برنامه : https://drive.google.com/file/d/1rQXqgVRMl-xEjilbdq40TAEHpyDt16H4/view
سلام و درود
به احتمال زیاد شما به ازای هر بخش یک progressbar در نظر گرفتید که اشتباه است باید یک progressbar داشته باشید.
موفق باشید.
سلام دوباره
من یک فرگمنت دارم که در تب لایوت گفتم به تعداد تب هام از این فرگمنت ساخته بشه و داده ها رو از اکتیویتی به هر فرگمنت پاس دادم و تو ریسایکلر نشون میدم ، حالا طبق آموزش من فقط یک progressbar تعریف کردم ولی همونطور که تو اسکرین شاتم نشون دادم ولی چندین بار نشون میده و گاهی داده های بعدی که نشون داده میشن تو ریسایکلر پراگرس بار محو نمیشه و میمونه. ممنون میشم راهنماییم کنید.
سلام. خیلی ممنونم بابت آموزش خوبتون.
من میخوام از این آموزش EndLessRecyclerView داخل رتروفیت استفاده کنم و داده های جدید رو از سمت سرور بگیرم. من آداپتور ریسایکلرویو رو مثل شما پیاده سازی کردم. فقط مشکلم در متود زیر هست و نمیدونم چه تغییراتی باید بدم تا بتونم با رتروفیت ازش استفاده کنم.contactAdapter.setOnLoadMoreListener
منون میشم راهنمایی کنید.
سلام
ممنون بایت آموزشتون .
اگه ی لیست بلند 400 آیتم داشته باشیم چطور میشه مثلا 20 تا 20 لودش کنم؟
هر بار که پروگرس میاد 20 30 تا از لیست رو ادد کنه.
ن اینکه اطلاعات جدید لود شه.
ممنون میشم اگه راهنمایی کنید.
سلام و درود
ممنون بابت آموزش تون
اگه یک لیست بلند 400 آیتمی داشته باشیم چطور میشه که هر بار که پروگرس میاد 20 30 تا از لیستم رو لود کنه ؟
ممنون میشم راهنمایی کنید.