Я несколько раз составлял список элементов с помощью Android RecyclerView, но это довольно сложный процесс. Просматривая один из многочисленных онлайн-уроков (this, thisи this хороши), но я ищу простой пример, который я могу скопировать и вставьте, чтобы быстро приступить к работе. Необходимы только следующие функции:

  • Вертикальная планировка
  • Один TextView в каждой строке
  • Реагирует на события кликов

Поскольку я хотел этого несколько раз, я, наконец, решил дать ответ ниже для моей и вашей будущей справки.

Suragch

Ответов: 12

Ответы (12)

Ниже приведен минимальный пример, который будет выглядеть, как на следующем изображении.

RecyclerView with a list of animal names

Начать с пустого занятия. Вы выполните следующие задачи, чтобы добавить RecyclerView. Все, что вам нужно сделать, это скопировать и вставить код в каждый раздел. Позже вы сможете настроить его под свои нужды.

  • Добавить зависимости в gradle
  • Добавьте файлы макета xml для действия и для строки RecyclerView
  • Сделайте адаптер RecyclerView
  • Инициализировать RecyclerView в своей деятельности

Обновить зависимости Gradle

Убедитесь, что в вашем приложении есть следующие зависимости gradle.build файл:

implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'

Вы можете обновить номера версий до самой последней. Используйте compile, а не реализацию, если вы все еще используете Android Studio 2.x.

Создать макет занятия

Добавьте RecyclerView в свой XML-макет.

activity_main.xml




    


Create row layout

Каждая строка в нашем RecyclerView будет иметь только один TextView. Создайте новый файл ресурсов макета.

recyclerview_row.xml




    


Создайте адаптер

Для RecyclerView требуется адаптер для заполнения представлений в каждой строке вашими данными. Создайте новый файл java.

MyRecyclerViewAdapter.java

public class MyRecyclerViewAdapter extends RecyclerView.Adapter {

    private List mData;
    private LayoutInflater mInflater;
    private ItemClickListener mClickListener;

    // data is passed into the constructor
    MyRecyclerViewAdapter(Context context, List 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 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);

Если вы хотите что-то посложнее, посмотрите следующие ответы:

Изменение цвета строки при нажатии

См. этот ответ, чтобы узнать, как изменить цвет фона и добавить эффект пульсации при щелчке по строке.

Insert single item

Обновление строк

См. этот ответ, чтобы узнать, как добавлять, удалять и обновлять строки.

Insert single item

Дополнительная литература

реализация androidx.recyclerview: recyclerview: .... Рекомендуется обновить библиотеки androidx, которые находятся здесь:

https://developer.android.com/jetpack/androidx/releases/recyclerview

XML-тег Widget файла макета затем должен быть обновлен до: androidx.recyclerview.widget.RecyclerView

Вот гораздо более новое решение Kotlin для этого, которое намного проще, чем многие из написанных здесь ответов, оно использует анонимный класс.

val items = mutableListOf()

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() {

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

I took the liberty to use android.R.layout.simple_list_item_1 as it's simpler. I wanted to simplify it even further and put ItemHolder as an inner class but couldn't quite figure out how to reference it in a type in the outer class parameter.

Android RecyclerView

Начните с добавления библиотеки 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 implements Filterable {

    private List userModelList;
    private List getUserModelListFiltered;
    private Context context;
    private SelectedUser selectedUser;

    public UsersAdapter(List 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 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) 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

    


    

        
            

        
        
        
    


Найдите recyclerview и заполните данные.

Toolbar toolbar;
RecyclerView recyclerView;

List 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

Вы можете использовать абстрактный адаптер с утилитами diff и фильтром

SimpleAbstractAdapter.kt

abstract class SimpleAbstractAdapter(private var items: ArrayList = arrayListOf()) : RecyclerView.Adapter() {
   protected var listener: OnViewHolderListener? = 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?
   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 : DiffUtil.Callback() {
    private val mOldItems = ArrayList()
    private val mNewItems = ArrayList()

    fun setItems(oldItems: List, newItems: List) {
        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 {
    fun onItemClick(position: Int, item: T)
}

fun getItem(position: Int): T? {
    return items.getOrNull(position)
}

fun getItems(): ArrayList {
    return items
}

fun setViewHolderListener(listener: OnViewHolderListener) {
    this.listener = listener
}

fun addAll(list: List) {
    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): ArrayFilter {
    return this.filter.setFilter(filter)
}

interface SimpleAdapterFilter {
    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 = arrayListOf()
    private var filter: SimpleAdapterFilter = DefaultFilter()
    private var list: ArrayList = arrayListOf()
    private var values: ArrayList = arrayListOf()


    fun setFilter(filter: SimpleAdapterFilter): 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()
            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 ?: arrayListOf()
        notifyDataSetChanged()
        onFilterObjectCallback?.handle(results.count)
    }

}

class DefaultFilter : SimpleAdapterFilter {
    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
    }
  }
}

И расширить абстрактный адаптер с помощью методов

TasksAdapter.kt

import android.annotation.SuppressLint
  import kotlinx.android.synthetic.main.task_item_layout.view.*

class TasksAdapter(private val listener:TasksListener? = null) : SimpleAbstractAdapter() {
override fun getLayout(): Int {
    return R.layout.task_item_layout
}

override fun getDiffCallback(): DiffCallback? {
    return object : DiffCallback() {
        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 {
    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 {
            override fun onFilterItem(contains: CharSequence, item:Task): Boolean {
                return contains.toString().toLowerCase().contains(item.id?.toLowerCase().toString())
            }
    })

данные фильтра

mAdapter?.filter("test")

Минимальное представление Recycler, готовое к использованию шаблона Kotlin для:

  • Вертикальная планировка
  • Один TextView в каждой строке
  • Реагирует на события щелчка (одиночное и долгое нажатие)

Я знаю, что это старая ветка, поэтому ответьте здесь. Добавляем этот ответ для использования в будущем:

Добавить представление корзины в зависимости сборки

  implementation 'com.google.android.material:material:1.4.0-alpha02'
    // RecyclerView
    implementation "androidx.recyclerview:recyclerview:1.2.0"

Добавить вид корзины в ваш макет

    

Создать макет для отображения элементов списка (list_item.xml)



    

        
        
    


Теперь создайте минимальный адаптер для хранения данных, код здесь не требует пояснений

 class WifiAdapter(private val wifiList: ArrayList) : RecyclerView.Adapter() {

     // 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) {
         wifiList.clear()
         notifyDataSetChanged()
         wifiList.addAll(scanResult)
         notifyDataSetChanged()

     }
 }

Добавьте этот класс для обработки событий одиночного и длительного щелчка по элементам списка

import android.content.Context;
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener
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)

Результат: enter image description here

Это будет простейшая версия реализации RecyclerView.

enter image description here

activity_main.xml




    


list_item_view.xml




    


CustomAdapter.java

открытый класс CustomAdapter расширяет RecyclerView.Adapter  {
  данные частного списка ;
  общедоступный CustomAdapter (список  данных) {
    this.data = data;
  }

  @Override
  общедоступный CustomAdapter.ViewHolder onCreateViewHolder (родительский элемент ViewGroup, int viewType) {
    Просмотр rowItem = LayoutInflater.from (parent.getContext ()). Inflate (R.layout.list_item_view, parent, false);
    вернуть новый ViewHolder (rowItem);
  }

  @Override
  public void onBindViewHolder (держатель CustomAdapter.ViewHolder, позиция int) {
    Holder.textView.setText (this.data.get (позиция));
  }

  @Override
  public int getItemCount () {
    вернуть this.data.size ();
  }

  общедоступный статический класс ViewHolder расширяет RecyclerView.ViewHolder реализует View.OnClickListener {
    частный TextView textView;

    public ViewHolder (Просмотр представления) {
      супер (просмотр);
      view.setOnClickListener (это);
      this.textView = view.findViewById (R.id.textview);
    }

    @Override
    public void onClick (Просмотр просмотра) {
      Toast.makeText (view.getContext (), «позиция:» + getLayoutPosition () + «текст:» + this.textView.getText (), Toast.LENGTH_SHORT) .show ();
    }
  }
}

MainActivity.java

открытый класс MainActivity расширяет AppCompatActivity {

  @Override
  protected void onCreate (Bundle savedInstanceState) {
    super.onCreate (savedInstanceState);
    setContentView (R.layout.activity_main);

    RecyclerView recyclerView = findViewById (R.id.recycler_view);
    
    recyclerView.setLayoutManager (новый LinearLayoutManager (это));
    recyclerView.setAdapter (новый CustomAdapter (generateData ()));
    recyclerView.addItemDecoration (новый DividerItemDecoration (это, DividerItemDecoration.VERTICAL));
  }

  частный список  generateData () {
    Список  data = new ArrayList <> ();
    for (int i = 0; i <100; i ++) {
      data.add (String.valueOf (i) + «th Element»);
    }
    вернуть данные;
  }

}

Теперь вам понадобится 1 адаптер на все RecyclerView

  • Один адаптер можно использовать для всех RecyclerView. Итак, NO onBindViewHolder, No onCreateViewHolder обработка.
  • Нет кода для настройки адаптера из класса Java / Kotlin. Отметьте класс образца.
  • Вы можете установить события и пользовательские данные для каждого списка с помощью адаптеров привязки.

screenshot

Я показываю здесь установку двух разных RecyclerView на 1 адаптер -

activity_home.xml




    

        

        

        

        

    

    

        

        

    


Вы можете видеть, что я передаю список, идентификатор макета элемента и прослушиватель щелчков из макета.

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/

Кроме того, когда вы собираетесь добавить представление ресайклера в свою деятельность, вам нужно сделать следующее, как показано ниже, и как вы должны это сделать, было описано по ссылке

  • добавить компонент RecyclerView в ваш файл макета
  • создайте класс, который вы собираетесь отображать в виде строк списка
  • создать файл макета, который является макетом строки вашего списка
  • Теперь нам нужен специальный адаптер, поэтому создайте собственный адаптер, расширив из родительского класса RecyclerView.Adapter
  • добавьте recyclerview в свой mainActivity oncreate
  • добавление разделителей
  • добавление слушателей Touch

Для начала просто просмотреть что-нибудь в представлении Recycler

адаптер просмотра ресайклера может быть примерно таким.

class CustomAdapter: RecyclerView.Adapter() {
    var data =  listOf()
        set(value) {
            field = value
            notifyDataSetChanged()
        }
    override fun getItemCount() =data.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.txt.text= data[position]
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_view, parent, false)
        )
    }


    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
        val txt: TextView = itemView.findViewById(R.id.item_text_view)
    }
}

и для присоединения адаптера к виду ресайклера и для присоединения данных к адаптеру

val view = findViewById(R.id.recycler_view)                                              
val adapter = CustomAdapter()                                                                          
val data = listOf("text1", "text2", "text3")
adapter.data = data                                                                             
view.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
view.adapter = adapter       
            

Зависимости

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 byTopicsMainArrayList=new ArrayList<>();


    TabRefreshReceiver tabRefreshReceiver;
    RecyclerView recyclerView;
    SAdpByTopics sAdpByTopics;
    public ArrayList 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() {
                    @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 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 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 getParams() throws AuthFailureError {

                Map map = new HashMap();
//                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 {
        ArrayList topicsArrayList=new ArrayList<>();
        Activity activity;

     public SAdpByTopics(ArrayList 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 child;
    ArrayList 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 child) {
        this.child = child;
    }

    public String getMainTopicJson() {
        return MainTopicJson;
    }

    public void setMainTopicJson(String mainTopicJson) {
        MainTopicJson = mainTopicJson;
    }

    public ArrayList getChild() {
        return child;
    }

    public void setQuestions(ArrayList questions) {
        this.questions = questions;
    }

    public ArrayList getQuestions() {
        return questions;
    }

    public ArrayList getByTopicList() {
        ArrayList 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;
    }

}

На основе разных источников я создал простую реализацию RecyclerView с использованием простой библиотеки.

Добавьте эту строку в build.gradle

implementation 'com.hereshem.lib:awesomelib:2.0.1'

Add Создайте RecyclerView, добавив MyRecyclerView в activity_main.xml с помощью


Теперь в MainActivity создайте ViewHolder, передав имя класса, который необходимо привязать

public static class EVHolder extends MyViewHolder {
    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 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();
    }
});

Готово.

Дополнительный пример и реализацию можно найти здесь. Надеюсь, это поможет !!!

2022 WebDevInsider