我正在尝试显示一个switchPreference,它允许用户根据里程或公里显示距离。我正在使用SwitchPreferenceCompat支持库。根据库,我可以使用textSwitchOff和textSwitchOn向开关添加文本。我只想在交换机上添加“km”或“miles”,以便用户知道显示的是哪个指标。
根据this doc,我需要的是以下代码:
<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。
答案 0 :(得分:7)
由于SwitchPreferenceCompat
默认使用SwitchCompat
小部件,Android Switch widget textOn and textOff not working in Lollipop此处也有一个应用程序。第一个声明
默认情况下,“材质”主题下不会显示文本,因为切换窗口小部件资产无法与文本一起使用。
也解释了为什么结果看起来不太好。
SwitchPreferenceCompat
类本身不提供设置是否应显示开/关文本的可能性。因此,使其工作的一种方法可能是覆盖onBindViewHolder(PreferenceViewHolder)
方法以编程方式设置它。
另一个也许更好的方法是利用你必须使用偏好compat库的主题机制。您不能直接为视图设置任何属性,但可以定义要与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>
使用稍加修改的default switch layout
<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
后,您永远不会获得更适合inflater自动了解的新设备的版本,例如当前唯一可用的替代android.support.v14.preference.SwitchPreferenceCompat
。这可能需要你做更多的工作。
编辑:这是海报实施上述建议的结果,正如他正确提到的,结果看起来并不好看:
答案 1 :(得分:0)
基于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不需要存在,它只需要是项目中唯一的任何字符串即可。
结果:
随时问任何问题。
编辑:使代码通用,因此可以用于任何目的。