SwitchPreferenceCompat:android:switchTextOff/switchTextOn不';行不通

SwitchPreferenceCompat:android:switchTextOff/switchTextOn不';行不通,android,switchpreference,Android,Switchpreference,我试图显示一个switchPreference,它允许用户根据英里或公里显示距离。我正在使用SwitchPreferenceCompat支持库。根据库,我可以使用textSwitchOff和textSwitchOn向开关添加文本。我只想将“km”或“miles”添加到我的开关中,以便用户知道显示哪个度量 根据,我只需要以下代码: <android.support.v7.preference.PreferenceCategory android:layout="@layout/pre

我试图显示一个switchPreference,它允许用户根据英里或公里显示距离。我正在使用SwitchPreferenceCompat支持库。根据库,我可以使用textSwitchOff和textSwitchOn向开关添加文本。我只想将“km”或“miles”添加到我的开关中,以便用户知道显示哪个度量

根据,我只需要以下代码:

<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>

还是不行。我正在两个不同的genymotion仿真器(API 16和API 21)上尝试它。

因为默认情况下使用了
SwitchCompat
小部件的
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>

@布局/预处理堆栈
使用稍微修改过的


基于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;
            }
        }
    }
}
namespace keeptraveling.Ui
{
类CustomSwitchPreferenceWidget:SwitchPreferenceCompat
{
私有int TitleId=0;
private bool IsTitleFound=>TitleId>0;//相当于bool IsTitleFound(){return TitleId>0};
公共字符串TextWhenOn{get;set;}//getter和setter
公共字符串TextWhenOff{get;set;}
公共CustomSwitchPreferenceWidget(上下文,IAttributeSet属性):基本(上下文,属性)
{
TypedArray attrsArray=context.actainStyledAttributes(attrs,Resource.Styleable.CustomSwitchPreferenceWidget);
TextWhenOn=attrsArray.GetString(Resource.Styleable.CustomSwitchPreferenceWidget\u TextWhenOn);
TextWhenOff=attrsArray.GetString(Resource.Styleable.CustomSwitchPreferenceWidget_TextWhenOff);
}
//方法,该方法将在holder元素中搜索id为=“title”的视图
//一旦找到,它将存储在TitleId成员中
私有void FindTitleId(首选视图持有者)
{
//基本元素是线性布局,但可以再次检查以确保它是线性布局
LinearLayout布局=(LinearLayout)holder.ItemView;
对于(int i=0;i找到它!!
FindTitleId(持有人);
//如果由于某种原因找不到它,请从方法返回
如果(!IsTitleFound)返回;
}
AppCompatTextView title=(AppCompatTextView)holder.FindViewById(TitleId);
如果(标题!=null)
{
if(MChecked)//MChecked值是自解释的
{
title.Text=TextWhenOn;
}
其他的
{
title.Text=TextWhenOff;
}
}
}
}
}

然后必须在值/att中声明属性
<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" />
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;
            }
        }
    }
}
<?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>
<?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>