最初在列表中不可见时未选中 MultiSelectListPreference 复选框 (API 23)
MultiSelectListPreference checkboxes not checked when not initially visible in list (API 23)
给定一个仅包含 MultiSelectListPreference 及其数组资源中的条目、值和默认值的 SettingsActivity,尽管 Android 知道它们应该被选中,但某些复选框并未绘制为已选中。单击未选中的项目时,该项目保持未选中状态(因为 Android 认为它正在取消选中已选中的项目)。
Here's a video of this happening
此处提供项目:https://github.com/ImmersibleElf/MSLPBug
它似乎在 API 21 和 22 中工作正常,但在 23 中不行。这可能是视图回收中的错误?或者可能是什么原因?
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>
解决方法是创建 MultiSelectListPreference 的子 class 并像这样覆盖方法 showDialog:
@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();
}
}
});
}
}
非常好。此代码的工作方式与 mdiener 提到的一样:
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();
}
}
});
}
}
}
给定一个仅包含 MultiSelectListPreference 及其数组资源中的条目、值和默认值的 SettingsActivity,尽管 Android 知道它们应该被选中,但某些复选框并未绘制为已选中。单击未选中的项目时,该项目保持未选中状态(因为 Android 认为它正在取消选中已选中的项目)。
Here's a video of this happening
此处提供项目:https://github.com/ImmersibleElf/MSLPBug
它似乎在 API 21 和 22 中工作正常,但在 23 中不行。这可能是视图回收中的错误?或者可能是什么原因?
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>
解决方法是创建 MultiSelectListPreference 的子 class 并像这样覆盖方法 showDialog:
@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();
}
}
});
}
}
非常好。此代码的工作方式与 mdiener 提到的一样:
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();
}
}
});
}
}
}