preference菜单要在PreferenceFragment中使用,但是这个过期了,最新的建议使用PreferenceFragmentCompat。androidx需要引入的库为
androidx.preference:preference:1.2.0
public abstract class PreferenceFragmentCompat extends Fragment implements...
集成自Fragment,所以我们可以按照Fragment的生命周期来分析。
1、先看onCreate
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final TypedValue tv = new TypedValue();
//设置主题
requireContext().getTheme().resolveAttribute(R.attr.preferenceTheme, tv, true);
int theme = tv.resourceId;
//preferenceTheme为空时使用PreferenceThemeOverlay
if (theme == 0) {
// Fallback to default theme.
theme = R.style.PreferenceThemeOverlay;
}
requireContext().getTheme().applyStyle(theme, false);
//PreferenceManager是一个重要的类,需要使用它来管理Preference组件
mPreferenceManager = new PreferenceManager(requireContext());
mPreferenceManager.setOnNavigateToScreenListener(this);
final Bundle args = getArguments();
final String rootKey;
if (args != null) {
rootKey = getArguments().getString(ARG_PREFERENCE_ROOT);
} else {
rootKey = null;
}
//子类可以在这里面通过 setPreferenceScreen(PreferenceScreen)或 addPreferencesFromResource(int)将Preference提供给当前Fragment
onCreatePreferences(savedInstanceState, rootKey);
}
2、接下来就是onCreateView了
private int mLayoutResId = R.layout.preference_list_fragment;//默认使用布局
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
/*使用preferenceFragmentCompatStyle主题样式,通过以下方式设置主题
<item name="preferenceFragmentCompatStyle">@style/SettingsPreferenceFragmentStyle</item>
*/
TypedArray a = requireContext().obtainStyledAttributes(null,
R.styleable.PreferenceFragmentCompat,
R.attr.preferenceFragmentCompatStyle,
0);
//确定布局,这里面有一个重要的位置list_container,preference要加在这里
mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_android_layout,
mLayoutResId);
.
.
.
final View view = themedInflater.inflate(mLayoutResId, container, false);
//获取list_container
final View rawListContainer = view.findViewById(AndroidResources.ANDROID_R_LIST_CONTAINER);
if (!(rawListContainer instanceof ViewGroup)) {
throw new IllegalStateException("Content has view with id attribute "
+ "'android.R.id.list_container' that is not a ViewGroup class");
}
final ViewGroup listContainer = (ViewGroup) rawListContainer;
//创造RecyclerView
final RecyclerView listView = onCreateRecyclerView(themedInflater, listContainer,
savedInstanceState);
if (listView == null) {
throw new RuntimeException("Could not create RecyclerView");
}
mList = listView;
//设置divider
listView.addItemDecoration(mDividerDecoration);
setDivider(divider);
if (dividerHeight != -1) {
setDividerHeight(dividerHeight);
}
mDividerDecoration.setAllowDividerAfterLastItem(allowDividerAfterLastItem);
// If mList isn't present in the view hierarchy, add it. mList is automatically inflated
// on an Auto device so don't need to add it.
//将RecyclerView加入到list_container
if (mList.getParent() == null) {
listContainer.addView(mList);
}
mHandler.post(mRequestFocus);
return view;
}
3、默认布局preference_list_fragment.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="NewApi"
android:orientation="vertical"
android:layout_height="match_parent"
android:layout_width="match_parent" >
<!--recyclerview通过addView加入到这里,RecyclerView里面是Preference-->
<FrameLayout
android:id="@android:id/list_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp"
android:gravity="center"
android:visibility="gone" />
</LinearLayout>
4、onCreateRecyclerView
public RecyclerView onCreateRecyclerView(@NonNull LayoutInflater inflater,
@NonNull ViewGroup parent, @Nullable Bundle savedInstanceState) {
// If device detected is Auto, use Auto's custom layout that contains a custom ViewGroup
// wrapping a RecyclerView
if (requireContext().getPackageManager().hasSystemFeature(PackageManager
.FEATURE_AUTOMOTIVE)) {
RecyclerView recyclerView = parent.findViewById(R.id.recycler_view);
if (recyclerView != null) {
return recyclerView;
}
}
//默认RecyclerView布局为preference_recyclerview
RecyclerView recyclerView = (RecyclerView) inflater
.inflate(R.layout.preference_recyclerview, parent, false);
//设置排布方式,默认为LinearLayoutManager,子类可以改成Grid或者瀑布流排布
recyclerView.setLayoutManager(onCreateLayoutManager());
recyclerView.setAccessibilityDelegateCompat(
new PreferenceRecyclerViewAccessibilityDelegate(recyclerView));
return recyclerView;
}
public RecyclerView.LayoutManager onCreateLayoutManager() {
return new LinearLayoutManager(requireContext());
}
5、其他重要的方法:
解析preferce菜单的xml文件,该xml根节点应该为PreferenceScreen
public void addPreferencesFromResource(@XmlRes int preferencesResId) {
requirePreferenceManager();
setPreferenceScreen(mPreferenceManager.inflateFromResource(requireContext(),
preferencesResId, getPreferenceScreen()));
}
//替换新的PreferenceScreen
public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
...
}
//处理点击事件
public boolean onPreferenceTreeClick(@NonNull Preference preference)
//RecyclerView要使用的Adapter
protected RecyclerView.Adapter onCreateAdapter(@NonNull PreferenceScreen preferenceScreen)