SwitchPreferenceCompat: android:switchTextOff / switchTextOn не работает
Я пытаюсь отобразить switchPreference, который позволяет пользователю отображать расстояние в милях или км. Я использую библиотеку поддержки SwitchPreferenceCompat. Согласно библиотеке, я могу использовать textSwitchOff и textSwitchOn, чтобы добавить текст к переключателю. Я просто хочу добавить "км" или "миль" к своему коммутатору, чтобы пользователь знал, какая метрика отображается.
В соответствии с этим документом все, что мне нужно, это код ниже:
<android.support.v7.preference.PreferenceCategory
android:layout="@layout/preferences_category"
android:title="Distance" >
<android.support.v7.preference.SwitchPreferenceCompat android:title="KM or Miles"
android:key="kmormiles"
android:switchTextOff="miles"
android:switchTextOn="km"
android:defaultValue="true"/>
</android.support.v7.preference.PreferenceCategory>
Тем не менее, переключатель просто выглядит как обычный переключатель, на самом переключателе нет дополнительного текста.
Как мне заставить это отображаться с textOn и textOff?
Я также попробовал следующее:
addPreferencesFromResource(R.xml.preferences);
kmormiles = (SwitchPreferenceCompat) findPreference("kmormiles");
kmormiles.setSwitchTextOff("Km");
kmormiles.setSwitchTextOn("miles");
Все еще не работает. Я пробую это на двух разных эмуляторах genymotion, API 16 и API 21.
1 ответ
Потому что SwitchPreferenceCompat
используя SwitchCompat
виджет по умолчанию, виджет Android Switch textOn и textOff не работает в Lollipop, здесь также есть приложение. И первое утверждение
Текст не отображается по умолчанию в теме "Материал", поскольку ресурсы виджета-переключателя плохо работают с текстом.
также объясняет, почему результат выглядит не очень хорошо.
SwitchPreferenceCompat
Сам класс не дает возможности установить, должен ли отображаться текст включения / выключения. Так что одним из способов заставить это работать может быть переопределение onBindViewHolder(PreferenceViewHolder)
метод, чтобы установить это программно.
Другой и, возможно, лучший метод - это использование механизмов тем, которые вы все равно вынуждены использовать с библиотекой предпочтений. Вы не можете установить какой-либо атрибут для видов напрямую, но вы можете определить макет, который будет использоваться с android:widgetLayout
, Так что просто создайте свой собственный оверлей темы предпочтений
<style name="MyPreferenceThemeOverlay" parent="PreferenceThemeOverlay">
<item name="switchPreferenceCompatStyle">@style/MySwitchPreferenceCompat</item>
</style>
с вашим собственным стилем предпочтений переключателя
<style name="MySwitchPreferenceCompat" parent="Preference.SwitchPreferenceCompat">
<item name="android:widgetLayout">@layout/pref_stack</item>
</style>
используя слегка измененную схему переключателей по умолчанию
<android.support.v7.widget.SwitchCompat
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/switchWidget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:focusable="false"
app:showText="true" />
Еще одна вещь, которую вы должны иметь в виду при работе с кодом - это сама функциональность Compat. С использованием android.support.v7.preference.SwitchPreferenceCompat
явно, вы никогда не получите версии, более подходящие для более новых устройств, о которых автоматически знает инфлятор, как единственно доступная в настоящее время альтернатива android.support.v14.preference.SwitchPreferenceCompat
, Это может потребовать немного больше работы на вашей стороне, хотя.
РЕДАКТИРОВАТЬ: Это результаты реализации вышеизложенного предложения автора, как он правильно сказал, результаты выглядят не очень хорошо:
Опираясь на опцию Tynn переопределить метод OnBindViewHolder, я реализовал его, и он работает. Поэтому я опубликую здесь код с пояснительными комментариями на случай, если кто-то захочет его использовать.
ПРИМЕЧАНИЕ. Я разрабатываю свое приложение на Xamarin.Android, поэтому код написан на C#, но его перевод на Java (или Kotlin) должен быть интуитивно понятным.
CustomSwitchPreferenceWidget.cs
namespace KeepTravelling.Ui
{
class CustomSwitchPreferenceWidget : SwitchPreferenceCompat
{
private int TitleId = 0;
private bool IsTitleFound => TitleId > 0; //equivalent to bool IsTitleFound(){ return TitleId > 0};
public string TextWhenOn { get; set; }//getters and setters
public string TextWhenOff { get; set; }
public CustomSwitchPreferenceWidget(Context context, IAttributeSet attrs) : base(context, attrs)
{
TypedArray attrsArray = context.ObtainStyledAttributes(attrs, Resource.Styleable.CustomSwitchPreferenceWidget);
TextWhenOn = attrsArray.GetString(Resource.Styleable.CustomSwitchPreferenceWidget_textWhenOn);
TextWhenOff = attrsArray.GetString(Resource.Styleable.CustomSwitchPreferenceWidget_textWhenOff);
}
//Method that will search through holder element for a view with id = "title"
//Once found it will store it in TitleId member
private void FindTitleId(PreferenceViewHolder holder)
{
//Base element is a LinearLayout, but you can check it again to make sure it is
LinearLayout layout = (LinearLayout)holder.ItemView;
for (int i = 0; i < layout.ChildCount; i++)
{
var item = layout.GetChildAt(i);
if (item.GetType().ToString().Contains("Layout")) //check if child element is a layout view
{
ViewGroup group = (ViewGroup)item;
for (int j = 0; j < group.ChildCount; j++)
{
var nestedItem = group.GetChildAt(j);
string entryName = Context.Resources.GetResourceEntryName(nestedItem.Id);
if (entryName.Equals("title"))//we are looking for the TextView with id = "title"
{
//If we found it, store in TitleId member and return from the method
TitleId = nestedItem.Id;
return;
}
if (nestedItem.GetType().ToString().Contains("Layout"))
{
ViewGroup nestedGroup = (ViewGroup)nestedItem;
for (int k = 0; k < nestedGroup.ChildCount; k++)//3 levels should be enough and it actually never arrive here
{
var nestedNestedItem = nestedGroup.GetChildAt(k);
string nestedEntryName = Context.Resources.GetResourceEntryName(nestedNestedItem.Id);
if (entryName.Equals("title"))
{
TitleId = nestedNestedItem.Id;
return;
}
}
}
}
}
}
}
public override void OnBindViewHolder(PreferenceViewHolder holder)
{
base.OnBindViewHolder(holder);
//Check if we already have found it
if (!IsTitleFound)
{
//If not => find it!!
FindTitleId(holder);
//If for some reason it is not found, return from method
if (!IsTitleFound) return;
}
AppCompatTextView title = (AppCompatTextView)holder.FindViewById(TitleId);
if (title != null)
{
if (MChecked)//MChecked value is self-explanatory
{
title.Text = TextWhenOn;
}
else
{
title.Text = TextWhenOff;
}
}
}
}
}
Затем вы должны объявить атрибуты в values /attrs.xml следующим образом:
Ресурсы / значения /attrs.xml
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<declare-styleable name="CustomSwitchPreferenceWidget">
<attr name="textWhenOn" format="string"/>
<attr name="textWhenOff" format="string"/>
</declare-styleable>
</resources>
И теперь вы можете использовать их в своем макете (в моем случае я использую его в файле настроек): Resources / xml / preferences.axml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:customAttrs="http://schemas.android.com/apk/res-auto2">
<!-- More items -->
<!-- ... -->
<KeepTravelling.Ui.CustomSwitchPreferenceWidget
android:defaultValue="true"
android:title="Start location service"
android:key="start_stop_option"
android:summary="If this option is turned off the service won't be running and thus you will not get new locations."
customAttrs:textWhenOn="Text when ON"
customAttrs:textWhenOff="Text when OFF">
</KeepTravelling.Ui.CustomSwitchPreferenceWidget>
</PreferenceScreen>
Обратите внимание, что вы должны объявить используемое вами пространство имен xml, чтобы оно не совпадало с пространством Android. URL не должен существовать, он должен быть только любой строкой, которая будет уникальной в проекте.
И результат:
Не стесняйтесь задавать любые вопросы.
РЕДАКТИРОВАТЬ: сделал код универсальным, чтобы его можно было использовать для любых целей.