Android: Как получить радиогруппу с тумблерами?
Я хочу группу кнопок, где пользователь может выбрать одну из них в качестве опции. Это должно быть поведение радиобутгруппы, но я не хочу, чтобы присутствовал радиокружок. Я просто хочу, чтобы пользователь мог переключать только одну из кнопок.
Я думаю, что мне нужно что-то вроде группы переключателей.
Существует ли что-то подобное в Android?
11 ответов
Я бы просто повторно использовал RadioGroup
вот так: (обратите внимание, onClick
атрибут, то есть нажатие кнопки вызовет вашу активность onToggle(View)
метод.
<RadioGroup android:id="@+id/toggleGroup"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:orientation="horizontal"
>
<ToggleButton android:id="@+id/btn_Letter"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="1"
android:textSize="14sp"
android:textOn="Letter"
android:textOff="Letter"
android:onClick="onToggle"
android:checked="true"
/>
<ToggleButton android:id="@+id/btn_A4"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="1"
android:textSize="14sp"
android:textOn="A4"
android:textOff="A4"
android:onClick="onToggle"
/>
</RadioGroup>
В своей деятельности или в другом месте вы можете определить слушателя, например,
static final RadioGroup.OnCheckedChangeListener ToggleListener = new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final RadioGroup radioGroup, final int i) {
for (int j = 0; j < radioGroup.getChildCount(); j++) {
final ToggleButton view = (ToggleButton) radioGroup.getChildAt(j);
view.setChecked(view.getId() == i);
}
}
};
и зарегистрируйте его, например, в onCreate()
:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.scan_settings);
((RadioGroup) findViewById(R.id.toggleGroup)).setOnCheckedChangeListener(ToggleListener);
}
наконец в onToggle(View)
, вы будете делать все, что должно произойти, в зависимости от вашего приложения. а также вызовите метод проверки RadioGroup с идентификатором переключенного представления. Вот так:
public void onToggle(View view) {
((RadioGroup)view.getParent()).check(view.getId());
// app specific stuff ..
}
Вы можете использовать обычные переключатели и использовать изображение для фона RadioButton и не указывать текстовую строку:
<RadioButton
android:id="@+id/custom_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="@null"
android:background="@drawable/button_custom"
/>
Для фона используйте любой нарисованный объект, но, скорее всего, вы захотите использовать селектор, чтобы иметь возможность предоставлять разные изображения для разных состояний. Самая простая версия использует только два изображения:
<item android:state_checked="true" android:state_pressed="true"
android:drawable="@drawable/custom_selected" />
<item android:state_checked="false" android:state_pressed="true"
android:drawable="@drawable/custom_normal" />
<item android:state_checked="true" android:state_focused="true"
android:drawable="@drawable/custom_selected" />
<item android:state_checked="false" android:state_focused="true"
android:drawable="@drawable/custom_normal" />
<item android:state_checked="false" android:drawable="@drawable/custom_normal" />
<item android:state_checked="true" android:drawable="@drawable/custom_selected" />
При этом радио-кнопка выглядит как обычная кнопка (точнее, выглядит как любой нарисованный вами рисунок) и ведет себя как радио-кнопка в группе радио.
Вот как мне это удалось (нет RadioGroup
участвует):
private CompoundButton.OnCheckedChangeListener toggleListener = new CompoundButton.OnCheckedChangeListener()
{
boolean avoidRecursions = false;
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if(avoidRecursions) return;
avoidRecursions = true;
// don't allow the un-checking
if(!isChecked)
{
buttonView.setChecked(true);
avoidRecursions = false;
return;
}
// un-check the previous checked button
if(buttonView != toggleButton1 && toggleButton1.isChecked()) toggleButton1.setChecked(false);
else if(buttonView != toggleButton2 && toggleButton2.isChecked()) toggleButton2.setChecked(false);
else if(buttonView != toggleButton3 && toggleButton3.isChecked()) toggleButton3.setChecked(false);
else if(buttonView != toggleButton4 && toggleButton4.isChecked()) toggleButton4.setChecked(false);
avoidRecursions = false;
}
};
// ...
toggleButton1.setOnCheckedChangeListener(toggleListener);
toggleButton2.setOnCheckedChangeListener(toggleListener);
toggleButton3.setOnCheckedChangeListener(toggleListener);
toggleButton4.setOnCheckedChangeListener(toggleListener);
Я перепробовал все методы, описанные выше, и ни один из них не работал так хорошо.
Попытка взломать радиокнопку, чтобы она выглядела как настоящая кнопка, выглядит плохо.
В конце концов я просто взял исходный код RadioGroup и изменил его так, чтобы он принимал ToggleButton, а не RadioButton. Работает действительно хорошо!
Вот источник на Github: ToggleGroup
Использование:
<com.rapsacnz.ToggleGroup
android:id="@+id/deal_detail_toolbar"
android:layout_width="fill_parent"
android:layout_height="60dip"
android:layout_alignParentBottom="true"
android:background="@drawable/bgnd_toggle_button">
<ToggleButton
android:id="@+id/b1"
android:textOn="@string/tab_1_label"
android:textOff="@string/tab_1_label"
android:textSize="10sp"
android:textColor="@color/tab_button_color"
android:checked="true"
android:layout_width="fill_parent"
android:layout_height="60dp"
android:layout_weight="1"
android:drawableTop="@drawable/toggle_spotlight"
android:drawablePadding="-5dp "
android:gravity="bottom|center"
android:paddingTop="10dp"
android:paddingBottom="5dp"
android:background="@drawable/bgnd_transparent" />
<ToggleButton
android:id="@+id/b2"
android:textOn="@string/tab_2_label"
android:textOff="@string/tab_2_label"
android:textSize="10sp"
android:textColor="@color/tab_button_color"
android:checked="false"
android:layout_width="fill_parent"
android:layout_height="60dp"
android:layout_weight="1"
android:drawableTop="@drawable/toggle_browse"
android:gravity="bottom|center"
android:paddingTop="10dp"
android:paddingBottom="5dp"
android:background="@drawable/bgnd_transparent" />
<ToggleButton
android:id="@+id/b3"
android:textOn="@string/tab_3_label"
android:textOff="@string/tab_3_label"
android:textSize="10sp"
android:textColor="@color/tab_button_color"
android:checked="false"
android:layout_width="fill_parent"
android:layout_height="60dp"
android:layout_weight="1"
android:drawableTop="@drawable/toggle_purchased"
android:gravity="bottom|center"
android:paddingTop="10dp"
android:paddingBottom="5dp"
android:background="@drawable/bgnd_transparent" />
</com.rapsacnz.ToggleGroup>
Надеюсь это поможет
Я использую Kotlin, и я попробовал ответ Вольфа Паулюса, и он не сработал для меня. Я поиграл с ним и смог заставить его работать следующим образом: во-первых, я удалил "onClick" из xml:
<RadioGroup android:id="@+id/toggleGroup"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:orientation="horizontal"
>
<ToggleButton android:id="@+id/btn_Letter"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="1"
android:textSize="14sp"
android:textOn="Letter"
android:textOff="Letter"
android:checked="true"
/>
<ToggleButton android:id="@+id/btn_A4"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="1"
android:textSize="14sp"
android:textOn="A4"
android:textOff="A4"
/>
</RadioGroup>
Я не использовал ToggleListener
вместо этого внутри onCreate()
Я слушал каждого из ToggleButton
у меня есть:
btn_Letter.setOnClickListener { it -> onToggle(it) }
btn_A4.setOnClickListener { it -> onToggle(it) }
И самая важная часть, onToggle(btn: View)
private fun onToggle(btn: View) {
val radioGroup = (btn.parent as RadioGroup)
for (index in 0 until radioGroup.childCount) {
val child = radioGroup.getChildAt(index) as ToggleButton
child.isChecked = child.id == btn.id
// do what ever else you need to do
}
}
Это оно. Надеюсь, это поможет.
Мое решение достигает того же эффекта, но без использования радиокнопок.
Для xml, сначала un "селектор" в "@ drawable / myselectorfile":
<?xml version="1.0" encoding="UTF-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false"
android:drawable="@drawable/icon_off" />
<item android:state_checked="true"
android:drawable="@drawable/icon_on" />
</selector>
un файл для элементов моего списка:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/txtInfo"
android:layout_width="140dp"
android:layout_height="wrap_content"
android:paddingTop="15dip" />
<ToggleButton
android:id="@+id/BtnToggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="14dp"
android:background="@drawable/toggle_style"
android:padding="10dip"
android:textOff=""
android:textOn=""
android:focusable="false"/>
</LinearLayout>
и мой список:
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/lv_lista"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
в существующем методе:
lista.setOnItemClickListener(new OnItemClickListener() {
@SuppressWarnings("deprecation")
@Override
public void onItemClick(AdapterView<?> pariente, View view, int posicion, long id) {
@SuppressWarnings("unused")
ListEntity elegido = (ListEntity) pariente.getItemAtPosition(posicion);
varToggle = (ToggleButton) view.findViewById(R.id.BtnToggle);
varToggle.setChecked(true);
// showDialog(0); // dialog optional
//restart btn's
reStart(posicion);
}
});
в классе Activity:
@Override
protected Dialog onCreateDialog(int id){
Dialog dialogo = crearDialogoConfirmacion();
return dialogo;
}
public void reStart(int posicion){
for(int j=0;j<lista.getCount();j++)
{
View vista = lista.getChildAt(j);
ToggleButton varToggle2 = (ToggleButton) vista.findViewById(R.id.BtnToggle);
if(j != posicion){ varToggle2.setChecked(false); }
}
}
Я сделал это с LinearLayout вместо RadioGroup, используя ButterKnife:
@BindViews({R.id.one, R.id.two, R.id.three})
List<ToggleButton> toggleGroup;
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
ButterKnife.bind(this, view);
}
@OnClick({R.id.one, R.id.two, R.id.three})
public void toggle(ToggleButton selected) {
if (selected.isChecked()) {
// Deselect other buttons
for (ToggleButton button : toggleGroup) {
if (button.getId() != selected.getId()) {
button.setChecked(false);
}
}
} else {
// Disallow deselecting the current button
selected.toggle();
}
}
public void OnTabSelected(View v){
RadioGroup radioGroup = (RadioGroup)v.getParent();
for (int j = 0; j < radioGroup.getChildCount(); j++) {
ToggleButton toggleButton = (ToggleButton) radioGroup.getChildAt(j);
toggleButton.setChecked(v.getId() == toggleButton.getId());
}
}
Значит, вы хотите, чтобы кнопки из этого можно было выбрать только одну? Если вы не показываете переключатель, как пользователь узнает, что он выбрал?
Вы можете работать с RadioButton и RadioGroup, но я не знаю, сможете ли вы легко сгенерировать настраиваемую радиокнопку с видом, более подходящим для вашего приложения. Но это может быть как-то возможно, если вы можете расширить само радио-кнопку и переопределить метод рисования или посмотреть, какие кнопки можно интегрировать в радиогруппу. Может быть, вы можете реализовать специальный интерфейс для своего представления, а затем объединить несколько пользовательских кнопок в одну радиогруппу.
Котлин версия:
for(index in 0..(radioGroup.childCount-1))
(radioGroup.getChildAt(index) as ToggleButton).isChecked = false
Используя любой контейнер ViewGroup, добавьте свои CompoundButtons (CheckBox, RadioButton, Switch, SwitchCompat, ToggleButton), а затем внутри своего onCheckedChanged вызовите служебную функцию, чтобы очистить другие кнопки.
<LinearLayout
android:id="@+id/toggle_group"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ToggleButton
android:id="@+id/toggle_btn1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textOff="Off1"
android:textOn="On1" />
<View
android:layout_width="2dp"
android:layout_height="match_parent"
android:layout_margin ="8dp"
android:background="#ffff" />
<ToggleButton
android:id="@+id/toggle_btn2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textOff="Off2"
android:textOn="On2" />
</LinearLayout>
Внутри вашего onCheckedChanged займитесь изменением состояния и вызовите служебный метод, чтобы очистить других потомков. Следующее поддерживает все группы контейнеров представления, которые являются производными от ViewGroup, и позволяет смешивать не- CompoundButton объекты в контейнере. Поскольку у вас уже часто есть обратный вызов onCheckedChanged, существует только новый код для вызова служебной функции.
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int id = buttonView.getId();
switch (id) {
case R.id.toggle_btn1:
if (isChecked) {
doBtn1Action();
doRadioGroupChange((ViewGroup)buttonView.getParent(), id);
}
break;
case R.id.toggle_btn2:
if (isChecked) {
doBtn2Action();;
doRadioGroupChange((ViewGroup)buttonView.getParent(), id);
}
break;
А вот функция полезности для очистки детей.
/**
* Emulate radioGroup and clear buttons which don't match checkedId.
* @param viewGroup
* @param checkedId
*/
private static void doRadioGroupChange(final ViewGroup viewGroup, final int checkedId) {
for (int rgIdx = 0; rgIdx < viewGroup.getChildCount(); rgIdx++) {
View child = viewGroup.getChildAt(rgIdx);
if (child instanceof CompoundButton) {
final CompoundButton view = (CompoundButton) viewGroup.getChildAt(rgIdx);
view.setChecked(view.getId() == checkedId);
}
}
}