Android支持EditTextPreference输入类型

Android support EditTextPreference input type

有什么方法可以指定android.support.v7.preference.EditTextPreference的输入法类型吗?

编辑: 以下之前的答案是基于原版 android.preference.EditTextPreference 的,不幸的是不适用于 android.support.v7.preference.EditTextPreference.

android.preference.EditTextPreference 中,EditText 控件以编程方式创建,并且 Preference 中的 AttributeSet 被传递给它。

android.preference.EditTextPreference Source:

public EditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);

    mEditText = new EditText(context, attrs);

    // Give it an ID so it can be saved/restored
    mEditText.setId(com.android.internal.R.id.edit);

    /*
     * The preference framework and view framework both have an 'enabled'
     * attribute. Most likely, the 'enabled' specified in this XML is for
     * the preference framework, but it was also given to the view framework.
     * We reset the enabled state.
     */
    mEditText.setEnabled(true);
}

White 允许我们在 Preference 本身上设置 inputType 并将其传递给 EditText。不幸的是 android.support.v7.preference.EditTextPreference 似乎在 Layout

中创建了 EditText

有关解决此问题的想法,请参阅 this issue

Just wanted to let you know that subclassing EditTextPreferenceDialogFragment and overriding onAddEditTextToDialogView as well as overriding PreferenceFragmentCompat#onDisplayPreferenceDialog to show that subclass as needed seems to be working fine, thanks for the help.


创建您自己的 class 扩展 EditTextPreference 并将其设置在那里。

这是我的 EditIntegerPreference class:

public class EditIntegerPreference extends EditTextPreference {
    public EditIntegerPreference(Context context) {
        super(context);
    }

    public EditIntegerPreference(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
    }

    public EditIntegerPreference(Context context, AttributeSet attributeSet, int defStyle) {
        super(context, attributeSet, defStyle);

        getEditText().setInputType(InputType.TYPE_CLASS_NUMBER);
        getEditText().setSelectAllOnFocus(true);
    }

    @Override
    public String getText() {
        try {
            return String.valueOf(getSharedPreferences().getInt(getKey(), 0));
        } catch (Exception e) {
            return getSharedPreferences().getString(getKey(), "0");
        }
    }

    @Override
    public void setText(String text) {
        try {
            if (getSharedPreferences() != null) {
                getSharedPreferences().edit().putInt(getKey(), Integer.parseInt(text)).commit();
            }
        } catch (Exception e) {
            // TODO: This catch stinks!
        }
    }

    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
        getEditText().setInputType(InputType.TYPE_CLASS_NUMBER);
        getEditText().setSelectAllOnFocus(true);

        if (restoreValue) {
            getEditText().setText(getText());
        } else {
            super.onSetInitialValue(restoreValue, defaultValue != null ? defaultValue : "");
        }
    }
}

请注意,可以将 inputType 属性添加到 EditTextPreference

android:inputType="number"

我没有走这条路的原因是我希望我的偏好存储为 Integer 而不是 String

现在可以使用 Android-Support-Preference-V7-Fix 库。
修复了 EditTextPreference 将 XML 属性(如 inputType)转发到 EditText , 就像最初的偏好一样。

如果您不想使用第三方库,可以为 EditTextPreference 指定布局

<EditTextPreference android:defaultValue="0"
                        android:key="some_key"
                        android:title="Title"
                        android:dialogLayout="@layout/preference_edit_text"/>

然后在res/layout/preference_edit_text.xml

<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <EditText android:id="@android:id/edit"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:inputType="number"
          android:singleLine="true" 
          app:layout_constraintStart_toStartOf="parent"
          app:layout_constraintEnd_toEndOf="parent"
          app:layout_constraintTop_toTopOf="parent"
          app:layout_constraintBottom_toBottomOf="parent"
          android:layout_marginStart="21dp" 
          android:layout_marginEnd="21dp"/>

</android.support.constraint.ConstraintLayout>

请注意,编辑文本 ID 必须是:@android:id/edit 但是你可以在 android:inputType 字段

中随意使用任何你想要的东西

我确定有比使用 21dp 边距更好的对齐 EditText 的方法 但至少它有效

这是我从 Cory Charlton 得到的答案版本,已转移到 Jetpack 首选项并用 Kotlin 编写:

 import android.content.Context
 import android.content.SharedPreferences
 import android.text.InputType
 import android.util.AttributeSet
 import androidx.preference.EditTextPreference
 
 
 class EditIntegerPreference : EditTextPreference {
     constructor(context: Context?) : super(context) {
         setInputMethod()
     }
 
     constructor(context: Context?, attributeSet: AttributeSet?) : super(context, attributeSet) {
         setInputMethod()
     }
 
     constructor(context: Context?, attributeSet: AttributeSet?, defStyle: Int) : super(
         context,
         attributeSet,
         defStyle
     ) {
         setInputMethod()
     }
 
     override fun getText(): String =
         try {
             java.lang.String.valueOf(sharedPreferences.getInt(key, 0))
         } catch (e: Exception) {
             "0"
         }
 
     override fun setText(text: String?) {
         try {
             if (text != null) {
                 sharedPreferences?.edit()?.putInt(key, text.toInt())?.apply()
                 summary = text
             } else {
                 sharedPreferences?.remove(key)
                 summary = ""
             }
         } catch (e: Exception) {
             sharedPreferences?.remove(key)
             summary = ""
         }
     }
 
     override fun onSetInitialValue(defaultValue: Any?) {
         val defaultValueInt: Int =
                 when (defaultValue){
                     is Int -> defaultValue
                     is String -> try {defaultValue.toInt()} catch (ex: java.lang.Exception){0}
                     else -> 0
                 }
 
         text = sharedPreferences.getInt(key, defaultValueInt).toString()
     }
 
     private fun setInputMethod() {
         setOnBindEditTextListener {
             it.inputType = InputType.TYPE_CLASS_NUMBER
         }
     }
 
     fun SharedPreferences.remove(key: String) = edit().remove(key).apply()
 }

Kotlin + DataStore + androidx.Preference

的解决方法

免责声明!

可能不是这样做的方法!
理想情况下应该只有:

  • 将输入设置为 int
  • 覆盖 DataStore class:putInt/getInt

扩展函数

在我的例子中,我有一个 PreferenceFragmentCompat,所以:

fun PreferenceFragmentCompat.setNumericInput(
@StringRes prefRes: Int, initialValue: String) {

  val preference = findPreference(getString(prefRes)) as EditTextPreference?

  preference?.setOnBindEditTextListener { editText ->
    editText.inputType = InputType.TYPE_CLASS_NUMBER or 
      InputType.TYPE_NUMBER_FLAG_SIGNED

    // set the initial value: I read it from the DataStore and then
    // pass it as the 2nd argument to setNumericInput.
    // BTW, I do store stringPreferenceKeys, as it's the putString method 
    // that get's triggered
    if (editText.text.isEmpty()) editText.setText(initialValue)

    editText.setSelection(editText.text.length) // put cursor at the end
  }

  // to use it in the summary do something like:
  preference?.setOnPreferenceChangeListener { it, newValue ->
    it.summary = "updated: $newValue"
    true
  }
}

此外,在我的 Activity 中扩展 BaseSettingsActivity 我 使用

替换 SharedPreferences 中的管理
preferenceManager.preferenceDataStore = dataStoreCvLogger