Intereting Posts
Как избавиться от панели имен программ в верхней части приложения? Дополнительное пространство между клавишей «Сводная панель инструментов» и кнопкой «Домой / Вверх» WebView показывает исходный html с loadDataWithBaseURL, а не визуализированный вид Android: Существуют ли устройства плотности xxxhdpi? Android Studio – проверка кода – исключение сгенерированных файлов GetString вне контекста или действия Не удалось создать эмулятор с Android версии 4.0.3 Не удалось найти следующие классы: android.support.v7.internal.app.WindowDecorActionBar Как начать работу с Android для Android без телефона? Круглые до 2 знаков после запятой Как программно запустить конкретное приложение в Android? OnSurfaceTextureAvailable никогда не вызывается, когда в представлении текстуры создаются объекты Service Android gradle build System.getEnv ("RELEASE_PASSWORD") возвращает null Получение ошибки «Активность Java.lang.IllegalStateException была уничтожена» при использовании вкладок с ViewPager Как предотвратить выполнение команд GC_CONCURRENT в Logcat

Одиночный выбор в RecyclerView

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

public void onBindViewHolder(ViewHolder holder, final int position) { holder.mTextView.setText(fonts.get(position).getName()); holder.checkBox.setChecked(fonts.get(position).isSelected()); holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if(isChecked) { for (int i = 0; i < fonts.size(); i++) { fonts.get(i).setSelected(false); } fonts.get(position).setSelected(isChecked); } } }); } 

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

Я объясню вам изображения.

По умолчанию первый элемент выбирается из моего адаптера

Введите описание изображения здесь

То я пытаюсь выбрать 2-й, а затем 3-й, а затем 4-й и, наконец, 5-й,

Введите описание изображения здесь

Здесь должен быть выбран только 5-й, но все пять выбираются.

Если я прокручу список донизу и вернусь наверх,

Введите описание изображения здесь

Я получил то, что ожидал,

Как я могу решить эту проблему? И некоторое время. Если я прокручу список очень быстро, будет выбран другой элемент. Как преодолеть эту проблему?

Обновить

Пока я пытаюсь использовать notifyDataSetChanged() после fonts.get(position).setSelected(isChecked); Я получил следующее исключение,

 java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:1462) at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onChanged(RecyclerView.java:2982) at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyChanged(RecyclerView.java:7493) at android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged(RecyclerView.java:4338) at com.app.myapp.screens.RecycleAdapter.onRowSelect(RecycleAdapter.java:111) 

Любое решение будет высоко оценено.

Благодарю.

Solutions Collecting From Web of "Одиночный выбор в RecyclerView"

Решение проблемы:

 public class yourRecyclerViewAdapter extends RecyclerView.Adapter<yourRecyclerViewAdapter.yourViewHolder> { private static CheckBox lastChecked = null; private static int lastCheckedPos = 0; ... ... public void onBindViewHolder(ViewHolder holder, final int position) { holder.mTextView.setText(fonts.get(position).getName()); holder.checkBox.setChecked(fonts.get(position).isSelected()); holder.checkBox.setTag(new Integer(position)); //for default check in first item if(position == 0 && fonts.get(0).isSelected() && holder.checkBox.isChecked()) { lastChecked = holder.checkBox; lastCheckedPos = 0; } holder.checkBox.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { CheckBox cb = (CheckBox)v; int clickedPos = ((Integer)cb.getTag()).intValue(); if(cb.isChecked) { if(lastChecked != null) { lastChecked.setChecked(false); fonts.get(lastCheckedPos).setSelected(false); } lastChecked = cb; lastCheckedPos = clickedPos; } else lastChecked = null; fonts.get(clickedPos).setSelected(cb.isChecked); } }); } ... ... } 

Надеюсь эта помощь!

Его слишком поздно все же выставлять это может помочь кому-то другому. Используйте ниже код в качестве ссылки для проверки отдельного элемента в RecyclerView

 /** * Created by subrahmanyam on 28-01-2016, 04:02 PM. */ public class SampleAdapter extends RecyclerView.Adapter<SampleAdapter.ViewHolder> { private final String[] list; private int lastCheckedPosition = -1; public SampleAdapter(String[] list) { this.list = list; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = View.inflate(parent.getContext(), R.layout.sample_layout, null); ViewHolder holder = new ViewHolder(view); return holder; } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.choiceName.setText(list[position]); holder.radioButton.setChecked(position == lastCheckedPosition); } @Override public int getItemCount() { return list.length; } public class ViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.choice_name) TextView choiceName; @Bind(R.id.choice_select) RadioButton radioButton; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); radioButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { lastCheckedPosition = getAdapterPosition(); //because of this blinking problem occurs so //i have a suggestion to add notifyDataSetChanged(); // notifyItemRangeChanged(0, list.length);//blink list problem notifyDataSetChanged(); } }); } } } 

Похоже, здесь есть две вещи:

(1) Представления повторно используются, поэтому старый слушатель все еще присутствует.

(2) Вы меняете данные, не уведомляя адаптер об изменении.

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

(1) Просмотр повторно использовать

В основном, в onBindViewHolder вам предоставляется уже инициализированный ViewHolder , который уже содержит представление. Этот ViewHolder может быть или не быть ранее привязан к некоторым данным!

Обратите внимание на этот бит кода прямо здесь:

 holder.checkBox.setChecked(fonts.get(position).isSelected()); 

Если держатель ранее был связан, то флажок уже имеет прослушиватель, когда изменяется состояние проверки! Этот слушатель запускается в этот момент, что и вызывало ваше IllegalStateException .

Простое решение – удалить слушателя перед вызовом setChecked . Элегантное решение потребует большего знания ваших взглядов – я рекомендую вам искать более удобный способ справиться с этим.

(2) Уведомлять адаптер при изменении данных

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

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

 if(isChecked) { for (int i = 0; i < fonts.size(); i++) { if (i == position) continue; Font f = fonts.get(i); if (f.isSelected()) { f.setSelected(false); notifyItemChanged(i); // Tell the adapter this item is updated } } fonts.get(position).setSelected(isChecked); notifyItemChanged(position); } 

Просто используйте mCheckedPosition сохранения mCheckedPosition

 @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.checkBox.setChecked(position == mCheckedPostion); holder.checkBox.setOnClickListener(v -> { if (position == mCheckedPostion) { holder.checkBox.setChecked(false); mCheckedPostion = -1; } else { mCheckedPostion = position; notifyDataSetChanged(); } }); } 

Перед установкой setChecked() необходимо очистить OnCheckedChangeListener :

 @Override public void onBindViewHolder(final ViewHolder holder, int position) { holder.mRadioButton.setOnCheckedChangeListener(null); holder.mRadioButton.setChecked(position == mCheckedPosition); holder.mRadioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { mCheckedPosition = position; notifyDataSetChanged(); } }); } 

Таким образом, это не вызовет java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling .

Эта помощь может помочь тем, кто хочет использовать одну радиостанцию ​​для работы -> Radio Button RecycleView – Gist

If lamda Expression не поддерживается. Используйте это вместо

  View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View v) { mSelectedItem = getAdapterPosition(); notifyItemRangeChanged(0, mItems.size()); } }; 

ура

Это происходит потому, что RecyclerView, как следует из названия, отлично справляется с переработкой своих ViewHolders. Это означает, что каждый ViewHolder, когда он исчезает из виду (на самом деле, он требует немного больше, чем скрывается из виду, но имеет смысл упростить его таким образом), он перерабатывается; Это означает, что RecyclerView принимает этот ViewHolder, который уже завышен и заменяет его элементы элементами другого элемента в вашем наборе данных.

Теперь, что происходит здесь, так это то, что после прокрутки вниз, и ваши первые, выбранные, ViewHolders исчезают из поля зрения, они перерабатываются и используются для других позиций вашего набора данных. Как только вы снова встанете, ViewHolders, которые были связаны с первыми 5 элементами, теперь не обязательно совпадают .

Вот почему вы должны сохранить внутреннюю переменную в своем адаптере, которая запоминает состояние выбора для каждого элемента . Таким образом, в методе onBindViewHolder вы можете узнать, был ли выбран элемент, чей ViewHolder в данный момент привязан или нет, и измените представление соответственно, в этом случае ваше состояние RadioButton (хотя я бы предложил использовать CheckBox, если вы планируете Выбор нескольких элементов).

Если вы хотите узнать больше о RecyclerView и его внутренней работе, я приглашаю вас проверить FancyAdapters , проект, который я начал в GitHub. Это набор адаптеров, которые реализуют отбор , перетаскивание элементов и прокрутку для отклонения возможностей. Возможно, проверив код, вы сможете получить хорошее представление о том, как работает RecyclerView.

  public class GetStudentAdapter extends RecyclerView.Adapter<GetStudentAdapter.MyViewHolder> { private List<GetStudentModel> getStudentList; Context context; RecyclerView recyclerView; public class MyViewHolder extends RecyclerView.ViewHolder { TextView textStudentName; RadioButton rbSelect; public MyViewHolder(View view) { super(view); textStudentName = (TextView) view.findViewById(R.id.textStudentName); rbSelect = (RadioButton) view.findViewById(R.id.rbSelect); } } public GetStudentAdapter(Context context, RecyclerView recyclerView, List<GetStudentModel> getStudentList) { this.getStudentList = getStudentList; this.recyclerView = recyclerView; this.context = context; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.select_student_list_item, parent, false); return new MyViewHolder(itemView); } @Override public void onBindViewHolder(final MyViewHolder holder, final int position) { holder.textStudentName.setText(getStudentList.get(position).getName()); holder.rbSelect.setChecked(getStudentList.get(position).isSelected()); holder.rbSelect.setTag(position); // This line is important. holder.rbSelect.setOnClickListener(onStateChangedListener(holder.rbSelect, position)); } @Override public int getItemCount() { return getStudentList.size(); } private View.OnClickListener onStateChangedListener(final RadioButton checkBox, final int position) { return new View.OnClickListener() { @Override public void onClick(View v) { if (checkBox.isChecked()) { for (int i = 0; i < getStudentList.size(); i++) { getStudentList.get(i).setSelected(false); } getStudentList.get(position).setSelected(checkBox.isChecked()); notifyDataSetChanged(); } else { } } }; } } 

Этот простой работал для меня

 private RadioButton lastCheckedRB = null; ... @Override public void onBindViewHolder(final CoachListViewHolder holder, final int position) { holder.priceRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { RadioButton checked_rb = (RadioButton) group.findViewById(checkedId); if (lastCheckedRB != null) { lastCheckedRB.setChecked(false); } //store the clicked radiobutton lastCheckedRB = checked_rb; } }); 

Пожалуйста, попробуйте это … Это работает для меня ..

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

 SparseBooleanArray sparseBooleanArray; 

В конструкторе инициализируйте это,

  sparseBooleanArray=new SparseBooleanArray(); 

В держателе связки добавить,

 @Override public void onBindViewHolder(DispositionViewHolder holder, final int position) { holder.tv_disposition.setText(dispList.get(position).getName()); if(sparseBooleanArray.get(position,false)) { holder.rd_disp.setChecked(true); } else { holder.rd_disp.setChecked(false); } setClickListner(holder,position); } private void setClickListner(final DispositionViewHolder holder, final int position) { holder.rd_disp.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sparseBooleanArray.clear(); sparseBooleanArray.put(position, true); notifyDataSetChanged(); } }); } 

Rd_disp – это переключатель в файле xml.

Поэтому, когда просмотр ресайклера загружает элементы, в bindView Holder он проверяет, содержит ли sparseBooleanArray значение «true», соответствующее его позиции.

Если возвращаемое значение истинно, мы установили выбор переключателя true.Else, мы устанавливаем значение false. В onclickHolder я очистил sparseArray и установил значение true, соответствующее этой позиции. Когда я вызываю notify datasetChange, он снова вызывает onBindViewHolder, и условие снова проверяется. Это делает наш выбор только для выбора определенного радио.

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

Три шага для этого: 1) Объявить глобальную целочисленную переменную,

 private int mSelectedItem = -1; 

2) в onBindViewHolder

  mRadio.setChecked(position == mSelectedItem); 

3) в onClickListener

 mSelectedItem = getAdapterPosition(); notifyItemRangeChanged(0, mSingleCheckList.size()); mAdapter.onItemHolderClick(SingleCheckViewHolder.this);