如何在导航控件片段中关闭导航 DrawerLayout onBackPressed
Posted
技术标签:
【中文标题】如何在导航控件片段中关闭导航 DrawerLayout onBackPressed【英文标题】:How to close navigation DrawerLayout onBackPressed in Navigation Controls Fragment 【发布时间】:2019-09-19 12:47:49 【问题描述】:我创建了一个具有 Navigation 模式的 Androidx 项目。现在我想在片段中关闭 drawerLayout onBackPressed()
。而且我想将OnClickListener
设置为我的自定义菜单的抽屉菜单项,我猜无法覆盖片段中的onBackPressed()
。
我想知道如何实现这一目标?
这是我的抽屉:
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:id="@+id/drawerLayoutHome"
android:layout_
android:layout_>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_
android:layout_
android:layout_gravity="start"
android:background="@color/colorPrimaryDark"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:itemIconTint="@color/white"
app:itemTextColor="@color/white"
app:menu="@menu/activity_main_drawer"/>
</androidx.drawerlayout.widget.DrawerLayout>
我想实现这个:
override fun onBackPressed()
if (drawerLayoutHome.isDrawerOpen(GravityCompat.END))
drawerLayoutHome.closeDrawer(GravityCompat.END)
else
super.onBackPressed()
但是这是针对Activity
的,如何在Fragment
中实现呢?
【问题讨论】:
【参考方案1】:您好,您可以通过让您的片段处于活动状态并使用 kotlin 代码覆盖 onbackpress 来做到这一点
这是您的后台功能,您可以在其中获取导航主机,然后您可以检查当前的片段或要在其中打开抽屉的片段。
override fun onBackPressed()
val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragmentHomeHost)
val completeFragmentList = navHostFragment?.childFragmentManager?.fragments
if (completeFragmentList != null)
when
completeFragmentList[0] is HomeFragment ->
val home = (completeFragmentList[0] as HomeFragment)
else -> super.onBackPressed()
if (drawerLayoutHome.isDrawerOpen(GravityCompat.START))
drawerLayoutHome.closeDrawer(GravityCompat.START)
else
super.onBackPressed()
这里是锄头,你可以得到选择项监听器
override fun onNavigationItemSelected(item: MenuItem): Boolean
drawerLayoutHome.closeDrawer(GravityCompat.START)
return true
【讨论】:
【参考方案2】:您可以通过在抽屉活动中实现 OnBackStackChangedListener
在 Fragment
中执行此操作。
然后,将您的抽屉与ActionBarDrawerToggle
链接并覆盖onBackStackChanged()
并同步您的抽屉切换。
这是完整的sn-p:
public class MainActivity extends AppCompatActivity implements FragmentManager.OnBackStackChangedListener
private DrawerLayout drawer;
private ActionBarDrawerToggle toggle;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
//Bind listener here
getSupportFragmentManager().addOnBackStackChangedListener(this);
drawer = findViewById(R.id.drawer_layout);
toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
toggle.setToolbarNavigationClickListener(view -> onBackPressed());
drawer.addDrawerListener(toggle);
toggle.syncState();
//Override fragment backstack lister method
@Override
public void onBackStackChanged()
//toggle.setDrawerIndicatorEnabled(getSupportFragmentManager().getBackStackEntryCount() == 0);
//getSupportActionBar().setDisplayHomeAsUpEnabled(getSupportFragmentManager().getBackStackEntryCount() > 0);
toggle.syncState();
@Override
public void onBackPressed()
drawer = findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START))
drawer.closeDrawer(GravityCompat.START);
else
//super.onBackPressed();
希望对你有帮助。
【讨论】:
我的抽屉在我的活动中 我在活动中实现了背压。但我要求直接在片段中处理它不想在活动中编写代码 这里有两种不同的方法,onBackPressed()
用于活动,onBackStackChanged()
用于片段,FragmentManager.OnBackStackChangedListener
在 activty 上,因此当片段可见并在那时触发onBackStackChanged()
时返回动作。在onBackStackChanged()
内部,我们同步了抽屉标签toggle.syncState()
,所以如果抽屉打开了,那么抽屉就会关闭。
嘿,这个答案需要用 kotlin 语言解释,而你是用 java 提供的
根据 android doc,java 和 kotlin 一起工作非常顺利,另一件事是您可以在 android studio 中轻松地将任何 java 代码转换为 kotlin。【参考方案3】:
简答
如果不在托管Activity
内添加额外代码,就无法拦截Fragment
内的onBackPressed
回调。它根本没有在Android SDK
中实现。停下来。
原答案
Fragment
类中没有 onBackPressed
回调这样的东西。但是你可以自己实现:
创建接口:
interface FragmentOnBackPressedListener
fun onBackPressed()
现在在你的活动中:
override fun onBackPressed()
// find top fragment
val currentFragment = supportFragmentManager
.findFragmentById(R.id.your_nav_host_fragment_id)?.let
it.childFragmentManager.fragments.getOrNull(0)
// check if it implements FragmentOnBackPressedListener
if (currentFragment is FragmentOnBackPressedListener )
// if it does, transfer flow to the fragment
return currentFragment.onBackPressed()
// if it doesn't, apply default behaviour
super.onBackPressed()
然后在你的片段中:
class ExampleFragment : Fragment(), FragmentOnBackPressedListener
override fun onBackPressed()
// close your drawer layout here if visible
// Also: to close fragment, invoke
// findNavController().navigateUp() or findNavController().popBackStack()
【讨论】:
不,谢谢,但我实际上已经这样做了,但我问这可能吗?要做到这一点 ?直接在片段中而不写在活动中 @ArbazPirwani 那么恐怕答案是不可能【参考方案4】:在 Kotlin 中,只需在您的活动中重写此方法,
override fun onBackPressed()
if (drawer_layout.isDrawerOpen(GravityCompat.START))
drawer_layout.closeDrawer(GravityCompat.START)
else
super.onBackPressed()
【讨论】:
你说得对,我已经这样做了,但我希望它在片段中 片段总是包含一个基础活动。您可以在该活动中使用您的导航抽屉....... 在片段中使用它有什么好处?例如:如果您在第一个片段中使用它,并且通过导航抽屉中的任何项目导航到另一个片段,它将导航到另一个片段,并且您必须创建导航抽屉到该片段以及再次导航到任何其他片段......很快...... 我的导航抽屉只能在一个片段中使用 然后,尝试在片段中创建自定义工具栏,并将您的活动主题设置为 noActionBar。希望它有效....【参考方案5】:我也遇到过类似的问题。
所以,我在我的 Activity 文件的 onBackPressed 中添加了这个。
FragmentManager manager = getSupportFragmentManager();
if (manager.getBackStackEntryCount() > 0)
while (manager.getBackStackEntryCount() > 0)
manager.popBackStackImmediate();
【讨论】:
【参考方案6】:您可以使用OnBackPressedDispatcher
从片段内控制onBackPress()
。
class SampleFragment: Fragment()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true)
override fun handleOnBackPressed()
if (drawer.isDrawerOpen(GravityCompat.START))
drawer.closeDrawer(GravityCompat.START)
else
isEnabled = false
requireActivity().onBackPressed()
)
【讨论】:
以上是关于如何在导航控件片段中关闭导航 DrawerLayout onBackPressed的主要内容,如果未能解决你的问题,请参考以下文章