MultiSelectListPreference checkboxes are not checked when they are not displayed in the list (API 23)

Given the SettingsActivity property using only the MultiSelectListPreference method with its entries, values, and default values ​​in the array resources, some flags do not appear as verified, although Android knows that they need to be checked. When you click on an unverified item, the item remains unchecked (because Android believes that it unchecked the checked item).

Here is a video of this event

The project is available here: https://github.com/ImmersibleElf/MSLPBug

It seems to work fine in APIs 21 and 22, but not in 23. Perhaps this is a bug in recycling views? Or what could be the reason?

SettingsActivity.java

package com.immersibleelf.mslpbug; import android.os.Bundle; import android.preference.PreferenceFragment; import android.support.v7.app.AppCompatActivity; public class SettingsActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Display the fragment as the main content. getFragmentManager().beginTransaction() .replace(android.R.id.content, new SettingsFragment()) .commit(); } @Override public void onPause() { super.onPause(); } public static class SettingsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the settings from an XML resource addPreferencesFromResource(R.xml.settings); } } } 

settings.xml

 <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <MultiSelectListPreference android:key="mslp_key" android:title="MultiSelectListPreference" android:entries="@array/mslp_entries" android:entryValues="@array/mslp_entry_values" android:defaultValue="@array/mslp_default_value" android:persistent="true" /> </PreferenceScreen> 

arrays.xml

 <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="mslp_entries"> <item>Entry 01</item> <item>Entry 02</item> <item>Entry 03</item> <item>Entry 04</item> <item>Entry 05</item> <item>Entry 06</item> <item>Entry 07</item> <item>Entry 08</item> <item>Entry 09</item> <item>Entry 10</item> <item>Entry 11</item> <item>Entry 12</item> <item>Entry 13</item> <item>Entry 14</item> <item>Entry 15</item> </string-array> <string-array name="mslp_entry_values"> <item>1</item> <item>2</item> <item>3</item> <item>4</item> <item>5</item> <item>6</item> <item>7</item> <item>8</item> <item>9</item> <item>10</item> <item>11</item> <item>12</item> <item>13</item> <item>14</item> <item>15</item> </string-array> <string-array name="mslp_default_value"> <item>1</item> <item>2</item> <item>3</item> <item>4</item> <item>5</item> <item>6</item> <item>7</item> <item>8</item> <item>9</item> <item>10</item> <item>11</item> <item>12</item> <item>13</item> <item>14</item> <item>15</item> </string-array> </resources> 
+6
source share
2 answers

The workaround is to subclass MultiSelectListPreference and overwrite the showDialog method as follows:

 @Override protected void showDialog(Bundle state) { super.showDialog(state); AlertDialog dialog = (AlertDialog)getDialog(); if (dialog == null) return; if (Build.VERSION.SDK_INT >= 23) { ListView listView = dialog.getListView(); listView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { int size = view.getChildCount(); for (int i=0; i<size; i++) { View v = view.getChildAt(i); if (v instanceof CheckedTextView) ((CheckedTextView)v).refreshDrawableState(); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { int size = view.getChildCount(); for (int i=0; i<size; i++) { View v = view.getChildAt(i); if (v instanceof CheckedTextView) ((CheckedTextView)v).refreshDrawableState(); } } }); } } 
+4
source

Excellent. This code works as mentioned above:

 import android.app.AlertDialog; import android.content.Context; import android.os.Build; import android.os.Bundle; import android.preference.MultiSelectListPreference; import android.util.AttributeSet; import android.view.View; import android.widget.AbsListView; import android.widget.CheckedTextView; import android.widget.ListView; /** * Android bug: https://code.google.com/p/android/issues/detail?id=205487 */ public class MultiSelectWrapper extends MultiSelectListPreference { public MultiSelectWrapper(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } public MultiSelectWrapper(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MultiSelectWrapper(Context context, AttributeSet attrs) { super(context, attrs); } public MultiSelectWrapper(Context context) { super(context); } @Override protected void showDialog(Bundle state) { super.showDialog(state); AlertDialog dialog = (AlertDialog)getDialog(); if (dialog == null) return; if (Build.VERSION.SDK_INT >= 23) { ListView listView = dialog.getListView(); listView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { int size = view.getChildCount(); for (int i=0; i<size; i++) { View v = view.getChildAt(i); if (v instanceof CheckedTextView) ((CheckedTextView)v).refreshDrawableState(); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { int size = view.getChildCount(); for (int i=0; i<size; i++) { View v = view.getChildAt(i); if (v instanceof CheckedTextView) ((CheckedTextView)v).refreshDrawableState(); } } }); } } } 
0
source

All Articles