I'm trying to implement a custom Preference MyEditTextPreference whose summary is an EditText, as opposed to the default TextView (see preference.xml). This lets me edit the summary directly by tapping on it.
My problem is: in my use-case, I have 2 (or more) MyEditTextPreference with different summary texts and a SwitchPreference which toggles the preferences' visibility on / off.
When I toggle their visibility multiple times, at some point one of the MyEditTextPreference will have the summary of the other one.
example:
state: "summary 111" | "summary 222"
toggle visibility on & off
state: "summary 111" | "summary 222"
toggle visibility on & off
...
toggle visibility on & off
state: "summary 111" | "summary 111"
Can someone please tell me what is it that I am doing wrong, or not understanding here? all I know is under the hood the list of Preferences are stored in a RecyclerView, but I'm not sure what to do with this information or where to look deeper.
MyEditTextPreference.kt
package com.example.settingspreferences.widget
import android.content.Context
import android.text.Editable
import android.text.TextWatcher
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder
import com.example.settingspreferences.R
class MyEditTextPreference : Preference {
private var TAG = "ABC MSSEditTextPreference"
private var editText: EditText? = null
private var customSummary: CharSequence? = null
private var textWatcher: TextWatcher? = null
private var cursorPosition: Int = 0
constructor(context: Context) : super(context) {
layoutResource = R.layout.my_edittext_preference
TAG += "[$key]"
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
layoutResource = R.layout.my_edittext_preference
TAG += "[$key]"
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
layoutResource = R.layout.my_edittext_preference
TAG += "[$key]"
}
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes) {
layoutResource = R.layout.my_edittext_preference
TAG += "[$key]"
}
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)
editText = holder.findViewById(android.R.id.summary) as EditText
editText!!.visibility = View.VISIBLE
editText!!.imeOptions = EditorInfo.IME_ACTION_DONE
Log.d(TAG, "onBindViewHolder: editText.text = " + editText!!.text.toString())
if (customSummary != null) {
editText!!.setText(customSummary)
} else {
editText!!.setText("")
}
if (textWatcher != null) {
editText!!.removeTextChangedListener(textWatcher)
}
textWatcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
// Save the cursor position before text changed
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
// Update the custom summary when the text is changed
customSummary = s
}
override fun afterTextChanged(s: Editable?) {
// No action needed
}
}
editText!!.addTextChangedListener(textWatcher)
}
override fun getSummary(): CharSequence? {
Log.d(TAG, "getSummary: super.getSummary()=${super.getSummary()}, customSummary=${customSummary}")
return customSummary ?: super.getSummary()
}
override fun setSummary(summary: CharSequence?) {
Log.d(TAG, "setSummary: customSummary=$customSummary, summary=$summary")
customSummary = summary
super.setSummary(summary)
if (editText != null) {
editText!!.setText(customSummary)
}
}
}
my_edittext_preference.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:baselineAligned="false"
android:clipToPadding="true"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:orientation="vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@android:id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
tools:background="@color/black"
tools:src="@drawable/ic_accessibility_animation" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginTop="6dp"
android:layout_marginEnd="6dp"
android:layout_marginBottom="6dp"
android:layout_weight="1">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:hyphenationFrequency="normal"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
tools:text="Title" />
<EditText
android:id="@android:id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignStart="@android:id/title"
android:background="@null"
android:ellipsize="end"
android:hyphenationFrequency="normal"
android:inputType="textNoSuggestions"
android:lines="1"
android:maxLines="1"
android:minWidth="10dp"
android:paddingStart="2dp"
android:paddingTop="6dp"
android:paddingEnd="2dp"
android:paddingBottom="6dp"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
tools:text="summary" />
</RelativeLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginStart="54dp"
android:background="#404040" />
</LinearLayout>
MainActivity.kt (which launches SettingsFragment, which launches CustomSettingsFragment)
package com.example.settingspreferences
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.settings_container, SettingsFragment())
.commit()
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:id="@+id/settings_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" />
</androidx.constraintlayout.widget.ConstraintLayout>
SettingsFragment.kt
package com.example.settingspreferences
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}
R.xml.root_preferences
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="Custom Preferences">
<Preference
android:icon="@drawable/ic_ampos_settings_color_correction"
android:key="high_contrast_mode"
android:title="See custom preferences"
android:fragment="com.example.settingspreferences.CustomSettingsFragment" />
</PreferenceCategory>
</PreferenceScreen>
CustomSettingsFragment.kt
package com.example.settingspreferences
import android.os.Bundle
import android.text.InputType
import android.util.Log
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import com.example.settingspreferences.widget.MyEditTextPreference
class CustomSettingsFragment : PreferenceFragmentCompat() {
private val TAG = "ABC CustomSettingsFragment"
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.custom_preferences, rootKey)
val switchPreference = findPreference<SwitchPreference>("switch_make_visible")
val et1: MyEditTextPreference? = findPreference("cet1")
val et2: MyEditTextPreference? = findPreference("cet2")
et1!!.setSummary("Summary 1")
et2!!.setSummary("000000")
switchPreference!!.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { preference, newValue ->
val newVal = newValue as Boolean
et1.isVisible = !newVal
et2.isVisible = !newVal
true
}
}
}