Add divider support to preference support lib
b/23902415
Change-Id: Ibfc2ec3bbc663d8866b027b9e8c6f8838dfd5a68
diff --git a/v14/preference/api/current.txt b/v14/preference/api/current.txt
index fed4623..5ebd7cf 100644
--- a/v14/preference/api/current.txt
+++ b/v14/preference/api/current.txt
@@ -60,6 +60,8 @@
method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+ method public void setDivider(android.graphics.drawable.Drawable);
+ method public void setDividerHeight(int);
method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
method public void setPreferencesFromResource(int, java.lang.String);
field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
diff --git a/v14/preference/res/drawable/preference_list_divider_material.xml b/v14/preference/res/drawable/preference_list_divider_material.xml
new file mode 100644
index 0000000..a5913de
--- /dev/null
+++ b/v14/preference/res/drawable/preference_list_divider_material.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:tint="?android:attr/colorForeground">
+ <solid android:color="#1f000000" />
+ <size
+ android:height="1dp"
+ android:width="1dp" />
+</shape>
diff --git a/v14/preference/res/values/attrs.xml b/v14/preference/res/values/attrs.xml
index 62d9e47..16f9699 100644
--- a/v14/preference/res/values/attrs.xml
+++ b/v14/preference/res/values/attrs.xml
@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2015 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
<resources>
<declare-styleable name="SwitchPreference">
@@ -52,4 +52,15 @@
<attr name="entryValues" />
<attr name="android:entryValues" />
</declare-styleable>
+
+ <!-- Base attributes available to PreferenceFragment. -->
+ <declare-styleable name="PreferenceFragment">
+ <!-- The layout for the PreferenceFragment. This should rarely need to be changed. -->
+ <attr name="android:layout" />
+ <!-- List separator to draw between preference views -->
+ <attr name="android:divider" />
+ <!-- List separator height -->
+ <attr name="android:dividerHeight" />
+ </declare-styleable>
+
</resources>
diff --git a/v14/preference/res/values/styles.xml b/v14/preference/res/values/styles.xml
index 8e1f255..c197121 100644
--- a/v14/preference/res/values/styles.xml
+++ b/v14/preference/res/values/styles.xml
@@ -74,6 +74,10 @@
<item name="android:textStyle">normal</item>
</style>
+ <style name="PreferenceFragment.Material">
+ <item name="android:divider">@drawable/preference_list_divider_material</item>
+ </style>
+
<style name="PreferenceFragmentList.Material">
<item name="android:paddingLeft">0dp</item>
<item name="android:paddingRight">0dp</item>
diff --git a/v14/preference/res/values/themes.xml b/v14/preference/res/values/themes.xml
index 6c1c93f..64bc91e 100644
--- a/v14/preference/res/values/themes.xml
+++ b/v14/preference/res/values/themes.xml
@@ -18,10 +18,13 @@
<resources>
<style name="PreferenceThemeOverlay.v14">
<item name="switchPreferenceStyle">@style/Preference.SwitchPreference</item>
+ <item name="preferenceFragmentStyle">@style/PreferenceFragment</item>
</style>
<style name="PreferenceThemeOverlay.v14.Material">
<item name="preferenceScreenStyle">@style/Preference.PreferenceScreen.Material</item>
+ <item name="preferenceFragmentCompatStyle">@style/PreferenceFragment.Material</item>
+ <item name="preferenceFragmentStyle">@style/PreferenceFragment.Material</item>
<item name="preferenceCategoryStyle">@style/Preference.Category.Material</item>
<item name="preferenceStyle">@style/Preference.Material</item>
<item name="preferenceInformationStyle">@style/Preference.Information.Material</item>
diff --git a/v14/preference/src/android/support/v14/preference/PreferenceFragment.java b/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
index 106f62d..29b6702 100644
--- a/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
+++ b/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
@@ -20,11 +20,15 @@
import android.app.Fragment;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.annotation.XmlRes;
+import android.support.v4.view.ViewCompat;
import android.support.v7.preference.DialogPreference;
import android.support.v7.preference.EditTextPreference;
import android.support.v7.preference.ListPreference;
@@ -32,6 +36,7 @@
import android.support.v7.preference.PreferenceGroupAdapter;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.PreferenceViewHolder;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
@@ -130,6 +135,8 @@
private int mLayoutResId = R.layout.preference_list_fragment;
+ private final DividerDecoration mDividerDecoration = new DividerDecoration();
+
private static final int MSG_BIND_PREFERENCES = 1;
private Handler mHandler = new Handler() {
@Override
@@ -234,12 +241,15 @@
Bundle savedInstanceState) {
TypedArray a = mStyledContext.obtainStyledAttributes(null,
- R.styleable.PreferenceFragmentCompat,
+ R.styleable.PreferenceFragment,
R.attr.preferenceFragmentStyle,
0);
- mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_layout,
- mLayoutResId);
+ mLayoutResId = a.getResourceId(R.styleable.PreferenceFragment_android_layout, mLayoutResId);
+
+ final Drawable divider = a.getDrawable(R.styleable.PreferenceFragment_android_divider);
+ final int dividerHeight = a.getInt(R.styleable.PreferenceFragment_android_dividerHeight,
+ -1);
a.recycle();
@@ -268,11 +278,44 @@
}
mList = listView;
+
+ listView.addItemDecoration(mDividerDecoration);
+ setDivider(divider);
+ if (dividerHeight != -1) {
+ setDividerHeight(dividerHeight);
+ }
+
listContainer.addView(mList);
mHandler.post(mRequestFocus);
return view;
}
+ /**
+ * Sets the drawable that will be drawn between each item in the list.
+ * <p>
+ * <strong>Note:</strong> If the drawable does not have an intrinsic
+ * height, you should also call {@link #setDividerHeight(int)}.
+ *
+ * @param divider the drawable to use
+ * @attr ref R.styleable#PreferenceFragment_divider
+ * @attr ref R.styleable#PreferenceFragment_android_divider
+ */
+ public void setDivider(Drawable divider) {
+ mDividerDecoration.setDivider(divider);
+ }
+
+ /**
+ * Sets the height of the divider that will be drawn between each item in the list. Calling
+ * this will override the intrinsic height as set by {@link #setDivider(Drawable)}
+ *
+ * @param height The new height of the divider in pixels.
+ * @attr ref R.styleable#PreferenceFragment_dividerHeight
+ * @attr ref R.styleable#PreferenceFragment_android_dividerHeight
+ */
+ public void setDividerHeight(int height) {
+ mDividerDecoration.setDividerHeight(height);
+ }
+
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -586,4 +629,78 @@
public Fragment getCallbackFragment() {
return null;
}
+
+ private class DividerDecoration extends RecyclerView.ItemDecoration {
+
+ private Drawable mDivider;
+ private int mDividerHeight;
+
+ @Override
+ public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
+ if (mDivider == null) {
+ return;
+ }
+ final int childCount = parent.getChildCount();
+ final int width = parent.getWidth();
+ for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
+ final View view = parent.getChildAt(childViewIndex);
+ if (shouldDrawDividerAbove(view, parent)) {
+ int top = (int) ViewCompat.getY(view);
+ mDivider.setBounds(0, top, width, top + mDividerHeight);
+ mDivider.draw(c);
+ }
+ if (shouldDrawDividerBelow(view, parent)) {
+ int top = (int) ViewCompat.getY(view) + view.getHeight();
+ mDivider.setBounds(0, top, width, top + mDividerHeight);
+ mDivider.draw(c);
+ }
+ }
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+ RecyclerView.State state) {
+ if (shouldDrawDividerAbove(view, parent)) {
+ outRect.top = mDividerHeight;
+ }
+ if (shouldDrawDividerBelow(view, parent)) {
+ outRect.bottom = mDividerHeight;
+ }
+ }
+
+ private boolean shouldDrawDividerAbove(View view, RecyclerView parent) {
+ final RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
+ return holder.getAdapterPosition() == 0 &&
+ ((PreferenceViewHolder) holder).isDividerAllowedAbove();
+ }
+
+ private boolean shouldDrawDividerBelow(View view, RecyclerView parent) {
+ final PreferenceViewHolder holder =
+ (PreferenceViewHolder) parent.getChildViewHolder(view);
+ boolean nextAllowed = true;
+ int index = parent.indexOfChild(view);
+ if (index < parent.getChildCount() - 1) {
+ final View nextView = parent.getChildAt(index + 1);
+ final PreferenceViewHolder nextHolder =
+ (PreferenceViewHolder) parent.getChildViewHolder(nextView);
+ nextAllowed = nextHolder.isDividerAllowedAbove();
+ }
+ return nextAllowed && holder.isDividerAllowedBelow();
+ }
+
+ public void setDivider(Drawable divider) {
+ if (divider != null) {
+ mDividerHeight = divider.getIntrinsicHeight();
+ } else {
+ mDividerHeight = 0;
+ }
+ mDivider = divider;
+ mList.invalidateItemDecorations();
+ }
+
+ public void setDividerHeight(int dividerHeight) {
+ mDividerHeight = dividerHeight;
+ mList.invalidateItemDecorations();
+ }
+ }
}
diff --git a/v17/preference-leanback/res/values/styles.xml b/v17/preference-leanback/res/values/styles.xml
index d52cd87..42d2b5b 100644
--- a/v17/preference-leanback/res/values/styles.xml
+++ b/v17/preference-leanback/res/values/styles.xml
@@ -62,6 +62,10 @@
<item name="android:dialogLayout">@layout/preference_dialog_edittext</item>
</style>
+ <style name="PreferenceFragment.Leanback">
+ <item name="android:divider">@null</item>
+ </style>
+
<style name="PreferenceFragmentList.Leanback">
<item name="android:paddingStart">0dp</item>
<item name="android:paddingEnd">0dp</item>
diff --git a/v17/preference-leanback/res/values/themes.xml b/v17/preference-leanback/res/values/themes.xml
index a34bc20..591fdfa 100644
--- a/v17/preference-leanback/res/values/themes.xml
+++ b/v17/preference-leanback/res/values/themes.xml
@@ -18,6 +18,8 @@
<resources>
<style name="PreferenceThemeOverlay.v14.Leanback">
<item name="preferenceScreenStyle">@style/LeanbackPreference.PreferenceScreen</item>
+ <item name="preferenceFragmentCompatStyle">@style/PreferenceFragment.Leanback</item>
+ <item name="preferenceFragmentStyle">@style/PreferenceFragment.Leanback</item>
<item name="preferenceCategoryStyle">@style/LeanbackPreference.Category</item>
<item name="preferenceStyle">@style/LeanbackPreference</item>
<item name="preferenceInformationStyle">@style/LeanbackPreference.Information</item>
diff --git a/v7/preference/api/current.txt b/v7/preference/api/current.txt
index 7d7aeb1..9034fd4 100644
--- a/v7/preference/api/current.txt
+++ b/v7/preference/api/current.txt
@@ -203,6 +203,8 @@
method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+ method public void setDivider(android.graphics.drawable.Drawable);
+ method public void setDividerHeight(int);
method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
method public void setPreferencesFromResource(int, java.lang.String);
field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
@@ -280,6 +282,10 @@
public class PreferenceViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
method public android.view.View findViewById(int);
+ method public boolean isDividerAllowedAbove();
+ method public boolean isDividerAllowedBelow();
+ method public void setDividerAllowedAbove(boolean);
+ method public void setDividerAllowedBelow(boolean);
}
public class SwitchPreferenceCompat extends android.support.v7.preference.TwoStatePreference {
diff --git a/v7/preference/res/values-v17/styles.xml b/v7/preference/res/values-v17/styles.xml
index 20168b2..2184354 100644
--- a/v7/preference/res/values-v17/styles.xml
+++ b/v7/preference/res/values-v17/styles.xml
@@ -19,6 +19,7 @@
<style name="PreferenceFragment">
<item name="android:paddingStart">0dp</item>
<item name="android:paddingEnd">0dp</item>
+ <item name="android:divider">?android:attr/listDivider</item>
</style>
<style name="PreferenceFragmentList">
diff --git a/v7/preference/res/values/attrs.xml b/v7/preference/res/values/attrs.xml
index b93c1e6..5d39b63 100644
--- a/v7/preference/res/values/attrs.xml
+++ b/v7/preference/res/values/attrs.xml
@@ -1,243 +1,248 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2015 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
<resources>
- <declare-styleable name="Theme">
+ <declare-styleable name="Theme">
- <!-- =================== -->
- <!-- Preference styles -->
- <!-- =================== -->
- <eat-comment />
+ <!-- =================== -->
+ <!-- Preference styles -->
+ <!-- =================== -->
+ <eat-comment />
- <!-- Theme for inflating Preference objects -->
- <attr name="preferenceTheme" format="reference" />
+ <!-- Theme for inflating Preference objects -->
+ <attr name="preferenceTheme" format="reference" />
- <!-- Default style for PreferenceScreen. -->
- <attr name="preferenceScreenStyle" format="reference" />
- <!-- Default style for the PreferenceActivity. -->
- <attr name="preferenceActivityStyle" format="reference" />
- <!-- Default style for Headers pane in PreferenceActivity. -->
- <attr name="preferenceFragmentStyle" format="reference" />
- <!-- Default style for PreferenceCategory. -->
- <attr name="preferenceCategoryStyle" format="reference" />
- <!-- Default style for Preference. -->
- <attr name="preferenceStyle" format="reference" />
- <!-- Default style for informational Preference. -->
- <attr name="preferenceInformationStyle" format="reference" />
- <!-- Default style for CheckBoxPreference. -->
- <attr name="checkBoxPreferenceStyle" format="reference" />
- <!-- Default style for YesNoPreference. -->
- <attr name="yesNoPreferenceStyle" format="reference" />
- <!-- Default style for DialogPreference. -->
- <attr name="dialogPreferenceStyle" format="reference" />
- <!-- Default style for EditTextPreference. -->
- <attr name="editTextPreferenceStyle" format="reference" />
- <!-- Default style for RingtonePreference. -->
- <attr name="ringtonePreferenceStyle" format="reference" />
- <!-- The preference layout that has the child/tabbed effect. -->
- <attr name="preferenceLayoutChild" format="reference" />
- <!-- Preference panel style -->
- <attr name="preferencePanelStyle" format="reference" />
- <!-- Preference headers panel style -->
- <attr name="preferenceHeaderPanelStyle" format="reference" />
- <!-- Preference list style -->
- <attr name="preferenceListStyle" format="reference" />
- <!-- Preference fragment list style -->
- <attr name="preferenceFragmentListStyle" format="reference" />
- <!-- Preference fragment padding side -->
- <attr name="preferenceFragmentPaddingSide" format="dimension" />
- <!-- Default style for switch preferences. -->
- <attr name="switchPreferenceStyle" format="reference" />
- <!-- Default style for switch compat preferences. -->
- <attr name="switchPreferenceCompatStyle" format="reference" />
- <!-- Default style for seekbar preferences. -->
- <attr name="seekBarPreferenceStyle" format="reference" />
- </declare-styleable>
+ <!-- Default style for PreferenceScreen. -->
+ <attr name="preferenceScreenStyle" format="reference" />
+ <!-- Default style for the PreferenceActivity. -->
+ <attr name="preferenceActivityStyle" format="reference" />
+ <!-- Default style for Headers pane in PreferenceActivity. -->
+ <attr name="preferenceFragmentStyle" format="reference" />
+ <!-- Default style for Headers pane in PreferenceActivity. -->
+ <attr name="preferenceFragmentCompatStyle" format="reference" />
+ <!-- Default style for PreferenceCategory. -->
+ <attr name="preferenceCategoryStyle" format="reference" />
+ <!-- Default style for Preference. -->
+ <attr name="preferenceStyle" format="reference" />
+ <!-- Default style for informational Preference. -->
+ <attr name="preferenceInformationStyle" format="reference" />
+ <!-- Default style for CheckBoxPreference. -->
+ <attr name="checkBoxPreferenceStyle" format="reference" />
+ <!-- Default style for YesNoPreference. -->
+ <attr name="yesNoPreferenceStyle" format="reference" />
+ <!-- Default style for DialogPreference. -->
+ <attr name="dialogPreferenceStyle" format="reference" />
+ <!-- Default style for EditTextPreference. -->
+ <attr name="editTextPreferenceStyle" format="reference" />
+ <!-- Default style for RingtonePreference. -->
+ <attr name="ringtonePreferenceStyle" format="reference" />
+ <!-- The preference layout that has the child/tabbed effect. -->
+ <attr name="preferenceLayoutChild" format="reference" />
+ <!-- Preference panel style -->
+ <attr name="preferencePanelStyle" format="reference" />
+ <!-- Preference headers panel style -->
+ <attr name="preferenceHeaderPanelStyle" format="reference" />
+ <!-- Preference list style -->
+ <attr name="preferenceListStyle" format="reference" />
+ <!-- Preference fragment list style -->
+ <attr name="preferenceFragmentListStyle" format="reference" />
+ <!-- Preference fragment padding side -->
+ <attr name="preferenceFragmentPaddingSide" format="dimension" />
+ <!-- Default style for switch preferences. -->
+ <attr name="switchPreferenceStyle" format="reference" />
+ <!-- Default style for switch compat preferences. -->
+ <attr name="switchPreferenceCompatStyle" format="reference" />
+ <!-- Default style for seekbar preferences. -->
+ <attr name="seekBarPreferenceStyle" format="reference" />
+ </declare-styleable>
- <!-- Base attributes available to PreferenceFragment. -->
- <declare-styleable name="PreferenceFragmentCompat">
- <!-- The layout for the PreferenceFragment. This should rarely need to be changed. -->
- <attr name="layout" />
- <attr name="android:layout" />
- </declare-styleable>
+ <!-- Base attributes available to PreferenceFragment. -->
+ <declare-styleable name="PreferenceFragmentCompat">
+ <!-- The layout for the PreferenceFragment. This should rarely need to be changed. -->
+ <attr name="android:layout" />
+ <!-- List separator to draw between preference views -->
+ <attr name="android:divider" />
+ <!-- List separator height -->
+ <attr name="android:dividerHeight" />
+ </declare-styleable>
- <!-- Base attributes available to PreferenceGroup. -->
- <declare-styleable name="PreferenceGroup">
- <!-- Whether to order the Preference under this group as they appear in the XML file.
- If this is false, the ordering will follow the Preference order attribute and
- default to alphabetic for those without the order attribute. -->
- <attr name="orderingFromXml" format="boolean" />
- <attr name="android:orderingFromXml" />
- </declare-styleable>
+ <!-- Base attributes available to PreferenceGroup. -->
+ <declare-styleable name="PreferenceGroup">
+ <!-- Whether to order the Preference under this group as they appear in the XML file.
+ If this is false, the ordering will follow the Preference order attribute and
+ default to alphabetic for those without the order attribute. -->
+ <attr name="orderingFromXml" format="boolean" />
+ <attr name="android:orderingFromXml" />
+ </declare-styleable>
- <!-- Base attributes available to Preference. -->
- <declare-styleable name="Preference">
- <!-- The optional icon for the preference -->
- <attr name="icon" />
- <attr name="android:icon" />
- <!-- The key to store the Preference value. -->
- <attr name="key" format="string" />
- <attr name="android:key" />
- <!-- The title for the Preference in a PreferenceActivity screen. -->
- <attr name="title" />
- <attr name="android:title" />
- <!-- The summary for the Preference in a PreferenceActivity screen. -->
- <attr name="summary" format="string" />
- <attr name="android:summary" />
- <!-- The order for the Preference (lower values are to be ordered first). If this is not
- specified, the default ordering will be alphabetic. -->
- <attr name="order" format="integer" />
- <attr name="android:order" />
- <!-- When used inside of a modern PreferenceActivity, this declares
- a new PreferenceFragment to be shown when the user selects this item. -->
- <attr name="fragment" format="string" />
- <attr name="android:fragment" />
- <!-- The layout for the Preference in a PreferenceActivity screen. This should
- rarely need to be changed, look at widgetLayout instead. -->
- <attr name="layout" />
- <attr name="android:layout" />
- <!-- The layout for the controllable widget portion of a Preference. This is inflated
- into the layout for a Preference and should be used more frequently than
- the layout attribute. For example, a checkbox preference would specify
- a custom layout (consisting of just the CheckBox) here. -->
- <attr name="widgetLayout" format="reference" />
- <attr name="android:widgetLayout" />
- <!-- Whether the Preference is enabled. -->
- <attr name="enabled" format="boolean" />
- <attr name="android:enabled" />
- <!-- Whether the Preference is selectable. -->
- <attr name="selectable" format="boolean" />
- <attr name="android:selectable" />
- <!-- The key of another Preference that this Preference will depend on. If the other
- Preference is not set or is off, this Preference will be disabled. -->
- <attr name="dependency" format="string" />
- <attr name="android:dependency" />
- <!-- Whether the Preference stores its value to the shared preferences. -->
- <attr name="persistent" format="boolean" />
- <attr name="android:persistent" />
- <!-- The default value for the preference, which will be set either if persistence
- is off or persistence is on and the preference is not found in the persistent
- storage. -->
- <attr name="defaultValue" format="string|boolean|integer|reference|float" />
- <attr name="android:defaultValue" />
- <!-- Whether the view of this Preference should be disabled when
- this Preference is disabled. -->
- <attr name="shouldDisableView" format="boolean" />
- <attr name="android:shouldDisableView" />
- </declare-styleable>
+ <!-- Base attributes available to Preference. -->
+ <declare-styleable name="Preference">
+ <!-- The optional icon for the preference -->
+ <attr name="icon" />
+ <attr name="android:icon" />
+ <!-- The key to store the Preference value. -->
+ <attr name="key" format="string" />
+ <attr name="android:key" />
+ <!-- The title for the Preference in a PreferenceActivity screen. -->
+ <attr name="title" />
+ <attr name="android:title" />
+ <!-- The summary for the Preference in a PreferenceActivity screen. -->
+ <attr name="summary" format="string" />
+ <attr name="android:summary" />
+ <!-- The order for the Preference (lower values are to be ordered first). If this is not
+ specified, the default ordering will be alphabetic. -->
+ <attr name="order" format="integer" />
+ <attr name="android:order" />
+ <!-- When used inside of a modern PreferenceActivity, this declares
+ a new PreferenceFragment to be shown when the user selects this item. -->
+ <attr name="fragment" format="string" />
+ <attr name="android:fragment" />
+ <!-- The layout for the Preference in a PreferenceActivity screen. This should
+ rarely need to be changed, look at widgetLayout instead. -->
+ <attr name="layout" />
+ <attr name="android:layout" />
+ <!-- The layout for the controllable widget portion of a Preference. This is inflated
+ into the layout for a Preference and should be used more frequently than
+ the layout attribute. For example, a checkbox preference would specify
+ a custom layout (consisting of just the CheckBox) here. -->
+ <attr name="widgetLayout" format="reference" />
+ <attr name="android:widgetLayout" />
+ <!-- Whether the Preference is enabled. -->
+ <attr name="enabled" format="boolean" />
+ <attr name="android:enabled" />
+ <!-- Whether the Preference is selectable. -->
+ <attr name="selectable" format="boolean" />
+ <attr name="android:selectable" />
+ <!-- The key of another Preference that this Preference will depend on. If the other
+ Preference is not set or is off, this Preference will be disabled. -->
+ <attr name="dependency" format="string" />
+ <attr name="android:dependency" />
+ <!-- Whether the Preference stores its value to the shared preferences. -->
+ <attr name="persistent" format="boolean" />
+ <attr name="android:persistent" />
+ <!-- The default value for the preference, which will be set either if persistence
+ is off or persistence is on and the preference is not found in the persistent
+ storage. -->
+ <attr name="defaultValue" format="string|boolean|integer|reference|float" />
+ <attr name="android:defaultValue" />
+ <!-- Whether the view of this Preference should be disabled when
+ this Preference is disabled. -->
+ <attr name="shouldDisableView" format="boolean" />
+ <attr name="android:shouldDisableView" />
+ </declare-styleable>
- <!-- Base attributes available to CheckBoxPreference. -->
- <declare-styleable name="CheckBoxPreference">
- <!-- The summary for the Preference in a PreferenceActivity screen when the
- CheckBoxPreference is checked. If separate on/off summaries are not
- needed, the summary attribute can be used instead. -->
- <attr name="summaryOn" format="string" />
- <attr name="android:summaryOn" />
- <!-- The summary for the Preference in a PreferenceActivity screen when the
- CheckBoxPreference is unchecked. If separate on/off summaries are not
- needed, the summary attribute can be used instead. -->
- <attr name="summaryOff" format="string" />
- <attr name="android:summaryOff" />
- <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
- dependents will be disabled when this is unchecked, so the value of this preference is false. -->
- <attr name="disableDependentsState" format="boolean" />
- <attr name="android:disableDependentsState" />
- </declare-styleable>
+ <!-- Base attributes available to CheckBoxPreference. -->
+ <declare-styleable name="CheckBoxPreference">
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ CheckBoxPreference is checked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOn" format="string" />
+ <attr name="android:summaryOn" />
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ CheckBoxPreference is unchecked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOff" format="string" />
+ <attr name="android:summaryOff" />
+ <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
+ dependents will be disabled when this is unchecked, so the value of this preference is false. -->
+ <attr name="disableDependentsState" format="boolean" />
+ <attr name="android:disableDependentsState" />
+ </declare-styleable>
- <!-- Base attributes available to DialogPreference. -->
- <declare-styleable name="DialogPreference">
- <!-- The title in the dialog. -->
- <attr name="dialogTitle" format="string" />
- <attr name="android:dialogTitle" />
- <!-- The message in the dialog. If a dialogLayout is provided and contains
- a TextView with ID android:id/message, this message will be placed in there. -->
- <attr name="dialogMessage" format="string" />
- <attr name="android:dialogMessage" />
- <!-- The icon for the dialog. -->
- <attr name="dialogIcon" format="reference" />
- <attr name="android:dialogIcon" />
- <!-- The positive button text for the dialog. Set to @null to hide the positive button. -->
- <attr name="positiveButtonText" format="string" />
- <attr name="android:positiveButtonText" />
- <!-- The negative button text for the dialog. Set to @null to hide the negative button. -->
- <attr name="negativeButtonText" format="string" />
- <attr name="android:negativeButtonText" />
- <!-- A layout to be used as the content View for the dialog. By default, this shouldn't
- be needed. If a custom DialogPreference is required, this should be set. For example,
- the EditTextPreference uses a layout with an EditText as this attribute. -->
- <attr name="dialogLayout" format="reference" />
- <attr name="android:dialogLayout" />
- </declare-styleable>
+ <!-- Base attributes available to DialogPreference. -->
+ <declare-styleable name="DialogPreference">
+ <!-- The title in the dialog. -->
+ <attr name="dialogTitle" format="string" />
+ <attr name="android:dialogTitle" />
+ <!-- The message in the dialog. If a dialogLayout is provided and contains
+ a TextView with ID android:id/message, this message will be placed in there. -->
+ <attr name="dialogMessage" format="string" />
+ <attr name="android:dialogMessage" />
+ <!-- The icon for the dialog. -->
+ <attr name="dialogIcon" format="reference" />
+ <attr name="android:dialogIcon" />
+ <!-- The positive button text for the dialog. Set to @null to hide the positive button. -->
+ <attr name="positiveButtonText" format="string" />
+ <attr name="android:positiveButtonText" />
+ <!-- The negative button text for the dialog. Set to @null to hide the negative button. -->
+ <attr name="negativeButtonText" format="string" />
+ <attr name="android:negativeButtonText" />
+ <!-- A layout to be used as the content View for the dialog. By default, this shouldn't
+ be needed. If a custom DialogPreference is required, this should be set. For example,
+ the EditTextPreference uses a layout with an EditText as this attribute. -->
+ <attr name="dialogLayout" format="reference" />
+ <attr name="android:dialogLayout" />
+ </declare-styleable>
- <!-- Base attributes available to ListPreference. -->
- <declare-styleable name="ListPreference">
- <!-- The human-readable array to present as a list. Each entry must have a corresponding
- index in entryValues. -->
- <attr name="entries" format="reference" />
- <attr name="android:entries" />
- <!-- The array to find the value to save for a preference when an entry from
- entries is selected. If a user clicks on the second item in entries, the
- second item in this array will be saved to the preference. -->
- <attr name="entryValues" format="reference" />
- <attr name="android:entryValues" />
- </declare-styleable>
+ <!-- Base attributes available to ListPreference. -->
+ <declare-styleable name="ListPreference">
+ <!-- The human-readable array to present as a list. Each entry must have a corresponding
+ index in entryValues. -->
+ <attr name="entries" format="reference" />
+ <attr name="android:entries" />
+ <!-- The array to find the value to save for a preference when an entry from
+ entries is selected. If a user clicks on the second item in entries, the
+ second item in this array will be saved to the preference. -->
+ <attr name="entryValues" format="reference" />
+ <attr name="android:entryValues" />
+ </declare-styleable>
- <declare-styleable name="MultiSelectListPreference">
- <!-- The human-readable array to present as a list. Each entry must have a corresponding
- index in entryValues. -->
- <attr name="entries" />
- <attr name="android:entries" />
- <!-- The array to find the value to save for a preference when an entry from
- entries is selected. If a user clicks the second item in entries, the
- second item in this array will be saved to the preference. -->
- <attr name="entryValues" />
- <attr name="android:entryValues" />
- </declare-styleable>
+ <declare-styleable name="MultiSelectListPreference">
+ <!-- The human-readable array to present as a list. Each entry must have a corresponding
+ index in entryValues. -->
+ <attr name="entries" />
+ <attr name="android:entries" />
+ <!-- The array to find the value to save for a preference when an entry from
+ entries is selected. If a user clicks the second item in entries, the
+ second item in this array will be saved to the preference. -->
+ <attr name="entryValues" />
+ <attr name="android:entryValues" />
+ </declare-styleable>
- <declare-styleable name="SwitchPreferenceCompat">
- <!-- The summary for the Preference in a PreferenceActivity screen when the
- SwitchPreference is checked. If separate on/off summaries are not
- needed, the summary attribute can be used instead. -->
- <attr name="summaryOn" />
- <attr name="android:summaryOn" />
- <!-- The summary for the Preference in a PreferenceActivity screen when the
- SwitchPreference is unchecked. If separate on/off summaries are not
- needed, the summary attribute can be used instead. -->
- <attr name="summaryOff" />
- <attr name="android:summaryOff" />
- <!-- The text used on the switch itself when in the "on" state.
- This should be a very SHORT string, as it appears in a small space. -->
- <attr name="switchTextOn" format="string" />
- <attr name="android:switchTextOn" />
- <!-- The text used on the switch itself when in the "off" state.
- This should be a very SHORT string, as it appears in a small space. -->
- <attr name="switchTextOff" format="string" />
- <attr name="android:switchTextOff" />
- <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
- dependents will be disabled when this is unchecked, so the value of this preference is false. -->
- <attr name="disableDependentsState" />
- <attr name="android:disableDependentsState" />
- </declare-styleable>
+ <declare-styleable name="SwitchPreferenceCompat">
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ SwitchPreference is checked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOn" />
+ <attr name="android:summaryOn" />
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ SwitchPreference is unchecked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOff" />
+ <attr name="android:summaryOff" />
+ <!-- The text used on the switch itself when in the "on" state.
+ This should be a very SHORT string, as it appears in a small space. -->
+ <attr name="switchTextOn" format="string" />
+ <attr name="android:switchTextOn" />
+ <!-- The text used on the switch itself when in the "off" state.
+ This should be a very SHORT string, as it appears in a small space. -->
+ <attr name="switchTextOff" format="string" />
+ <attr name="android:switchTextOff" />
+ <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
+ dependents will be disabled when this is unchecked, so the value of this preference is false. -->
+ <attr name="disableDependentsState" />
+ <attr name="android:disableDependentsState" />
+ </declare-styleable>
- <declare-styleable name="PreferenceImageView">
- <attr name="maxWidth" format="dimension" />
- <attr name="android:maxWidth" />
- <attr name="maxHeight" format="dimension" />
- <attr name="android:maxHeight" />
- </declare-styleable>
+ <declare-styleable name="PreferenceImageView">
+ <attr name="maxWidth" format="dimension" />
+ <attr name="android:maxWidth" />
+ <attr name="maxHeight" format="dimension" />
+ <attr name="android:maxHeight" />
+ </declare-styleable>
</resources>
diff --git a/v7/preference/res/values/styles.xml b/v7/preference/res/values/styles.xml
index 4f34f1b..774c0c9 100644
--- a/v7/preference/res/values/styles.xml
+++ b/v7/preference/res/values/styles.xml
@@ -23,6 +23,7 @@
<style name="PreferenceFragment">
<item name="android:paddingLeft">0dp</item>
<item name="android:paddingRight">0dp</item>
+ <item name="android:divider">?android:attr/listDivider</item>
</style>
<style name="Preference.Information">
diff --git a/v7/preference/res/values/themes.xml b/v7/preference/res/values/themes.xml
index c2c2c3c..8a7eaa3 100644
--- a/v7/preference/res/values/themes.xml
+++ b/v7/preference/res/values/themes.xml
@@ -18,7 +18,7 @@
<resources>
<style name="PreferenceThemeOverlay">
<item name="preferenceScreenStyle">@style/Preference.PreferenceScreen</item>
- <item name="preferenceFragmentStyle">@style/PreferenceFragment</item>
+ <item name="preferenceFragmentCompatStyle">@style/PreferenceFragment</item>
<item name="preferenceCategoryStyle">@style/Preference.Category</item>
<item name="preferenceStyle">@style/Preference</item>
<item name="preferenceInformationStyle">@style/Preference.Information</item>
diff --git a/v7/preference/src/android/support/v7/preference/Preference.java b/v7/preference/src/android/support/v7/preference/Preference.java
index 4f210ae..1460005 100644
--- a/v7/preference/src/android/support/v7/preference/Preference.java
+++ b/v7/preference/src/android/support/v7/preference/Preference.java
@@ -516,6 +516,9 @@
} else {
setEnabledStateOnViews(holder.itemView, true);
}
+
+ holder.setDividerAllowedAbove(isEnabled());
+ holder.setDividerAllowedBelow(isEnabled());
}
/**
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java b/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
index 503fc9b..4289473 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
@@ -18,6 +18,9 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -25,6 +28,7 @@
import android.support.annotation.XmlRes;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
+import android.support.v4.view.ViewCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
@@ -123,6 +127,8 @@
private int mLayoutResId = R.layout.preference_list_fragment;
+ private final DividerDecoration mDividerDecoration = new DividerDecoration();
+
private static final int MSG_BIND_PREFERENCES = 1;
private Handler mHandler = new Handler() {
@Override
@@ -228,12 +234,17 @@
TypedArray a = mStyledContext.obtainStyledAttributes(null,
R.styleable.PreferenceFragmentCompat,
- R.attr.preferenceFragmentStyle,
+ R.attr.preferenceFragmentCompatStyle,
0);
- mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_layout,
+ mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_android_layout,
mLayoutResId);
+ final Drawable divider = a.getDrawable(
+ R.styleable.PreferenceFragmentCompat_android_divider);
+ final int dividerHeight = a.getInt(
+ R.styleable.PreferenceFragmentCompat_android_dividerHeight, -1);
+
a.recycle();
// Need to theme the inflater to pick up the preferenceFragmentListStyle
@@ -261,11 +272,44 @@
}
mList = listView;
+
+ listView.addItemDecoration(mDividerDecoration);
+ setDivider(divider);
+ if (dividerHeight != -1) {
+ setDividerHeight(dividerHeight);
+ }
+
listContainer.addView(mList);
mHandler.post(mRequestFocus);
return view;
}
+ /**
+ * Sets the drawable that will be drawn between each item in the list.
+ * <p>
+ * <strong>Note:</strong> If the drawable does not have an intrinsic
+ * height, you should also call {@link #setDividerHeight(int)}.
+ *
+ * @param divider the drawable to use
+ * @attr ref R.styleable#PreferenceFragmentCompat_divider
+ * @attr ref R.styleable#PreferenceFragmentCompat_android_divider
+ */
+ public void setDivider(Drawable divider) {
+ mDividerDecoration.setDivider(divider);
+ }
+
+ /**
+ * Sets the height of the divider that will be drawn between each item in the list. Calling
+ * this will override the intrinsic height as set by {@link #setDivider(Drawable)}
+ *
+ * @param height The new height of the divider in pixels.
+ * @attr ref R.styleable#PreferenceFragmentCompat_dividerHeight
+ * @attr ref R.styleable#PreferenceFragmentCompat_android_dividerHeight
+ */
+ public void setDividerHeight(int height) {
+ mDividerDecoration.setDividerHeight(height);
+ }
+
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -577,4 +621,78 @@
public Fragment getCallbackFragment() {
return null;
}
+
+ private class DividerDecoration extends RecyclerView.ItemDecoration {
+
+ private Drawable mDivider;
+ private int mDividerHeight;
+
+ @Override
+ public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
+ if (mDivider == null) {
+ return;
+ }
+ final int childCount = parent.getChildCount();
+ final int width = parent.getWidth();
+ for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
+ final View view = parent.getChildAt(childViewIndex);
+ if (shouldDrawDividerAbove(view, parent)) {
+ int top = (int) ViewCompat.getY(view);
+ mDivider.setBounds(0, top, width, top + mDividerHeight);
+ mDivider.draw(c);
+ }
+ if (shouldDrawDividerBelow(view, parent)) {
+ int top = (int) ViewCompat.getY(view) + view.getHeight();
+ mDivider.setBounds(0, top, width, top + mDividerHeight);
+ mDivider.draw(c);
+ }
+ }
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+ RecyclerView.State state) {
+ if (shouldDrawDividerAbove(view, parent)) {
+ outRect.top = mDividerHeight;
+ }
+ if (shouldDrawDividerBelow(view, parent)) {
+ outRect.bottom = mDividerHeight;
+ }
+ }
+
+ private boolean shouldDrawDividerAbove(View view, RecyclerView parent) {
+ final RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
+ return holder.getAdapterPosition() == 0 &&
+ ((PreferenceViewHolder) holder).isDividerAllowedAbove();
+ }
+
+ private boolean shouldDrawDividerBelow(View view, RecyclerView parent) {
+ final PreferenceViewHolder holder =
+ (PreferenceViewHolder) parent.getChildViewHolder(view);
+ boolean nextAllowed = true;
+ int index = parent.indexOfChild(view);
+ if (index < parent.getChildCount() - 1) {
+ final View nextView = parent.getChildAt(index + 1);
+ final PreferenceViewHolder nextHolder =
+ (PreferenceViewHolder) parent.getChildViewHolder(nextView);
+ nextAllowed = nextHolder.isDividerAllowedAbove();
+ }
+ return nextAllowed && holder.isDividerAllowedBelow();
+ }
+
+ public void setDivider(Drawable divider) {
+ if (divider != null) {
+ mDividerHeight = divider.getIntrinsicHeight();
+ } else {
+ mDividerHeight = 0;
+ }
+ mDivider = divider;
+ mList.invalidateItemDecorations();
+ }
+
+ public void setDividerHeight(int dividerHeight) {
+ mDividerHeight = dividerHeight;
+ mList.invalidateItemDecorations();
+ }
+ }
}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java b/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
index c7e247c..f9eaf22 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
@@ -28,6 +28,8 @@
*/
public class PreferenceViewHolder extends RecyclerView.ViewHolder {
private final SparseArray<View> mCachedViews = new SparseArray<>(4);
+ private boolean mDividerAllowedAbove;
+ private boolean mDividerAllowedBelow;
/* package */ PreferenceViewHolder(View itemView) {
super(itemView);
@@ -58,4 +60,44 @@
return v;
}
}
+
+ /**
+ * Dividers are only drawn between items if both items allow it, or above the first and below
+ * the last item if that item allows it.
+ *
+ * @return true if dividers are allowed above this item
+ */
+ public boolean isDividerAllowedAbove() {
+ return mDividerAllowedAbove;
+ }
+
+ /**
+ * Dividers are only drawn between items if both items allow it, or above the first and below
+ * the last item if that item allows it.
+ *
+ * @param allowed false to prevent dividers being drawn above this item
+ */
+ public void setDividerAllowedAbove(boolean allowed) {
+ mDividerAllowedAbove = allowed;
+ }
+
+ /**
+ * Dividers are only drawn between items if both items allow it, or above the first and below
+ * the last item if that item allows it.
+ *
+ * @return true if dividers are allowed below this item
+ */
+ public boolean isDividerAllowedBelow() {
+ return mDividerAllowedBelow;
+ }
+
+ /**
+ * Dividers are only drawn between items if both items allow it, or above the first and below
+ * the last item if that item allows it.
+ *
+ * @param allowed false to prevent dividers being drawn below this item
+ */
+ public void setDividerAllowedBelow(boolean allowed) {
+ mDividerAllowedBelow = allowed;
+ }
}