所以我正在创建我的第一个 Android 应用程序,并且我已经在使用 Jetpack Navigation。我还使用自己的自定义工具栏来实现我自己的自定义布局。但是,我想利用内置的 Jetpack 设置屏幕,即 AndroidX 首选项库 (https://developer.android.com/develop/ui/views/components/settings)。
因为我不知道在这个项目结束时我的设置会有多大(不要评判我),我希望能够将我的设置拆分到多个屏幕上,正如这里所说的(https:// developer.android.com/develop/ui/views/components/settings/organize-your-settings)。
但是文档利用片段工厂并强调从 Activity 实现 onPreferenceStartFragment()。然而,我的应用程序通过 Jetpack Navigation 将用户带到“设置”屏幕,因此它已经由 Fragment 而不是 Activity 托管,并且 NavControllers/NavigationGraphs 到目前为止使用起来非常简单且轻松。
那么我可以使用 NavController 和 NavigationGraph 实现“将层次结构拆分为多个屏幕”吗?
(我要发布一个答案,这是我尝试过的,到目前为止有效)
正如所承诺的那样。我就是这样做的。我发帖是因为互联网搜索没有发现任何人已经解决了这个问题,而且自从我弄清楚后,我认为这可能会对未来的其他人有所帮助。
另外,我认为这对于经验丰富的 Android 开发者来说可能是显而易见的,但我是新手,所以我不确定什么时候可以正常工作。
所以我已经在使用来自位于我的单个活动的
mainNavHostFragment
文件中的 MainActivity.Java
的导航。
使用“导航”所需输入的内容比使用“片段事务”和“片段工厂”要好得多,所以我想出了这一点,这样我就可以继续使用导航并避免使用 o.g.片段操作技术。
现在,当用户单击我提供的“设置”图标时,首先
mainNavHostFragment
会将用户导航到 HolderOfSettingsFragment.java
类。
在那个
HolderOfSettingsFragment.java
课程中,我有第二个NavHostFragment
,名为settingsNavHostFragment
,它是...
getChildFragmentManager
而不是 getSupportFragmentManager
androidx.fragment.app.FragmentContainerView
。按照通常的方式,我有一个从
settingsNavController
获得的 settingsNavHostFragment
。
FragmentContainerView
使用名为 navGraph
的 sub_navigation_from_settings
,它与我的 MainActivity 使用的不同。 sub_navigation_from_settings
中的起始片段是我的 root_preferences
,它对我的 SubSettingsExampleFragment
有一个 [导航] 操作。
根据https://developer.android.com/develop/ui/views/components/settings的文档,要从根首选项屏幕到附加屏幕建立“链接”,您所需要做的就是列出一个带有
<Preference/>
条目的 app:title
标签,该条目将与“链接”屏幕中的 <PreferenceCategory>
以及指示要跳转到的片段类的 app:fragment
相匹配。
偏好片段本身实际上非常无聊。它们实际上只是一个扩展
PreferenceFragmentCompat
的类,它实现 onCreatePreferences
,其单个操作是将 setPreferencesFromResource
应用于位于 XML 目录中的适当首选项资源。
根据相同的文档,为了响应
root_prefernces
中的“链接”点击,您需要实现 PreferenceFragmentCompat.OnPreferenceStartFragmentCallback
。文档说要在 Activity 中执行此操作,但我在 HolderOfSettingsFragment
中执行此操作,并且效果很好。
此外,实现
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback
接口意味着实现 onPreferenceStartFragment
,它是通过 caller
和 'pref` 调用的。所以我们就这么做了。
为了让
settingsNavHostFragment
处理事情,我们只需检查 pref.getTitle
是否匹配给定的标题,如果匹配,我们使用 settingsNavController
使用 sub_navigation_from_settings
中的操作 id 导航到适当的“首选项片段”图表。
它对我来说工作得很好。耶!
这可能会因为我不知道的事情导致冲突而行不通,但在那之前我很高兴它能起作用。
我希望这对我以外的人有帮助。
如果您想直接查看的话,这里是所有代码。
这是持有者java类:
package com.example.app;
import ...
import com.example.app.databinding.FragmentSettingsHolderBinding;
public class HolderOfSettingsFragment extends Fragment implements
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
public static final String TAG = "HolderOfSettingsFragment-";
FragmentSettingsHolderBinding bindingOfThis;
NavController settingsNavController;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
bindingOfThis = FragmentSettingsHolderBinding.inflate(inflater, container, false);
return bindingOfThis.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
NavHostFragment settingsNavHostFragment = (NavHostFragment) getChildFragmentManager().findFragmentById(R.id.settingsHolderFragContainer);
settingsNavController = settingsNavHostFragment.getNavController();
bindingOfThis.imgReturnIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
((AppCompatActivity) getActivity()).onBackPressed();
}
});
}
@Override
public boolean onPreferenceStartFragment(@NonNull PreferenceFragmentCompat caller, @NonNull Preference pref) {
String stringToCompare = (String) pref.getTitle();
if ( stringToCompare.equalsIgnoreCase("Other Settings") ) {
settingsNavController.navigate(R.id.action_settingsFragment_to_subSettingsExampleFragment);
}
return true;
}
@Override
public void onDestroy() {
super.onDestroy();
bindingOfThis = null;
}
}
它具有以下布局:
请注意,Android Studio 编辑器不会渲染此布局,我相信这是因为设置资源是存储在 XML 资源目录中的纯 XML。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HolderOfSettingsFragment">
<ImageView
android:id="@+id/imgReturnIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:src="?attr/actionModeCloseDrawable"
app:layout_constraintEnd_toStartOf="@+id/txtSettingsTitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/txtSettingsTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="12dp"
android:text="Settings"
android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionMode.Title"
app:layout_constraintBottom_toBottomOf="@+id/imgReturnIcon"
app:layout_constraintStart_toEndOf="@+id/imgReturnIcon"
app:layout_constraintTop_toTopOf="parent" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/settingsHolderFragContainer"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toBottomOf="@id/imgReturnIcon"
android:layout_marginTop="40dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/sub_navigation_from_settings"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
这是第二个导航图:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/sub_navigation_from_settings"
app:startDestination="@id/settingsFragment">
<fragment
android:id="@+id/settingsFragment"
android:name="com.example.app.SettingsFragment"
android:label="SettingsFragment" >
<action
android:id="@+id/action_settingsFragment_to_subSettingsExampleFragment"
app:destination="@id/subSettingsExampleFragment" />
</fragment>
<fragment
android:id="@+id/subSettingsExampleFragment"
android:name="com.example.app.SubSettingsExampleFragment"
android:label="SubSettingsExampleFragment" />
</navigation>
这是根设置 XML:
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="Current User">
<SwitchPreferenceCompat
app:key="current_user_hide_tb_labels"
app:title="Hide labels underneath Toolbar Icons?"
app:defaultValue="false"/>
</PreferenceCategory>
<Preference
app:title="Other Settings"
app:summary="Other Settings Example"
app:fragment="com.example.app.SubSettingsExampleFragment" />
最后是单独的示例设置屏幕的 xml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="Other Settings">
<SwitchPreferenceCompat
app:key="do_you_like"
app:title="Do you like me?"
app:defaultValue="false"/>
</PreferenceCategory>
</PreferenceScreen>
打开 nav_graph XML 并为您想要的每个额外屏幕添加额外的设置片段。
然后在根设置 XML 中添加标题...
<Preference
app:key="display_settings"
app:icon="@drawable/display_settings_icon"
app:title="@string/display_settings" />
<Preference
app:key="notification_settings"
app:icon="@drawable/notification_settings_icon"
app:title="@string/notification_settings" />
现在在根设置片段中添加首选项标题键的侦听器...
val displayPreferences: Preference? = findPreference("display_settings")
displayPreferences!!.onPreferenceClickListener =
Preference.OnPreferenceClickListener {
// must match name given in nav_graph XML
navController.navigate(R.id.nav_display_settings)
true
}
val notificationPreferences: Preference? = findPreference("notification_settings")
notificationPreferences!!.onPreferenceClickListener =
Preference.OnPreferenceClickListener {
// must match name given in nav_graph XML
navController.navigate(R.id.nav_notification_settings)
true
}
然后将所有相关代码从根设置片段和 XML 移动到您创建的新片段和 XML 文件。
当您单击根设置屏幕中的标题时,它们现在将打开相关片段。
希望对某人有帮助。