Я несколько раз составлял список элементов с помощью Android RecyclerView
, но это довольно сложный процесс. Я просматриваю одно из многочисленных онлайн-руководств ( это , это и это хорошо), но я ищу простой пример, который я могу скопировать и вставить, чтобы быстро приступить к работе. Необходимы только следующие функции:
- Вертикальная планировка
- Один TextView в каждой строке
- Реагирует на события щелчка
Поскольку я хотел этого несколько раз, я, наконец, решил дать ответ ниже для моей и вашей будущей ссылки.
android
android-recyclerview
Suragch
источник
источник
Ответы:
Ниже приведен минимальный пример, который будет выглядеть как на следующем изображении.
Начните с пустого занятия. Вы выполните следующие задачи, чтобы добавить RecyclerView. Все, что вам нужно сделать, это скопировать и вставить код в каждый раздел. Позже вы сможете настроить его под свои нужды.
Обновить зависимости Gradle
Убедитесь, что в вашем
gradle.build
файле приложения есть следующие зависимости :implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support:recyclerview-v7:28.0.0'
Вы можете обновить номера версий до самых последних . Используйте,
compile
а не,implementation
если вы все еще используете Android Studio 2.x.Создать макет занятия
Добавьте в
RecyclerView
свой xml-макет.activity_main.xml
<?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/rvAnimals" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout>
Создать макет строки
У каждой строки в нашем
RecyclerView
будет только одинTextView
. Создайте новый файл ресурсов макета.recyclerview_row.xml
<?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="horizontal" android:padding="10dp"> <TextView android:id="@+id/tvAnimalName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp"/> </LinearLayout>
Создайте адаптер
RecyclerView
Нужен адаптер для заполнения представлений в каждой строке с данными. Создайте новый файл java.MyRecyclerViewAdapter.java
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> { private List<String> mData; private LayoutInflater mInflater; private ItemClickListener mClickListener; // data is passed into the constructor MyRecyclerViewAdapter(Context context, List<String> data) { this.mInflater = LayoutInflater.from(context); this.mData = data; } // inflates the row layout from xml when needed @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = mInflater.inflate(R.layout.recyclerview_row, parent, false); return new ViewHolder(view); } // binds the data to the TextView in each row @Override public void onBindViewHolder(ViewHolder holder, int position) { String animal = mData.get(position); holder.myTextView.setText(animal); } // total number of rows @Override public int getItemCount() { return mData.size(); } // stores and recycles views as they are scrolled off screen public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { TextView myTextView; ViewHolder(View itemView) { super(itemView); myTextView = itemView.findViewById(R.id.tvAnimalName); itemView.setOnClickListener(this); } @Override public void onClick(View view) { if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition()); } } // convenience method for getting data at click position String getItem(int id) { return mData.get(id); } // allows clicks events to be caught void setClickListener(ItemClickListener itemClickListener) { this.mClickListener = itemClickListener; } // parent activity will implement this method to respond to click events public interface ItemClickListener { void onItemClick(View view, int position); } }
Примечания
ListViews
и является обычной потребностью. Вы можете удалить этот код, если он вам не нужен.Инициализировать RecyclerView в действии
Добавьте следующий код к своему основному действию.
MainActivity.java
public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener { MyRecyclerViewAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // data to populate the RecyclerView with ArrayList<String> animalNames = new ArrayList<>(); animalNames.add("Horse"); animalNames.add("Cow"); animalNames.add("Camel"); animalNames.add("Sheep"); animalNames.add("Goat"); // set up the RecyclerView RecyclerView recyclerView = findViewById(R.id.rvAnimals); recyclerView.setLayoutManager(new LinearLayoutManager(this)); adapter = new MyRecyclerViewAdapter(this, animalNames); adapter.setClickListener(this); recyclerView.setAdapter(adapter); } @Override public void onItemClick(View view, int position) { Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show(); } }
Примечания
ItemClickListener
что мы определили в нашем адаптере. Это позволяет нам обрабатывать события щелчка по строке вonItemClick
.Законченный
Вот и все. Теперь вы сможете запустить свой проект и получить что-то похожее на изображение вверху.
Продолжается
Добавление разделителя между строками
Вы можете добавить такой простой разделитель
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), layoutManager.getOrientation()); recyclerView.addItemDecoration(dividerItemDecoration);
Если вы хотите что-то посложнее, см. Следующие ответы:
Изменение цвета строки при нажатии
Посмотрите этот ответ, чтобы узнать, как изменить цвет фона и добавить эффект пульсации при щелчке строки.
Обновление строк
См. Этот ответ, чтобы узнать, как добавлять, удалять и обновлять строки.
дальнейшее чтение
источник
Минимальное представление Recycler, готовое к использованию шаблона Kotlin для:
Я знаю, что это старая ветка, и здесь есть ответы. Добавляем этот ответ для использования в будущем:
Добавьте вид корзины в свой макет
<android.support.v7.widget.RecyclerView android:id="@+id/wifiList" android:layout_width="match_parent" android:layout_height="match_parent" />
Создайте макет для отображения элементов списка (list_item.xml)
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:padding="5dp" android:layout_width="match_parent" android:orientation="vertical" android:layout_height="wrap_content"> <android.support.v7.widget.AppCompatTextView android:id="@+id/ssid" android:text="@string/app_name" android:layout_width="match_parent" android:textSize="17sp" android:layout_height="wrap_content" /> </LinearLayout> </android.support.v7.widget.CardView>
Теперь создайте минимальный адаптер для хранения данных, код здесь не требует пояснений.
class WifiAdapter(private val wifiList: ArrayList<ScanResult>) : RecyclerView.Adapter<WifiAdapter.ViewHolder>() { // holder class to hold reference inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { //get view reference var ssid: TextView = view.findViewById(R.id.ssid) as TextView } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { // create view holder to hold reference return ViewHolder( LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { //set values holder.ssid.text = wifiList[position].SSID } override fun getItemCount(): Int { return wifiList.size } // update your data fun updateData(scanResult: ArrayList<ScanResult>) { wifiList.clear() notifyDataSetChanged() wifiList.addAll(scanResult) notifyDataSetChanged() } }
Добавьте этот класс для обработки событий одиночного и длительного щелчка по элементам списка
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener { public interface ClickListener { void onClick(View view, int position); void onLongClick(View view, RecyclerView recyclerView, int position); } private GestureDetector gestureDetector; private ClickListener clickListener; public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) { this.clickListener = clickListener; gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { return true; } @Override public void onLongPress(MotionEvent e) { View child = recyclerView.findChildViewUnder(e.getX(), e.getY()); if (child != null && clickListener != null) { clickListener.onLongClick(child,recyclerView, recyclerView.getChildPosition(child)); } } }); } @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { View child = rv.findChildViewUnder(e.getX(), e.getY()); if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) { clickListener.onClick(child, rv.getChildPosition(child)); } return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { }
Наконец, установите свой адаптер в режим Recycler View и добавьте Touch Listener, чтобы начать перехват события касания для одиночного или двойного нажатия на элементы списка.
wifiAdapter = WifiAdapter(ArrayList()) wifiList.apply { // vertical layout layoutManager = LinearLayoutManager(applicationContext) // set adapter adapter = wifiAdapter // Touch handling wifiList.addOnItemTouchListener(RecyclerTouchListener(applicationContext, wifiList, object : RecyclerTouchListener.ClickListener { override fun onClick(view: View?, position: Int) { Toast.makeText(applicationContext, "RV OnCLickj " + position, Toast.LENGTH_SHORT).show() } override fun onLongClick(view: View, recyclerView: RecyclerView, position: Int) { Toast.makeText(applicationContext, "RV OnLongCLickj " + position, Toast.LENGTH_SHORT).show() } } )) }
Бонус; Обновить данные
wifiAdapter.updateData(mScanResults as ArrayList<ScanResult>)
Результат:
источник
Это будет самый простой вариант реализации RecyclerView.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.recyclerview.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/recycler_view"/> </FrameLayout>
list_item_view.xml
<?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="46dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textview" android:text="TextView" android:textSize="16dp" /> </LinearLayout>
CustomAdapter.java
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> { private List<String> data; public CustomAdapter (List<String> data){ this.data = data; } @Override public CustomAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View rowItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_view, parent, false); return new ViewHolder(rowItem); } @Override public void onBindViewHolder(CustomAdapter.ViewHolder holder, int position) { holder.textView.setText(this.data.get(position)); } @Override public int getItemCount() { return this.data.size(); } public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { private TextView textView; public ViewHolder(View view) { super(view); view.setOnClickListener(this); this.textView = view.findViewById(R.id.textview); } @Override public void onClick(View view) { Toast.makeText(view.getContext(), "position : " + getLayoutPosition() + " text : " + this.textView.getText(), Toast.LENGTH_SHORT).show(); } } }
MainActivity.java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(new CustomAdapter(generateData())); recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)); } private List<String> generateData() { List<String> data = new ArrayList<>(); for (int i = 0; i < 100; i++) { data.add(String.valueOf(i) + "th Element"); } return data; } }
источник
Начните с добавления библиотеки recyclerview.
implementation 'androidx.recyclerview:recyclerview:1.1.0'
Создайте класс модели.
public class UserModel implements Serializable { private String userName; public UserModel(String userName) { this.userName = userName; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
создать класс адаптера.
public class UsersAdapter extends RecyclerView.Adapter<UsersAdapter.UsersAdapterVh> implements Filterable { private List<UserModel> userModelList; private List<UserModel> getUserModelListFiltered; private Context context; private SelectedUser selectedUser; public UsersAdapter(List<UserModel> userModelList,SelectedUser selectedUser) { this.userModelList = userModelList; this.getUserModelListFiltered = userModelList; this.selectedUser = selectedUser; } @NonNull @Override public UsersAdapter.UsersAdapterVh onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { context = parent.getContext(); return new UsersAdapterVh(LayoutInflater.from(context).inflate(R.layout.row_users,null)); } @Override public void onBindViewHolder(@NonNull UsersAdapter.UsersAdapterVh holder, int position) { UserModel userModel = userModelList.get(position); String username = userModel.getUserName(); String prefix = userModel.getUserName().substring(0,1); holder.tvUsername.setText(username); holder.tvPrefix.setText(prefix); } @Override public int getItemCount() { return userModelList.size(); } @Override public Filter getFilter() { Filter filter = new Filter() { @Override protected FilterResults performFiltering(CharSequence charSequence) { FilterResults filterResults = new FilterResults(); if(charSequence == null | charSequence.length() == 0){ filterResults.count = getUserModelListFiltered.size(); filterResults.values = getUserModelListFiltered; }else{ String searchChr = charSequence.toString().toLowerCase(); List<UserModel> resultData = new ArrayList<>(); for(UserModel userModel: getUserModelListFiltered){ if(userModel.getUserName().toLowerCase().contains(searchChr)){ resultData.add(userModel); } } filterResults.count = resultData.size(); filterResults.values = resultData; } return filterResults; } @Override protected void publishResults(CharSequence charSequence, FilterResults filterResults) { userModelList = (List<UserModel>) filterResults.values; notifyDataSetChanged(); } }; return filter; } public interface SelectedUser{ void selectedUser(UserModel userModel); } public class UsersAdapterVh extends RecyclerView.ViewHolder { TextView tvPrefix; TextView tvUsername; ImageView imIcon; public UsersAdapterVh(@NonNull View itemView) { super(itemView); tvPrefix = itemView.findViewById(R.id.prefix); tvUsername = itemView.findViewById(R.id.username); imIcon = itemView.findViewById(R.id.imageView); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { selectedUser.selectedUser(userModelList.get(getAdapterPosition())); } }); } } }
создать макет row_uses.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:padding="10dp" android:layout_height="wrap_content"> <RelativeLayout android:layout_width="50dp" android:background="@drawable/users_bg" android:layout_height="50dp"> <TextView android:id="@+id/prefix" android:layout_width="wrap_content" android:textSize="16sp" android:textColor="@color/headerColor" android:text="T" android:layout_centerInParent="true" android:layout_height="wrap_content"/> </RelativeLayout> <TextView android:id="@+id/username" android:layout_width="wrap_content" android:textSize="16sp" android:textColor="@color/headerColor" android:text="username" android:layout_marginStart="90dp" android:layout_centerVertical="true" android:layout_height="wrap_content"/> <ImageView android:layout_width="wrap_content" android:id="@+id/imageView" android:layout_margin="10dp" android:layout_alignParentEnd="true" android:src="@drawable/ic_navigate_next_black_24dp" android:layout_height="wrap_content"/> </RelativeLayout> </LinearLayout>
Найдите recyclerview и заполните данные.
Toolbar toolbar; RecyclerView recyclerView; List<UserModel> userModelList = new ArrayList<>(); String[] names = {"Richard","Alice","Hannah","David"}; UsersAdapter usersAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = findViewById(R.id.recyclerview); toolbar = findViewById(R.id.toolbar); this.setSupportActionBar(toolbar); this.getSupportActionBar().setTitle(""); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL)); for(String s:names){ UserModel userModel = new UserModel(s); userModelList.add(userModel); } usersAdapter = new UsersAdapter(userModelList,this); recyclerView.setAdapter(usersAdapter); }
найти полное руководство и исходный код здесь:
Android RecyclerView
источник
usersAdapter = new UsersAdapter(userModelList,this);
?На основе разных источников я создал простую реализацию RecyclerView с использованием простой библиотеки.
Добавьте эту строку в
build.gradle
implementation 'com.hereshem.lib:awesomelib:2.0.1'
Добавить Создайте RecyclerView, добавив MyRecyclerView в activity_main.xml с помощью
<com.hereshem.lib.recycler.MyRecyclerView android:id="@+id/recycler" app:layoutManager="LinearLayoutManager" android:layout_width="match_parent" android:layout_height="match_parent"/>
Теперь в MainActivity создайте ViewHolder, передав имя класса, который необходимо привязать
public static class EVHolder extends MyViewHolder<Events> { TextView date, title, summary; public EVHolder(View v) { super(v); date = v.findViewById(R.id.date); title = v.findViewById(R.id.title); summary = v.findViewById(R.id.summary); } @Override public void bindView(Events c) { date.setText(c.date); title.setText(c.title); summary.setText(c.summary); } }
Создайте переменную списка элементов и адаптеры с очень небольшим количеством строк, передав элементы, класс и макет в адаптер
List<Events> items = new ArrayList<>(); MyRecyclerView recycler = findViewById(R.id.recycler); RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, items, EVHolder.class, R.layout.row_event); recycler.setAdapter(adapter);
ClickListener можно добавить следующими строками
recycler.setOnItemClickListener(new MyRecyclerView.OnItemClickListener() { @Override public void onItemClick(int position) { Toast.makeText(MainActivity.this, "Recycler Item Clicked " + position, Toast.LENGTH_SHORT).show(); } });
Все сделано.
Больше примеров и реализации можно найти здесь . Надеюсь это поможет !!!
источник
Теперь вам нужен 1 адаптер на все
RecyclerView
onBindViewHolder
, никакойonCreateViewHolder
обработки.Я показываю здесь установку двух разных
RecyclerView
по 1 адаптеру -activity_home.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="listOne" type="java.util.List"/> <variable name="listTwo" type="java.util.List"/> <variable name="onItemClickListenerOne" type="com.ks.nestedrecyclerbindingexample.callbacks.OnItemClickListener"/> <variable name="onItemClickListenerTwo" type="com.ks.nestedrecyclerbindingexample.callbacks.OnItemClickListener"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.RecyclerView rvItemLayout="@{@layout/row_one}" rvList="@{listOne}" rvOnItemClick="@{onItemClickListenerOne}" android:layout_width="match_parent" android:layout_height="wrap_content" app:layoutManager="android.support.v7.widget.LinearLayoutManager" /> <android.support.v7.widget.RecyclerView rvItemLayout="@{@layout/row_two}" rvList="@{listTwo}" rvOnItemClick="@{onItemClickListenerTwo}" android:layout_width="match_parent" android:layout_height="wrap_content" app:layoutManager="android.support.v7.widget.LinearLayoutManager" /> </LinearLayout> </layout>
Вы можете увидеть список передач, идентификатор макета элемента и прослушиватель щелчков из макета.
rvItemLayout="@{@layout/row_one}" rvList="@{listOne}" rvOnItemClick="@{onItemClickListenerOne}"
Эти настраиваемые атрибуты создаются BindingAdapter .
public class BindingAdapters { @BindingAdapter(value = {"rvItemLayout", "rvList", "rvOnItemClick"}, requireAll = false) public static void setRvAdapter(RecyclerView recyclerView, int rvItemLayout, List rvList, @Nullable OnItemClickListener onItemClickListener) { if (rvItemLayout != 0 && rvList != null && rvList.size() > 0) recyclerView.setAdapter(new GeneralAdapter(rvItemLayout, rvList, onItemClickListener)); } }
Теперь из Activity вы передаете список, нажимаете слушателя, например
HomeActivity.java
public class HomeActivity extends AppCompatActivity { ActivityHomeBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_home); binding.setListOne(new ArrayList()); // pass your list or set list from response of API binding.setListTwo(new ArrayList()); binding.setOnItemClickListenerOne(new OnItemClickListener() { @Override public void onItemClick(View view, Object object) { if (object instanceof ModelParent) { // TODO: your action here } } }); binding.setOnItemClickListenerTwo(new OnItemClickListener() { @Override public void onItemClick(View view, Object object) { if (object instanceof ModelChild) { // TODO: your action here } } }); } }
Вы не хотите слишком много читать, напрямую клонируйте / загружайте полный пример из моего репозитория github. И попробуйте сами.
Вы можете увидеть
GeneralAdapter.java
в репо выше.Если у вас возникли проблемы при настройке привязки данных, см. Этот ответ .
источник
Поскольку я пока не могу комментировать, я опубликую ссылку в качестве ответа. Я нашел простой, хорошо организованный учебник по recyclerview http://www.androiddeft.com/2017/10/01/recyclerview-android/
Кроме того, когда вы собираетесь добавить представление ресайклера в свою деятельность, вы хотите сделать, как показано ниже, и как вы должны это делать, было описано по ссылке
источник
Вы можете использовать абстрактный адаптер с утилитами diff и фильтром
SimpleAbstractAdapter.kt
abstract class SimpleAbstractAdapter<T>(private var items: ArrayList<T> = arrayListOf()) : RecyclerView.Adapter<SimpleAbstractAdapter.VH>() { protected var listener: OnViewHolderListener<T>? = null private val filter = ArrayFilter() private val lock = Any() protected abstract fun getLayout(): Int protected abstract fun bindView(item: T, viewHolder: VH) protected abstract fun getDiffCallback(): DiffCallback<T>? private var onFilterObjectCallback: OnFilterObjectCallback? = null private var constraint: CharSequence? = "" override fun onBindViewHolder(vh: VH, position: Int) { getItem(position)?.let { bindView(it, vh) } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH { return VH(parent, getLayout()) } override fun getItemCount(): Int = items.size protected abstract class DiffCallback<T> : DiffUtil.Callback() { private val mOldItems = ArrayList<T>() private val mNewItems = ArrayList<T>() fun setItems(oldItems: List<T>, newItems: List<T>) { mOldItems.clear() mOldItems.addAll(oldItems) mNewItems.clear() mNewItems.addAll(newItems) } override fun getOldListSize(): Int { return mOldItems.size } override fun getNewListSize(): Int { return mNewItems.size } override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return areItemsTheSame( mOldItems[oldItemPosition], mNewItems[newItemPosition] ) } abstract fun areItemsTheSame(oldItem: T, newItem: T): Boolean override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return areContentsTheSame( mOldItems[oldItemPosition], mNewItems[newItemPosition] ) } abstract fun areContentsTheSame(oldItem: T, newItem: T): Boolean } class VH(parent: ViewGroup, @LayoutRes layout: Int) : RecyclerView.ViewHolder(LayoutInflater.from(parent.context).inflate(layout, parent, false)) interface OnViewHolderListener<T> { fun onItemClick(position: Int, item: T) } fun getItem(position: Int): T? { return items.getOrNull(position) } fun getItems(): ArrayList<T> { return items } fun setViewHolderListener(listener: OnViewHolderListener<T>) { this.listener = listener } fun addAll(list: List<T>) { val diffCallback = getDiffCallback() when { diffCallback != null && !items.isEmpty() -> { diffCallback.setItems(items, list) val diffResult = DiffUtil.calculateDiff(diffCallback) items.clear() items.addAll(list) diffResult.dispatchUpdatesTo(this) } diffCallback == null && !items.isEmpty() -> { items.clear() items.addAll(list) notifyDataSetChanged() } else -> { items.addAll(list) notifyDataSetChanged() } } } fun add(item: T) { items.add(item) notifyDataSetChanged() } fun add(position:Int, item: T) { items.add(position,item) notifyItemInserted(position) } fun remove(position: Int) { items.removeAt(position) notifyItemRemoved(position) } fun remove(item: T) { items.remove(item) notifyDataSetChanged() } fun clear(notify: Boolean=false) { items.clear() if (notify) { notifyDataSetChanged() } } fun setFilter(filter: SimpleAdapterFilter<T>): ArrayFilter { return this.filter.setFilter(filter) } interface SimpleAdapterFilter<T> { fun onFilterItem(contains: CharSequence, item: T): Boolean } fun convertResultToString(resultValue: Any): CharSequence { return filter.convertResultToString(resultValue) } fun filter(constraint: CharSequence) { this.constraint = constraint filter.filter(constraint) } fun filter(constraint: CharSequence, listener: Filter.FilterListener) { this.constraint = constraint filter.filter(constraint, listener) } fun getFilter(): Filter { return filter } interface OnFilterObjectCallback { fun handle(countFilterObject: Int) } fun setOnFilterObjectCallback(objectCallback: OnFilterObjectCallback) { onFilterObjectCallback = objectCallback } inner class ArrayFilter : Filter() { private var original: ArrayList<T> = arrayListOf() private var filter: SimpleAdapterFilter<T> = DefaultFilter() private var list: ArrayList<T> = arrayListOf() private var values: ArrayList<T> = arrayListOf() fun setFilter(filter: SimpleAdapterFilter<T>): ArrayFilter { original = items this.filter = filter return this } override fun performFiltering(constraint: CharSequence?): Filter.FilterResults { val results = Filter.FilterResults() if (constraint == null || constraint.isBlank()) { synchronized(lock) { list = original } results.values = list results.count = list.size } else { synchronized(lock) { values = original } val result = ArrayList<T>() for (value in values) { if (constraint!=null && constraint.trim().isNotEmpty() && value != null) { if (filter.onFilterItem(constraint, value)) { result.add(value) } } else { value?.let { result.add(it) } } } results.values = result results.count = result.size } return results } override fun publishResults(constraint: CharSequence, results: Filter.FilterResults) { items = results.values as? ArrayList<T> ?: arrayListOf() notifyDataSetChanged() onFilterObjectCallback?.handle(results.count) } } class DefaultFilter<T> : SimpleAdapterFilter<T> { override fun onFilterItem(contains: CharSequence, item: T): Boolean { val valueText = item.toString().toLowerCase() if (valueText.startsWith(contains.toString())) { return true } else { val words = valueText.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() for (word in words) { if (word.contains(contains)) { return true } } } return false } } }
И расширить абстрактный адаптер с помощью методов реализации
ЗадачиAdapter.kt
import android.annotation.SuppressLint import kotlinx.android.synthetic.main.task_item_layout.view.* class TasksAdapter(private val listener:TasksListener? = null) : SimpleAbstractAdapter<Task>() { override fun getLayout(): Int { return R.layout.task_item_layout } override fun getDiffCallback(): DiffCallback<Task>? { return object : DiffCallback<Task>() { override fun areItemsTheSame(oldItem: Task, newItem: Task): Boolean { return oldItem.id == newItem.id } override fun areContentsTheSame(oldItem: Task, newItem: Task): Boolean { return oldItem.items == newItem.items } } } @SuppressLint("SetTextI18n") override fun bindView(item: Task, viewHolder: VH) { viewHolder.itemView.apply { val position = viewHolder.adapterPosition val customer = item.customer val customerName = if (customer != null) customer.name else "" tvTaskCommentTitle.text = customerName + ", #" + item.id tvCommentContent.text = item.taskAddress ivCall.setOnClickListener { listener?.onCallClick(position, item) } setOnClickListener { listener?.onItemClick(position, item) } } } interface TasksListener : SimpleAbstractAdapter.OnViewHolderListener<Task> { fun onCallClick(position: Int, item: Task) } }
Адаптер инициализации
mAdapter = TasksAdapter(object : TasksAdapter.TasksListener { override fun onCallClick(position: Int, item:Task) { } override fun onItemClick(position: Int, item:Task) { } }) rvTasks.adapter = mAdapter
и заполнить
mAdapter?.addAll(tasks)
добавить собственный фильтр
mAdapter?.setFilter(object : SimpleAbstractAdapter.SimpleAdapterFilter<MoveTask> { override fun onFilterItem(contains: CharSequence, item:Task): Boolean { return contains.toString().toLowerCase().contains(item.id?.toLowerCase().toString()) } })
фильтровать данные
mAdapter?.filter("test")
источник
Вот гораздо более новое решение Kotlin для этого, которое намного проще, чем многие из написанных здесь ответов, оно использует анонимный класс.
val items = mutableListOf<String>() inner class ItemHolder(view: View): RecyclerView.ViewHolder(view) { var textField: TextView = view.findViewById(android.R.id.text1) as TextView } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { rvitems.layoutManager = LinearLayoutManager(context) rvitems.adapter = object : RecyclerView.Adapter<ItemHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemHolder { return ItemHolder(LayoutInflater.from(parent.context).inflate(android.R.layout.simple_list_item_1, parent, false)) } override fun getItemCount(): Int { return items.size } override fun onBindViewHolder(holder: ItemHolder, position: Int) { holder.textField.text = items[position] holder.textField.setOnClickListener { Toast.makeText(context, "Clicked $position", Toast.LENGTH_SHORT).show() } } } }
Я взял на себя смелость использовать android.R.layout.simple_list_item_1, так как это проще. Я хотел еще больше упростить его и поместить ItemHolder в качестве внутреннего класса, но не мог понять, как ссылаться на него в типе во внешнем параметре класса.
источник
реализация androidx.recyclerview: recyclerview: .... Рекомендуется обновить библиотеки androidx, которые находятся здесь:
https://developer.android.com/jetpack/androidx/releases/recyclerview
Затем необходимо обновить XML-тег Widget файла макета до: androidx.recyclerview.widget.RecyclerView
источник
Зависимости
compile 'com.android.support:appcompat-v7:25.3.1' compile 'com.android.support:design:25.3.1' compile 'com.android.support:multidex:1.0.1' compile 'com.android.support:cardview-v7:25.3.1' compile 'com.android.support:support-v4:25.3.1' compile 'com.lguipeng.bubbleview:library:1.0.0' compile 'com.larswerkman:HoloColorPicker:1.5' compile 'com.mcxiaoke.volley:library-aar:1.0.0'
Один класс для элемента Click
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { private OnItemClickListener mListener; public interface OnItemClickListener { public void onItemClick(View view, int position); } GestureDetector mGestureDetector; public RecyclerItemClickListener(Context context, OnItemClickListener listener) { mListener = listener; mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { return true; } }); } @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { View childView = view.findChildViewUnder(e.getX(), e.getY()); if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) { mListener.onItemClick(childView, view.getChildPosition(childView)); return true; } return false; } @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } }
Второй класс RecyclerView
import android.annotation.SuppressLint; import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.support.v4.content.LocalBroadcastManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import com.android.volley.DefaultRetryPolicy; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.Volley; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; public class SLByTopics extends Fragment { public static ArrayList<MByTopics> byTopicsMainArrayList=new ArrayList<>(); TabRefreshReceiver tabRefreshReceiver; RecyclerView recyclerView; SAdpByTopics sAdpByTopics; public ArrayList<MByTopics> mByTopicsArrayList=new ArrayList<>(); ProgressDialog progressDialog; public SLByTopics(){ } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.sl_fragment_by_topics, container, false); progressDialog = new ProgressDialog(getActivity()); if (IsOnline.isNetworkAvailable(getActivity())) { getCategoryTree(); } else{ IsOnline.showNoInterNetMessage(getActivity()); } tabRefreshReceiver = new TabRefreshReceiver(); LocalBroadcastManager.getInstance(getContext()).registerReceiver(tabRefreshReceiver, new IntentFilter("BY_TOPICS")); setUpView(view); return view; } private void setUpView(View view) { recyclerView=(RecyclerView)view.findViewById(R.id.by_topics_list_recyclerView); LinearLayoutManager linearLayoutManager=new LinearLayoutManager(getActivity()); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); recyclerView.setLayoutManager(linearLayoutManager); } @Override public void onResume() { super.onResume(); recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() { @Override public void onItemClick(View view, final int position) { if (mByTopicsArrayList.get(position).getChild().size()>0){ Intent intent = new Intent(getActivity(), SByTopicCategory.class); intent.putExtra("selectedCategoryName",mByTopicsArrayList.get(position).getCatname()); intent.putExtra("jsonData",mByTopicsArrayList.get(position).getMainTopicJson()); startActivity(intent); getActivity().overridePendingTransition(R.anim.activity_in, R.anim.activity_out); }else { Intent intent = new Intent(getActivity(), SByCategoryQuestionList.class); intent.putExtra("selectedSubCategoryName",mByTopicsArrayList.get(position).getCatname()); intent.putExtra("catID",mByTopicsArrayList.get(position).getId()); startActivity(intent); getActivity().overridePendingTransition(R.anim.activity_in, R.anim.activity_out); } } })); } private class TabRefreshReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { try { FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.detach(SLByTopics.this).attach(SLByTopics.this).commit(); LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(tabRefreshReceiver); } catch (Exception e) { e.printStackTrace(); } } } private void getCategoryTree() { progressDialog.setMessage("Please Wait..."); progressDialog.setCancelable(false); progressDialog.show(); StringRequest stringRequest = new StringRequest(Request.Method.POST, Const.HOSTNAME + Const.STUDENT_GET_CATEGORY_TREE, new Response.Listener<String>() { @SuppressLint("LongLogTag") @Override public void onResponse(String response) { try { JSONObject object = new JSONObject(response); String status = object.getString("status"); int i = Integer.parseInt(status); switch (i) { case 0: progressDialog.dismiss(); // Toast.makeText(getActivity(), "getCategorySuccess", Toast.LENGTH_SHORT).show(); Log.e("getCategoryTree Response", "getCategoryTree Response : " + response); try { byTopicsMainArrayList.clear(); JSONArray info = object.getJSONArray("info"); if (info.length() > 0) { for (i = 0; i < info.length(); i++) { JSONObject data = info.getJSONObject(i); MByTopics mByTopics = new MByTopics(); mByTopics.setId(data.getString("id")); mByTopics.setCatname(data.getString("catname")); mByTopics.setMainTopicJson(data.toString()); JSONArray topicChildren = data.getJSONArray("children"); ArrayList<SMByTopicCategory> byChildrenArrayList = new ArrayList<>(); for (int j = 0; j < topicChildren.length(); j++) { JSONObject topicChildrenData = topicChildren.getJSONObject(j); SMByTopicCategory smByTopicCategory = new SMByTopicCategory(); smByTopicCategory.setId(topicChildrenData.getString("id")); smByTopicCategory.setCatname(topicChildrenData.getString("catname")); smByTopicCategory.setChildTopicJson(topicChildrenData.toString()); JSONArray topicChildrenQuestion = topicChildrenData.getJSONArray("children"); ArrayList<SMByTopicSubCategory> byChildrenSubArrayList = new ArrayList<>(); for (int k = 0; k < topicChildrenQuestion.length(); k++) { JSONObject topicChildrenSubData = topicChildrenQuestion.getJSONObject(k); SMByTopicSubCategory smByTopicSubCategory = new SMByTopicSubCategory(); smByTopicSubCategory.setId(topicChildrenSubData.getString("id")); smByTopicSubCategory.setCatname(topicChildrenSubData.getString("catname")); smByTopicSubCategory.setChildSubTopicJson(topicChildrenSubData.toString()); byChildrenSubArrayList.add(smByTopicSubCategory); } smByTopicCategory.setQuestions(byChildrenSubArrayList); byChildrenArrayList.add(smByTopicCategory); } mByTopics.setChild(byChildrenArrayList); byTopicsMainArrayList.add(mByTopics); } mByTopicsArrayList.clear(); mByTopicsArrayList=byTopicsMainArrayList; sAdpByTopics=new SAdpByTopics(mByTopicsArrayList,getActivity()); recyclerView.setAdapter(sAdpByTopics); sAdpByTopics.notifyDataSetChanged(); } }catch (Exception e){ e.printStackTrace(); } break; default: progressDialog.dismiss(); // Toast.makeText(getActivity(), "getCategoryError : " + response, Toast.LENGTH_SHORT).show(); Log.e("getCategoryTree Not Response", "getCategoryTree Uploading Not Response : " + response); } } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { progressDialog.dismiss(); Log.e("getCategoryTree Error :","getCategoryTree Error :"+error.getMessage()); // Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_LONG).show(); } }){ };/* { @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); // map.put("uid", String.valueOf(ConfigManager.getUserId())); return map; } };*/ stringRequest.setRetryPolicy(new DefaultRetryPolicy( 0, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)); RequestQueue requestQueue = Volley.newRequestQueue(getActivity()); requestQueue.add(stringRequest); } }
Класс адаптера для элемента вторичной переработки
import android.app.Activity; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.ArrayList; public class SAdpByTopics extends RecyclerView.Adapter<RecyclerView.ViewHolder> { ArrayList<MByTopics> topicsArrayList=new ArrayList<>(); Activity activity; public SAdpByTopics(ArrayList<MByTopics> topicsArrayList,Activity activity){ this.topicsArrayList=topicsArrayList; this.activity=activity; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemeView= LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_by_topic_list,parent,false); RecyclerView.ViewHolder holder=new Holder(itemeView); holder.setIsRecyclable(false); return holder; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { final Holder classHolder = (Holder) holder; try{ classHolder.txt_topic_name.setText(topicsArrayList.get(position).getCatname()); }catch (Exception e){ e.printStackTrace(); } } @Override public int getItemCount() { return topicsArrayList.size(); } class Holder extends RecyclerView.ViewHolder implements View.OnClickListener { TextView txt_topic_name; public Holder(View itemView) { super(itemView); txt_topic_name = (TextView) itemView.findViewById(R.id.txt_topic_name); } @Override public void onClick(View v) { } } }
Класс модуля
public class MByTopics { String id; String topicName; String catname; String MainTopicJson; ArrayList<SMByTopicCategory> child; ArrayList<SMByTopicSubCategory> questions; public void setId(String id){ this.id=id; } public String getId(){ return id; } public void setCatname(String catname) { this.catname = catname; } public String getCatname() { return catname; } public void setTopicName(String topicName) { this.topicName = topicName; } public String getTopicName() { return topicName; } public void setChild(ArrayList<SMByTopicCategory> child) { this.child = child; } public String getMainTopicJson() { return MainTopicJson; } public void setMainTopicJson(String mainTopicJson) { MainTopicJson = mainTopicJson; } public ArrayList<SMByTopicCategory> getChild() { return child; } public void setQuestions(ArrayList<SMByTopicSubCategory> questions) { this.questions = questions; } public ArrayList<SMByTopicSubCategory> getQuestions() { return questions; } public ArrayList<MByTopics> getByTopicList() { ArrayList<MByTopics> mByTopicsArrayList = new ArrayList<>(); for (int i=0;i<11;i++){ MByTopics mQuestionBankCategory=new MByTopics(); if (i==1 || i== 5|| i==9){ mQuestionBankCategory.setTopicName("Microeconomics"); }else if (i==2 || i== 10|| i==6) { mQuestionBankCategory.setTopicName("Macroeconomics"); }else { mQuestionBankCategory.setTopicName("Current Isssues"); } mByTopicsArrayList.add(mQuestionBankCategory); } return mByTopicsArrayList; } }
источник