从片段中的按钮单击打开导航抽屉(Kotlin)
Posted
技术标签:
【中文标题】从片段中的按钮单击打开导航抽屉(Kotlin)【英文标题】:Open Navigation Drawer from Button Click within Fragment (Kotlin) 【发布时间】:2020-06-01 08:45:48 【问题描述】:我在片段中创建了一个自定义按钮,并且我试图在单击时打开导航抽屉在活动中。
当您滑动时,导航抽屉仍然可以正常打开,但是当我单击按钮时应用程序会崩溃。
我猜这是因为我试图从 Fragment 访问,但我不知所措..
片段
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View?
// Inflate the layout for this fragment
val binding: SiteFragmentBinding = DataBindingUtil.inflate(
inflater, R.layout.site_fragment, container, false
)
binding.apply
siteOverflowOptionsMenuButton.setOnClickListener
showPopUp(it)
siteDrawerMenuButton.setOnClickListener
drawer_layout.openDrawer(nav_view) // this crashes (also crashes with Gravity.LEFT or similar)
return binding.root
activity.xml
?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<LinearLayout
android:layout_
android:layout_
android:orientation="vertical">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/siteNavHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_
android:layout_
app:defaultNavHost="true"
app:navGraph="@navigation/site_navigation" />
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:layout_
android:layout_
android:layout_gravity="start"
android:id="@+id/nav_view"
app:headerLayout="@layout/nav_header"
app:menu="@menu/drawer_menu"
/>
</androidx.drawerlayout.widget.DrawerLayout>
site_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/siteMainConstraintLayout"
android:layout_
android:layout_
android:background="@color/white"
tools:context=".site.SiteActivity"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/siteLogoConstraintLayout"
android:layout_
android:layout_
android:layout_marginTop="16dp"
android:foregroundGravity="center_horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/siteLogoImage"
android:layout_
android:layout_
android:src="@mipmap/ic_launcher_logo"
app:layout_constraintEnd_toStartOf="@id/siteTopHeadingText"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/siteTopHeadingText"
android:layout_
android:layout_
android:gravity="center_vertical"
android:paddingStart="12dp"
android:paddingLeft="12dp"
android:text="@string/site_top_heading"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textSize="18sp"
android:textStyle="bold|italic"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
android:id="@+id/siteOverflowOptionsMenuButton"
android:layout_
android:layout_
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
app:srcCompat="@drawable/ic_menu_vertical_dots"
android:tint="@color/locatorsPurpleCompany"
app:layout_constraintBottom_toBottomOf="@+id/siteLogoConstraintLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/siteLogoConstraintLayout" />
<ImageView
android:id="@+id/siteDrawerMenuButton"
android:layout_
android:layout_
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
app:srcCompat="@drawable/ic_menu_drawer"
android:tint="@color/locatorsPurpleCompany"
app:layout_constraintBottom_toBottomOf="@+id/siteLogoConstraintLayout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/siteLogoConstraintLayout" />
<androidx.cardview.widget.CardView
android:id="@+id/siteFilterOptionsCardView"
android:layout_
android:layout_
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
app:cardBackgroundColor="@color/locatorsGrey"
app:cardCornerRadius="18dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/siteLogoConstraintLayout">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/siteFilterOptionsConstraintLayout"
android:layout_
android:layout_>
<ImageView
android:id="@+id/siteFilterIconImageView"
android:layout_
android:layout_
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
app:srcCompat="@drawable/ic_filter"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/siteCurrentFilterTextView"
android:layout_
android:layout_
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="4dp"
android:background="@color/white"
android:drawableLeft="@drawable/ic_search"
android:drawablePadding="8dp"
android:ellipsize="end"
android:gravity="center_vertical"
android:lines="1"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:text="Search..."
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/siteClearIconImageView"
app:layout_constraintStart_toEndOf="@+id/siteFilterIconImageView"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/siteClearIconImageView"
android:layout_
android:layout_
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
app:srcCompat="@drawable/ic_clear"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/siteRecyclerView"
android:layout_
android:layout_
android:layout_marginBottom="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/siteFilterOptionsCardView"
app:layout_constraintVertical_bias="0.0"
tools:listitem="@layout/site_list_item" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButtonAdd"
android:layout_
android:layout_
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
android:layout_marginBottom="24dp"
android:backgroundTint="@color/locatorsPurpleCompany"
android:clickable="true"
android:elevation="28dp"
app:borderWidth="0dp"
app:fabSize="normal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/siteRecyclerView"
app:srcCompat="@drawable/ic_add_white" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
drawer_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
>
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_first_fragment"
android:icon="@drawable/ic_exit"
android:title="First" />
<item
android:id="@+id/nav_second_fragment"
android:icon="@drawable/ic_priority"
android:title="Second" />
<item
android:id="@+id/nav_third_fragment"
android:icon="@drawable/ic_filter"
android:title="Third" />
</group>
<item android:title="Communicate">
<menu>
<item
android:id="@+id/nav_share"
android:icon="@drawable/ic_contact"
android:title="Share" />
<item
android:id="@+id/nav_send"
android:icon="@drawable/ic_location"
android:title="Send" />
</menu>
</item>
<item android:title="Sub items">
<menu>
<group android:checkableBehavior="single">
<item
android:icon="@drawable/ic_star_full"
android:title="Sub item 1" />
<item
android:icon="@drawable/ic_location"
android:title="Sub item 2" />
</group>
</menu>
</item>
</menu>
崩溃日志
2020-02-17 12:31:56.719 23527-23527/com.locators.acorn E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.locators.acorn, PID: 23527
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.drawerlayout.widget.DrawerLayout.openDrawer(int)' on a null object reference
at com.locators.acorn.site.SiteFragment$onCreateView$$inlined$apply$lambda$2.onClick(SiteFragment.kt:46)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
【问题讨论】:
请上传崩溃日志。 你能添加你的片段布局吗? 崩溃日志和fragment.xml现在添加了..我知道这是一个空指针异常,只是看不到如何从片段访问.. 【参考方案1】:在您的实现中,您不要这样做,因为无法从 fragment
访问 drawer_layout
。因此你得到了NullPointerException
。尝试按照以下步骤操作:
步骤 - 1:在您的 Activity
中创建一个函数来打开-关闭导航抽屉
fun openCloseNavigationDrawer(view: View)
if (drawer_layout.isDrawerOpen(GravityCompat.START))
drawer_layout.closeDrawer(GravityCompat.START)
else
drawer_layout.openDrawer(GravityCompat.START)
第 2 步:从您的片段中调用 openCloseNavigationDrawer
OnClickListener
,并通过布局添加onClick
属性,并在siteDrawerMenuButton
上指出函数openCloseNavigationDrawer
。
<ImageView
android:id="@+id/siteDrawerMenuButton"
android:onClick="openCloseNavigationDrawer"
... />
选项 - 2:您可以通过转换您的Activity
来通过代码访问函数openCloseNavigationDrawer
,如下所示:
siteDrawerMenuButton.setOnClickListener v ->
(activity as YOUR_ACTIVITY).openCloseNavigationDrawer(v)
【讨论】:
像梦一样工作,谢谢! - 我使用了您答案的“更新”版本和以下 Kotlin 代码:siteDrawerMenuButton.setOnClickListenerview -> (activity as SiteActivity).openCloseNavigationDrawer(view) 为了防止返回按钮退出Activity,我在Activity中添加了以下内容: override fun onBackPressed() if (drawer_layout.isDrawerOpen(GravityCompat.START))drawer_layout.closeDrawer(GravityCompat. START) else super.onBackPressed() 【参考方案2】:聚会有点晚了,但万一有人觉得这很有用 - 这是与 Jetpack Binding 的单行代码:
class LoginViewModel ( applicationParam: Application ) : AndroidViewModel ( applicationParam )
screenViews = FragmentLoginBinding.inflate ( inflater,container,false )
override fun onViewCreated ( view: View, savedInstanceState: Bundle? )
// Set click listener for the Log in button
screenViews.login.setOnClickListener submitLogin()
// Set the click listener for the element that selects the register fragment from the navigation drawer
screenViews.goToRegisterFragment.setOnClickListener findNavController().navigate ( R.id.nav_register )
LoginViewModel 是名为 Login 的片段的视图模型,而 R_id_nav_register 是 mobile_navigation.xml 和 activity_main_drawer.xml 中的一个元素
【讨论】:
以上是关于从片段中的按钮单击打开导航抽屉(Kotlin)的主要内容,如果未能解决你的问题,请参考以下文章