5

ユーザーがマイルまたはキロ単位で距離を表示できるようにする switchPreference を表示しようとしています。SwitchPreferenceCompat サポート ライブラリを使用しています。ライブラリによると、textSwitchOff と textSwitchOn を使用して、スイッチにテキストを追加できます。スイッチに「km」または「マイル」を追加して、どのメトリックが表示されているかをユーザーが認識できるようにしたいだけです。

このドキュメントによると、必要なのは以下のコードだけです。

<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");

それでもうまくいきません。API 16 と API 21 の 2 つの異なる Genymotion エミュレーターで試しています。

4

2 に答える 2

7

デフォルトでウィジェットをSwitchPreferenceCompat使用するため、Lollipop で動作しない Android Switch ウィジェットの textOn と textOff には、ここでもアプリケーションがあります。そして最初の発言SwitchCompat

スイッチ ウィジェット アセットはテキストではうまく機能しないため、マテリアル テーマではデフォルトでテキストが表示されません。

また、結果がまったくよく見えない理由についても説明します。

クラス自体は、SwitchPreferenceCompatオン/オフのテキストを表示するかどうかを設定する可能性を提供しません。したがって、それを機能させる1つの方法は、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" />

コードで留意すべきもう 1 つの点は、compat機能自体です。明示的に使用するandroid.support.v7.preference.SwitchPreferenceCompatと、現在利用可能な唯一の代替のように、インフレータが自動的に認識している新しいデバイスにより適したバージョンを取得することはできませんandroid.support.v14.preference.SwitchPreferenceCompat。ただし、これにはもう少し作業が必要になる場合があります。

編集:これは、ポスターによる上記の提案を実装した結果です。彼が正しく述べたように、結果はまったく良くありません:

ここに画像の説明を入力

ここに画像の説明を入力

于 2016-02-22T21:58:54.903 に答える
0

OnBindViewHolder メソッドをオーバーライドする tynn のオプションに基づいて、私はそれを実装し、機能しています。そのため、誰かが使用したい場合に備えて、コードを説明コメント付きでここに投稿します。

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

Android のものと一致しないように、使用している xml 名前空間を宣言する必要があることに注意してください。URL は存在する必要はありません。プロジェクト内で一意になる任意の文字列である必要があります。

そして結果:

前のコードの結果

ご不明な点がございましたら、お気軽にお問い合わせください。

編集:コードを汎用にして、あらゆる目的に使用できるようにしました。

于 2019-04-08T18:47:06.317 に答える