可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I started dealing with preferences in a PreferenceFragment
. Here's what I have:
I'm trying to:
get rid of the dividers between items. I suppose this can be defined from styles, but I can't figure out how. I tried getting the
preference ListView
at runtime calling
findViewById(android.R.id.list)
, as I read somewhere, but it
returns null.
set new, full width dividers right on top of the headers, as seen here. For example in this case I want a full width divider right above "Statistiche", but not above "Generali" which is on top of the list.
The only way that comes to my mind is setting dividers as fake preferences, like with:
<Preference
android:layout="@layout/divider" //here I set width and a divider resource
/>
<PreferenceCategory ... />
The main issue here is that my PreferenceFragment
(or the ActionBarActivity
it's in) has some left/right padding, that make any divider I add into preferences.xml not cover the entire width.
So my question are:
How can I get rid of default, item-item dividers that you can see in the image?
How can I set full width dividers right above headers, or how can I get rid of internal fragment/activity padding? Of course my activity layout has no (explicit) padding whatsoever.
回答1:
Add this code under the PreferenceFragment
:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// remove dividers
View rootView = getView();
ListView list = (ListView) rootView.findViewById(android.R.id.list);
list.setDivider(null);
}
回答2:
AndroidX makes it simple, but I wish it was better documented.
In XML
To add/remove dividers between preferences in XML, use the following attributes:
<androidx.preference.PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto">
<Preference
...
app:allowDividerAbove="true/false"
app:allowDividerBelow="true/false"
... />
</androidx.preference.PreferenceScreen>
Note, a divider will only be shown between two preferences if the top divider has allowDividerBelow
set to true
and the bottom divider has allowDividerAbove
set to true
.
In Code
You can also change/remove dividers programmatically using the following methods in onActivityCreated
of your PreferenceFragmentCompat
:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// To remove:
setDivider(null);
// To change:
setDivider(ContextCompat.getDrawable(getActivity(), R.drawable.your_drawable));
setDividerHeight(your_height);
}
回答3:
Although a bit late I`m having same troubles with dividers in preff screen and found this solution:
Set custom style to the hosting activity and add to the style:
<item name="android:listDivider">@null</item>
It actually does the same as setting it trough code but you save one findById and i think it looks clearer set trough styles
回答4:
Had totally forgot about this question, will post an answer now to help others. I solved by moving my code in the onResume()
method of the activity that hosts my PreferenceFragment
. I think there are several other points at which you can recall a non-null ListView
using findViewById(android.R.id.list)
.
public boolean mListStyled;
@Override
public void onResume() {
super.onResume();
if (!mListStyled) {
View rootView = getView();
if (rootView != null) {
ListView list = (ListView) rootView.findViewById(android.R.id.list);
list.setPadding(0, 0, 0, 0);
list.setDivider(null);
//any other styling call
mListStyled = true;
}
}
}
You can probably get rid of the rootView
check, but at the same time you might even want to check for list != null
. I didn't face any NPE this way anyway.
So, setDivider(null)
takes off the item-item dividers. I managed to add section dividers covering the full width of the screen by:
- Removing padding from
list
;
- Adding a custom preference in my XML:
n
<Preference
android:title="divider"
android:selectable="false"
android:layout="@layout/preference_divider"/>
回答5:
For PreferenceFragmentCompat, ListView doesn't work.
But this works like a charm:
<style name="PrefsTheme" parent="PreferenceThemeOverlay.v14.Material">
<item name="android:divider">@null</item>
<item name="android:dividerHeight">0dp</item>
</style>
Add this to your app theme:
<item name="preferenceTheme">@style/PrefsTheme</item>
回答6:
I had this exact problem and wanted dividers between preference categories but not between the items themselves. I found that the accepted solution satisfied Question 1 by removing the dividers from preference items but did not fix question 2 and add the dividers between preference categories.
Fix below.
Basically override the onCreateAdapter method of your PreferenceFragmentCompat and give it a custom PreferenceGroupAdapter that has an overridden onBindViewHolder method that uses the position and whatever else you need to set above and below permissions for each view holder. A divider will be drawn when both viewholders allow a divider between them.
Here is my fix
public class SettingsFragment extends PreferenceFragmentCompat {
@Override
protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
return new CustomPreferenceGroupAdapter(preferenceScreen);
}
static class CustomPreferenceGroupAdapter extends PreferenceGroupAdapter {
@SuppressLint("RestrictedApi")
public CustomPreferenceGroupAdapter(PreferenceGroup preferenceGroup) {
super(preferenceGroup);
}
@SuppressLint("RestrictedApi")
@Override
public void onBindViewHolder(PreferenceViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
Preference currentPreference = getItem(position);
//For a preference category we want the divider shown above.
if(position != 0 && currentPreference instanceof PreferenceCategory) {
holder.setDividerAllowedAbove(true);
holder.setDividerAllowedBelow(false);
} else {
//For other dividers we do not want to show divider above
//but allow dividers below for CategoryPreference dividers.
holder.setDividerAllowedAbove(false);
holder.setDividerAllowedBelow(true);
}
}
}
回答7:
(AndroidX only)
Maksim Ivanov's answer got me most of the way there. But to remove dividers only for a specific Preference created in code, I had to do:
val pref = object : Preference(activity) {
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)
// By default, preferences created in code show dividers
holder.setDividerAllowedAbove(false)
holder.setDividerAllowedBelow(false)
}
}
回答8:
if you use a PreferenceFragment ,you can use ListView.setDivider(null)
;
if you use a PreferenceFragmentCompat ,you can use PreferenceFragmentCompat.setDivider(Drawable divider)
or setDividerHeight(int height)
;
回答9:
New solution for new android API 24 and above (December 25th, 2017).
I've found after try many ways on stackoverflow, but not work, or it just work but not work in nestest PreferenceScreen
.
Frist, you need to find listview from current displaying fragment, and remove the divider:
private fun removeDividerInCurrentFragment() {
this@YourPreferenceActivity.fragmentManager.findFragmentById(android.R.id.content)?.let {
it.view?.findViewById<ListView?>(android.R.id.list)?.let {
it.divider = null
it.dividerHeight = 0
}
}
}
Second, to remove the divider when fragment commited, call method above (removeDividerInCurrentFragment
) to remove listview's divider.
To sure if you have nestest PreferenceScreen
. Register listener when fragment changed in your PreferenceActivity
by implement FragmentManager.OnBackStackChangedListener
protocol:
class YourPreferenceActivity : PreferenceActivity(), FragmentManager.OnBackStackChangedListener {
override fun onBackStackChanged() {
this@YourPreferenceActivity.removeDividerInCurrentFragment()
}
}
Finally, register backstack changes listener by call fragmentManager.addOnBackStackChangedListener(this@ YourPreferenceActivity)
in onCreate
. And remove backstack changes listener by call fragmentManager.removeOnBackStackChangedListener
in onDestroyed
method.
Good luck!
回答10:
You can re-style your divider using this theme.
<style name="PreferenceFragment.Material">
<item name="android:divider">@drawable/preference_list_divider_material</item>
</style>