Android ListView с RadioButton в режиме singleChoice и настраиваемый макет строки
У меня есть ListView, который находится в режиме singleChoice. Все, что я хочу, - отобразить RadioButton в стороне, что при щелчке по ключевым словам, чтобы сказать, что он выбран, и когда щелкнут другой, который возвращается к невыбранному, и новый выбирается. Почему это так сложно? Это не должно быть так сложно. Я потратил DAYS на поиск подходящего ответа на этот вопрос, и я ничего не нашел, поэтому я надеюсь, что мы будем ясно и лаконично.
Мой макет для списка (R.layout.view_orders):
<?xml version="1.0" encoding="utf-8"?>
<ListView
android:choiceMode="singleChoice"
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="@drawable/list_divider"
android:dividerHeight="1px"
android:focusable="false"
android:focusableInTouchMode="false"
android:cacheColorHint="#00000000">
</ListView>
Моя пользовательская строка (R.layout.orders_row):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:app="http://schemas.android.com/apk/res/com.xxx.xxxxxx"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="6dip">
<com.xxx.xxxxxx.VerticalLabelView
app:text="SHORT"
app:textColor="#666"
app:textSize="14sp"
android:id="@+id/state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true" />
<TextView
android:id="@+id/quantity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/state"
android:layout_centerVertical="true"
android:gravity="center"
android:textSize="40sp"
android:layout_margin="2dip"
android:minWidth="30dip"
android:textColor="#555" />
<RelativeLayout
android:layout_toRightOf="@id/quantity"
android:layout_centerVertical="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/instrument"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#333"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
/>
<TextView
android:id="@+id/deets"
android:layout_below="@id/instrument"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="#888"
android:layout_marginLeft="2dip"
android:layout_marginRight="2dip"
/>
</RelativeLayout>
<RadioButton
android:id="@+id/selector"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
/>
</RelativeLayout>
Мой метод onCreate():
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.view_orders);
client = new Client(handler);
ola = new OrdersAdapter(this, R.layout.orders_row, Orders);
setListAdapter(ola);
final RelativeLayout loading = (RelativeLayout) findViewById(R.id.loading);
panel = (PositionsPanel) findViewById(R.id.panel);
Utility.showProgressBar(loading);
client.Connect("orders");
}
Теперь все, что работает, как и следовало ожидать, вы нажимаете на радиокамеру и через тег я могу соответствующим образом выбрать этот элемент из списка и манипулировать им, как я хочу. Однако, когда щелкнут первый переключатель, будет выбран последний. Нажмите этот же переключатель еще раз, и он теперь также выбран. Нажмите его еще раз, и ничего не произойдет, будут выбраны как последние, так и первые. Теперь я нажимаю любой другой в списке, он выбирается так, как ожидалось. Щелкните любой из выбранных переключателей, и ничего не произойдет, переключатель будет выбран.
Я попытался использовать следующее в onCreate():
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.view_orders);
client = new Client(handler);
ola = new OrdersAdapter(this, android.R.layout.simple_list_item_single_choice, Orders);
setListAdapter(ola);
final RelativeLayout loading = (RelativeLayout) findViewById(R.id.loading);
panel = (PositionsPanel) findViewById(R.id.panel);
Utility.showProgressBar(loading);
client.Connect("orders");
}
и просто не отображается никаких переключателей. УДИВИТЕЛЬНЫЙ.
Теперь, может быть (прочитайте: скорее всего), я просто плотный и не могу понять это, но я видел, что этот вопрос задал много, не имея реального ответа. Много ссылок на другие уроки или на книгу коммонсонов. Тем не менее, комментарии уже устарели, и его репозиторий сильно изменился, и это уже не правильные ответы.
Итак, кто-нибудь знает, как получить ожидаемую функциональность из этого? Или, если это не так, просто передайте мне исходный код приложения GMail.:)
Ответы
Ответ 1
Имейте в виду, что в элементе списка ListView RECYCLED. Вероятно, это объясняет, почему действия в одной строке влияют на другую. Копайтесь в книге Марка, и вы узнаете об этом.
Если вы используете адаптер со списком, вы можете использовать getView() на адаптере для добавления обработчика кликов в каждую строку по мере его создания/повторного использования и убедиться, что состояние управляется правильно, поскольку элементы строки создано и переработано.
Мой подход заключается в том, чтобы сохранить состояние в моей собственной структуре данных, а затем использовать getView(), чтобы отразить это в пользовательском интерфейсе, когда пользователь просматривает ListView. Может быть лучшее решение, но это работает для меня.
Ответ 2
Я проверил более простое решение:
Добавьте эту строку в RadioButton вашего xml файла:
<RadioButton
...
android:onClick="onClickRadioButton"
...
/>
Затем в классе активности, который использует ListView, добавьте следующее:
private RadioButton listRadioButton = null;
int listIndex = -1;
public void onClickRadioButton(View v) {
View vMain = ((View) v.getParent());
// getParent() must be added 'n' times,
// where 'n' is the number of RadioButtons' nested parents
// in your case is one.
// uncheck previous checked button.
if (listRadioButton != null) listRadioButton.setChecked(false);
// assign to the variable the new one
listRadioButton = (RadioButton) v;
// find if the new one is checked or not, and set "listIndex"
if (listRadioButton.isChecked) {
listIndex = ((ViewGroup) vMain.getParent()).indexOfChild(vMain);
} else {
listRadioButton = null;
listIndex = -1
}
}
С помощью этого простого кода проверяется только один RadioButton.
Если вы коснетесь того, который уже проверен, он возвращается в непроверенный режим.
"listIndex" отслеживает отмеченный элемент, -1, если нет.
Если вы хотите, чтобы всегда один был проверен, тогда код в onClickRadioButton должен быть:
public void onClickRadioButton(View v) {
View vMain = ((View) v.getParent());
int newIntex = ((ViewGroup) vMain.getParent()).indexOfChild(vMain);
if (listIndex == newIndex) return;
if (listRadioButton != null) {
listRadioButton.setChecked(false);
}
listRadioButton = (RadioButton) v;
listIndex = newIndex;
}
Ответ 3
Мое имя - Гураб Сингха. Я решил эту проблему. У меня есть письменный код для его решения. Надеюсь, это поможет всем вам. Благодарю. Мне требуется 3 часа для этого.
public void add_option_to_list(View v){
LinearLayout ll = (LinearLayout)v.getParent();
LinearLayout ll_helper = null;
LinearLayout ll2 = (LinearLayout)ll.getParent();
LinearLayout ll3 = (LinearLayout)ll2.getParent();
ListView ll4 = (ListView)ll3.getParent();
//RadioButton rb1= (RadioButton)ll.getChildAt(1);
Toast.makeText(getApplicationContext(), ", "+ll4.getChildCount(), Toast.LENGTH_LONG).show();
//ll.findViewById(R.id.radio_option_button)
for(int k=0;k<ll4.getChildCount();k++){
ll3 = (LinearLayout)ll4.getChildAt(k);
ll2 = (LinearLayout)ll3.getChildAt(0);
ll_helper = (LinearLayout)ll2.getChildAt(0);
RadioButton rb1 = (RadioButton)ll_helper.getChildAt(1);
if(rb1.isChecked())
rb1.setChecked(false);
}
RadioButton rb1 = (RadioButton)ll.getChildAt(1);
rb1.setChecked(true);
//Toast.makeText(getApplicationContext(), ""+((TextView)ll.getChildAt(4)).getText().toString(), Toast.LENGTH_LONG).show();
}
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="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Category Name"
android:textAppearance="?android:attr/textAppearanceMedium"
android:visibility="gone" />
<RadioButton
android:id="@+id/radio_option_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="add_option_to_list"
android:text="" />
<TextView
android:id="@+id/option_name"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginLeft="3dp"
android:layout_weight="5.35"
android:text="Category Name"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/option_price"
android:layout_width="76dp"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:gravity="right"
android:text="$0.00"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/option_unit_price"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:gravity="right"
android:text="$0.00"
android:textAppearance="?android:attr/textAppearanceMedium"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
Ответ 4
У меня была аналогичная проблема. Казалось, что это связано с переработкой взглядов. Но я добавил Log везде и заметил, что обработка перерабатывающей техники была прекрасной.
Проблема связана с обработкой RadioButtons. Я использовал:
if(answer == DBAdapter.YES){
rbYes.setChecked(true);
rbNo.setChecked(false);
}
else if(answer == DBAdapter.NO){
rbYes.setChecked(false);
rbNo.setChecked(true);
}
else{
rbYes.setChecked(false);
rbNo.setChecked(false);
}
и правильный способ сделать это:
if(answer == DBAdapter.YES){
rbYes.setChecked(true);
}
else if(answer == DBAdapter.NO){
rbNo.setChecked(true);
}
else{
RadioGroup rg = (RadioGroup)(holder.answerView);
rg.clearCheck();
}
Ответ 5
Вы можете добиться гораздо более простого, следуйте этому. Он был опробован в MarshMallow
1) Имейте CheckedTextView
:
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checkMark="?android:attr/listChoiceIndicatorSingle"
android:padding="10dp"
android:textAppearance="?android:attr/textAppearanceMedium">
Не забудьте поставить choiceMode:Single
в свой ListView
.
Ответ 6
Внутри адаптера
viewHolder.radioBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.e("called", "called");
if(position != mSelectedPosition && mSelectedRB != null){
mSelectedRB.setChecked(false);
}
mSelectedPosition = position;
mSelectedRB = (RadioButton)v;
}
});
viewHolder.radioBtn.setText(mList[position]);
if(mSelectedPosition != position){
viewHolder.radioBtn.setChecked(false);
}else{
viewHolder.radioBtn.setChecked(true);
if(mSelectedRB != null && viewHolder.radioBtn != mSelectedRB){
mSelectedRB = viewHolder.radioBtn;
}
}
добавить стиль к переключателю
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/tick" android:state_checked="true"/>
<item android:drawable="@drawable/untick" android:state_checked="false"/>
</selector>
а в 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" >
<RadioButton
android:id="@+id/radioBtn"
android:layout_width="match_parent"
android:layout_height="50dp"
android:button="@null"
android:checked="true"
android:drawablePadding="30dp"
android:drawableRight="@drawable/checkmark"
android:text="first" />
</RelativeLayout>
Ответ 7
На вашем адаптере:
public void setChecked(View v, int position) {
ViewGroup parent = ((ViewGroup) v.getParent()); // linear layout
for (int x = 0; x < parent.getChildCount() ; x++) {
View cv = parent.getChildAt(x);
((RadioButton)cv.findViewById(R.id.checkbox)).setChecked(false); // your checkbox/radiobtt id
}
RadioButton radio = (RadioButton)v.findViewById(R.id.checkbox);
radio.setChecked(true);
}
О вашей деятельности/фрагменте:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
((ModelNameAdapter)adapter).setChecked(view, position);
}
});