安卓支持EditTextPreference输入类型

17

有没有办法为android.support.v7.preference.EditTextPreference指定输入方式类型?


2
相关的Android问题,目前还没有解决方案。 - aha
5个回答

17
如果您不想使用第三方库,可以在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字段内使用任何你想要的内容。
我相信有更好的方法来对齐EditText,而不是使用21dp的边距,但至少它起作用了。

非常感谢。被接受的答案建议使用第三方库。此外,它实际上不是针对android-support库,而是针对androidX,这在我的情况下是不可接受的。 - Federricco

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

这个库比android.support.v7.preference要好得多。功能更加丰富,主题也更容易定制。 - Michael Updike
2
AndroidX具有setOnBindEditTextListener方法,可用于解决此问题。您可以在侦听器内更改EditText输入类型。请参阅https://developer.android.com/reference/androidx/preference/EditTextPreference#setOnBindEditTextListener(androidx.preference.EditTextPreference.OnBindEditTextListener) - Jrs42

4

以下是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()
 }

如果使用了 PreferenceDatastore,我们如何将其绑定到自定义的 DataStore - Paschalis

3

编辑: 以下先前的答案是基于原始的 android.preference.EditTextPreference,不幸的是对于 android.support.v7.preference.EditTextPreference 不起作用。

android.preference.EditTextPreference 中,EditText 控件是以编程方式创建的,并将来自 PreferenceAttributeSet 传递给它。

android.preference.EditTextPreference 源代码:

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

白色允许我们在“Preference”本身上设置“inputType”,并将其传递到“EditText”。不幸的是,“android.support.v7.preference.EditTextPreference”似乎在“Layout”中创建了“EditText”。请参见this issue以获取解决方案的建议。引用块中提到,子类化“EditTextPreferenceDialogFragment”并重写“onAddEditTextToDialogView”,以及重写“PreferenceFragmentCompat#onDisplayPreferenceDialog”以根据需要显示该子类似乎工作正常,感谢您的帮助。
创建一个继承EditTextPreference的自定义类并将其设置在那里。
这是我的EditIntegerPreference类:
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 : "");
        }
    }
}

请注意,可以向EditTextPreference添加inputType属性。
android:inputType="number"

我没有选择这种方法的原因是,我希望我的偏好被存储为一个整数而不是一个字符串

4
很遗憾,android.support.v7.preference.EditTextPreference 没有 getEditText() 方法。 - ivkil
@ivkil,你需要android.support.v7.preference.EditTextPreference有什么特别的原因吗?我问这个问题是因为自API级别1以来就存在android.preference.EditTextPreference - Cory Charlton
1
是的。为了为我的应用程序提供设置,我正在使用PreferenceFragmentCompat - ivkil
@ivkil 真糟糕,我还没有使用过 PreferenceFragmentCompat。不确定为什么支持实现会比原始的 Preference 更差。我会看看能否找到其他信息。 - Cory Charlton
@ivkil,我更新了我的答案,并提供了可能的、尽管更复杂的解决方案。 - Cory Charlton

0

Kotlin + DataStore + androidx.Preference的解决方案

免责声明!

可能这不是正确的做法!
理想情况下,应该只需:

  • 将输入设置为int
  • 在类中覆盖: 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
  }
}

此外,在我的扩展了BaseSettingsActivity的Activity中,我使用以下代码替换了SharedPreferences的管理:
preferenceManager.preferenceDataStore = dataStoreCvLogger 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接