Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/211.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何在AppBar下方创建剪裁的NavigationDrawer?_Android_Navigation Drawer_Clipped - Fatal编程技术网

Android 如何在AppBar下方创建剪裁的NavigationDrawer?

Android 如何在AppBar下方创建剪裁的NavigationDrawer?,android,navigation-drawer,clipped,Android,Navigation Drawer,Clipped,如何在AppBar下方创建剪裁的NavigationDrawer 最新的Android Studio(3.5.3)生成了一个全高的NavigationDrawer,我的问题是需要做哪些更改才能得到一个裁剪过的NavigationDrawer ( 请不要通过链接到包含大量古代答案的古代(如2015年)问题,将此问题标记为“重复”。 现在是2020年,我希望现在会有一种简单的方法来实现clipped NavigationDrawer。 希望现在有一个简单的解决方案可以很好地使用androidx和je

如何在AppBar下方创建剪裁的NavigationDrawer

最新的Android Studio(3.5.3)生成了一个全高的NavigationDrawer,我的问题是需要做哪些更改才能得到一个裁剪过的NavigationDrawer

( 请不要通过链接到包含大量古代答案的古代(如2015年)问题,将此问题标记为“重复”。 现在是2020年,我希望现在会有一种简单的方法来实现clipped NavigationDrawer。 希望现在有一个简单的解决方案可以很好地使用androidx和jetpack导航以及Kotlin方法,例如
setupActionBarWithNavController
。 当我提到用Android Studio生成的上述代码时,我现在谈论的是Android Studio 3.5.3,即当前的最新版本,以及它的项目模板“导航抽屉活动”,带有Kotlin和最低API级别19,即Android 4.4。 当今天的开发人员想找到一种方法来实现这一点,并使用google和stackoverflow进行搜索时,我们就不想找到并滚动浏览包含大量旧/过时页面答案的长页面。 由于这个问题现在是在2020年2月提出的,所以大家都会清楚,下面所有可能的答案也都将迟于2020年2月。 )

奇怪的是,似乎很难找到关于如何用Android实现裁剪抽屉的文档。 这里提到了导航抽屉的两种类型(“全高”和“剪裁”):

引述:

“标准导航抽屉可以使用以下其中一个立面位置:

 At the same elevation as a top app bar (full-height)

 At a lower elevation than a top app bar (clipped)"
在上面的网页上还有一个指向android特定页面的链接:

但是,该页面目前没有提到任何关于如何创建裁剪NavigationDrawer的内容。 此外,android页面似乎没有太多更新,因为它当前链接到关于抽屉布局的旧SupportV4库

当我看到androidx关于抽屉布局的新页面时,我仍然找不到关于“剪裁”抽屉的任何信息。 (既然“clipped”是谷歌材料设计中使用的术语,那么谷歌也应该使用这个词在文档页面中进行搜索)

这里有一些页面可以找到关于“剪辑”的信息,但不幸的是,目前还没有:

为了说明我在寻找什么(独立于上面可能会改变的材料设计页面),我在下面提供了一些图片

下面的第一个屏幕截图是使用Android Studio 3.5.3(目前是最新版本)生成Android应用程序,使用Kotlin和最低API级别19(Android 4.4)生成“导航抽屉活动”后的结果(经过两次修改,见下文)

我(在“activity\u main.xml”中)所做的两个更改是,我从NavigationView中删除了app:headerLayout,并将android:layout\u height=“match\u parent”替换为android:layout\u height=“wrap\u content”。

然后我用GIMP编辑了一些截图来说明我真正想要的,如下图所示。 “汉堡包图标”应该可以关闭NavigationDrawer,即使用它进行切换

下面是使用“全高”NavigationDrawer生成的一些相关文件,我的问题是,要获得上述编辑图片中的“剪裁”NavigationDrawer,我必须进行哪些更改


MainActivity.kt

package com.myapplication

import android.os.Bundle
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import androidx.drawerlayout.widget.DrawerLayout
import com.google.android.material.navigation.NavigationView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import android.view.Menu

class MainActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration: AppBarConfiguration

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)

        val fab: FloatingActionButton = findViewById(R.id.fab)
        fab.setOnClickListener { view ->
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                .setAction("Action", null).show()
        }
        val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
        val navView: NavigationView = findViewById(R.id.nav_view)
        val navController = findNavController(R.id.nav_host_fragment)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow,
                R.id.nav_tools, R.id.nav_share, R.id.nav_send
            ), drawerLayout
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        // Inflate the menu; this adds items to the action bar if it is present.
        menuInflater.inflate(R.menu.main, menu)
        return true
    }

    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.nav_host_fragment)
        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:menu="@menu/activity_main_drawer" />

</androidx.drawerlayout.widget.DrawerLayout>


app_bar_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </com.google.android.material.appbar.AppBarLayout>

    <include layout="@layout/content_main" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@android:drawable/ic_dialog_email" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>


content_main.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"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:showIn="@layout/app_bar_main">

    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/mobile_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>

这比我想象的要复杂一些,但这条错误消息帮助我达到了目的:

抽屉布局必须使用MeasureSpec精确测量

以下是Kotlin的解决方案:

  • 创建一个扩展DroperLayout类的新类。在onMeasure方法中,为widthMeasureSpec和heightMeasureSpec创建两个新变量,并将它们传递到超类:

    class CustomDrawerLayout @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
    ) : DrawerLayout(context, attrs, defStyleAttr) {
    
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        var newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec),MeasureSpec.EXACTLY)
        var newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),MeasureSpec.EXACTLY)
        super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec)
      }
    }
    
  • 在activity_main.xml文件中,更新最外面的标记以使用新的CustomDrawerLayout。将CustomDrawerLayout和NavigationView布局高度更改为:

    android:layout_height="wrap_content"
    
  • 确保在找到抽屉布局视图时,将其初始化为CustomDrawerLayout类的实例:

    var drawerLayout : CustomDrawerLayout = findViewById(R.id.clipped_drawer_layout)
    
  • 要保持操作栏可见,需要将其添加到NavigationView组件:

    android:layout_marginTop="?android:attr/actionBarSize"
    
  • 完整的activity_main.xml文件如下所示:

    <com.mullr.neurd.Miscellaneous.CustomDrawerLayout
    android:id="@+id/clipped_drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:openDrawer="start"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    
        <include
            layout="@layout/app_bar_main"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
        <com.google.android.material.navigation.NavigationView
            android:id="@+id/nav_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="start"
            android:layout_marginTop="?android:attr/actionBarSize"
            app:headerLayout="@layout/nav_header_main"
            app:menu="@menu/activity_main_drawer" />
    
    </com.mullr.neurd.Miscellaneous.CustomDrawerLayout>
    
    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_main)
    
    
            // NAVIGATION 
            val toolbar: Toolbar = findViewById(R.id.toolbar)
            setSupportActionBar(toolbar)
    
            var drawerLayout: CustomDrawerLayout = findViewById(R.id.full_drawer_layout)
            navView = findViewById(R.id.nav_view)
    
            // This needs to come after drawerLayout has been initialized
            toolbar.setNavigationOnClickListener {
                if(drawerLayout.isDrawerOpen(GravityCompat.START)){
                    drawerLayout.closeDrawer(GravityCompat.START)
                }
                else{
                    drawerLayout.openDrawer(GravityCompat.START)
                }
            }
    
            navController = findNavController(R.id.nav_host_fragment)
            navView.itemIconTintList = null
            toolbar.setupWithNavController(navcontroller,drawerLayout)
            // Passing each menu ID as a set of Ids because each
            // menu should be considered as top level destinations.
            appBarConfiguration = AppBarConfiguration(
                setOf(
                    R.id.nav_home, R.id.nav_favorites, R.id.nav_settings
                ), drawerLayout
            )
            setupActionBarWithNavController(navController, appBarConfiguration)
            navView.setupWithNavController(navController)
        }
    
    
    
    最后,从styles.xml(v21)文件中删除这一行,以便状态栏不被覆盖:

    <item name="android:statusBarColor">@android:color/transparent</item>
    
    <item name="android:statusBarColor">@android:color/transparent</item>
    
    @android:color/transparent
    
    应该这样做。

    当导航抽屉打开时,保持应用程序栏在屏幕上的新答案:

    main\u drawer.xml-包含自定义抽屉布局、应用程序栏主布局和导航视图的新布局文件

    <com.example.myapp.Miscellaneous.CustomDrawerLayout 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:id="@+id/full_drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        tools:openDrawer="start">
    
        <include
            layout="@layout/app_bar_main"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
        <com.google.android.material.navigation.NavigationView
            android:id="@+id/nav_view"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:fitsSystemWindows="true"
            app:headerLayout="@layout/nav_header_main"
            app:menu="@menu/activity_main_drawer">
    
        </com.google.android.material.navigation.NavigationView>
    
    </com.example.myapp.Miscellaneous.CustomDrawerLayout>
    
    最终结果应该如下所示:

    <com.mullr.neurd.Miscellaneous.CustomDrawerLayout
    android:id="@+id/clipped_drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:openDrawer="start"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    
        <include
            layout="@layout/app_bar_main"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
        <com.google.android.material.navigation.NavigationView
            android:id="@+id/nav_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="start"
            android:layout_marginTop="?android:attr/actionBarSize"
            app:headerLayout="@layout/nav_header_main"
            app:menu="@menu/activity_main_drawer" />
    
    </com.mullr.neurd.Miscellaneous.CustomDrawerLayout>
    
    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_main)
    
    
            // NAVIGATION 
            val toolbar: Toolbar = findViewById(R.id.toolbar)
            setSupportActionBar(toolbar)
    
            var drawerLayout: CustomDrawerLayout = findViewById(R.id.full_drawer_layout)
            navView = findViewById(R.id.nav_view)
    
            // This needs to come after drawerLayout has been initialized
            toolbar.setNavigationOnClickListener {
                if(drawerLayout.isDrawerOpen(GravityCompat.START)){
                    drawerLayout.closeDrawer(GravityCompat.START)
                }
                else{
                    drawerLayout.openDrawer(GravityCompat.START)
                }
            }
    
            navController = findNavController(R.id.nav_host_fragment)
            navView.itemIconTintList = null
            toolbar.setupWithNavController(navcontroller,drawerLayout)
            // Passing each menu ID as a set of Ids because each
            // menu should be considered as top level destinations.
            appBarConfiguration = AppBarConfiguration(
                setOf(
                    R.id.nav_home, R.id.nav_favorites, R.id.nav_settings
                ), drawerLayout
            )
            setupActionBarWithNavController(navController, appBarConfiguration)
            navView.setupWithNavController(navController)
        }
    
    要保留工具栏上“后退”按钮(或“向上”按钮)的行为,请确保在活动的onCreate方法()中包含此行:

    最后,从styles.xml(v21)文件中删除这一行,以便状态栏不被覆盖:

    <item name="android:statusBarColor">@android:color/transparent</item>
    
    <item name="android:statusBarColor">@android:color/transparent</item>
    
    @android:color/transparent
    

    很抱歉,但没有。我现在已经尝试过了,但实际上我在您的屏幕截图中也看到,您似乎误解了什么。在您的屏幕截图中,导航抽屉的标题仍然位于黑色应用程序栏的顶部,隐藏着“汉堡包”图标“。我希望抽屉内容位于应用程序栏的下方,而应用程序栏中的汉堡包图标是可见的,并且可以进行切换,正如我在问题中的第二张(GIMP编辑)图片所示。我更新了我的回答,您必须向XML文件添加一些属性才能实现这一点。很好,但并不完美(如我所希望的那样)。所需的切换效果正在工作(某种程度上