Как создать подрезанный Навигационный ящик под панелью приложений с Android? - PullRequest
1 голос
/ 05 февраля 2020

Как создать подрезанный Навигационный ящик под панелью приложения с помощью Android?

В последней версии Android Studio (3.5.3) создается полноразмерный блок навигации, и мой вопрос в том, что Нужно изменить, чтобы вместо этого получить ограниченный навигационный ящик?

(Пожалуйста, не обозначайте этот вопрос как «дубликат», ссылаясь на ДРЕВНИЕ (например, 2015) вопросы с длинным списком древних ответов. Сейчас 2020 и я надеюсь, что теперь будет существовать простой способ реализации ограниченного навигационного блока. Надеюсь, теперь есть простое решение, которое хорошо работает с навигацией androidx и jetpack и Kotlin методами, такими как setupActionBarWithNavController. Когда я упоминал выше код, сгенерированный с помощью Android Studio Я сейчас говорю о Android Studio 3.5.3, то есть о текущей последней версии, и ее шаблоне проекта "Активность в Навигационном блоке" с Kotlin и минимальным уровнем API 19, т.е. Android 4.4. Когда разработчики сегодня хочу найти способ сделать это, и искать с помощью Google и Sta ckoverflow, тогда мы не хотим находить и прокручивать длинные страницы с множеством старых / устаревших ответов. Поскольку этот вопрос теперь задается в феврале 2020 года, всем будет ясно, что все возможные ответы ниже также будут позже. )

Странно, что так сложно найти документацию о том, КАК реализовать ящик с обрезкой с Android. Здесь упоминаются два типа ("полная высота" и "обрезанный") навигационных ящиков:

https://material.io/components/navigation-drawer/#standard -втяжник

Цитата:

"Стандартный навигационный ящик может использовать одну из следующих отметок:

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

 At a lower elevation than a top app bar (clipped)"

На вышеуказанной веб-странице также имеется ссылка на страницу android Speci c:

https://material.io/develop/android/components/navigation-view/

Однако на этой странице в настоящее время ничего не говорится о том, как создать ограниченный навигационный ящик. Кроме того, эта страница android выглядит не очень обновлен, поскольку в настоящее время он ссылается на старую библиотеку поддержки v4 о DrawerLayout.

Когда я вместо этого смотрю на новую страницу androidx о DrawerLayout, я все еще не могу найти ничего о «обрезанном» ящике (поскольку «обрезанное» - это термин, используемый в дизайне материалов Google, тогда Google должен также использовать это же слово для поиска на страницах документации).

Вот некоторые страницы, где должно быть в состоянии найти что-то о "клипе "но Curre к сожалению, нет:

https://developer.android.com/jetpack/androidx/releases/drawerlayout

https://developer.android.com/guide/navigation/navigation-ui#add_a_navigation_drawer

Для иллюстрации того, что я ищу (независимо на приведенной выше странице дизайна материала, которая может измениться) Ниже приведены некоторые изображения.

Первый снимок экрана ниже - это результат (с двумя модификациями, см. ниже) после создания приложения Android с Android Studio 3.5.3 (в настоящее время самая последняя версия) и «Активность в окне навигации» с Kotlin и минимальным уровнем API 19 (Android 4.4).

Два внесенных мною изменения (в «Activity_main. *» 1095 * ") я удалил приложение: headerLayout из NavigationView и заменил android: layout_height =" match_parent "на android: layout_height =" wrap_content ". enter image description here

Затем я отредактировал несколько скриншотов с помощью GIMP, чтобы проиллюстрировать то, что я действительно хотел бы, как на картинке ниже. «Значок гамбургера» должен быть в состоянии закрыть панель навигации, т.е. использовать его для переключения.

enter image description here

Ниже приведены некоторые соответствующие файлы, созданные с помощью Навигационный ящик "в полный рост", и мой вопрос в том, какие изменения я должен внести, чтобы получить "обрезанный" Навигационный ящик, как на отредактированном выше изображении? 1066 *


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>

Ответы [ 2 ]

2 голосов
/ 05 февраля 2020

Это оказалось немного сложнее, чем я думал, но это сообщение об ошибке помогло мне попасть туда:

DrawerLayout должен быть измерен с помощью MeasureSpe c. EXACTLY

Вот решение Kotlin:

  1. Создайте новый класс, расширяющий класс DrawerLayout. Внутри метода onMeasure создайте две новые переменные для widthMeasureSpe c и heightMeasureSpe c и передайте их суперклассу:

    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)
      }
    }
    
  2. В вашем файле activity_main. xml обновите внешний тег, чтобы использовать новый CustomDrawerLayout. Измените значение CustomDrawerLayout и NavigationView layout_height следующим образом:

    android:layout_height="wrap_content"
    
  3. Убедитесь, что, когда вы найдете представление box_layout, вы инициализируете его как экземпляр класса CustomDrawerLayout:

    var drawerLayout : CustomDrawerLayout = findViewById(R.id.clipped_drawer_layout)
    
  4. Чтобы панель действий была видимой, необходимо добавить ее к компоненту NavigationView:

    android:layout_marginTop="?android:attr/actionBarSize"
    

Полный код активности. 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>

Наконец, удалите эту строку из ваших стилей. xml (v21) файл, чтобы строка состояния не закрывалась:

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

Это должно сделать это. enter image description here

0 голосов
/ 05 февраля 2020

Новый ответ, чтобы держать панель приложения на экране при открытии навигационного ящика:

main_drawer. xml - Новый файл макета, который содержит настраиваемый ящикLayout, макет app_bar_main и представление навигации

<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>

app_bar_main. xml - Удалить панель инструментов из этого файла

<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"
        android:visibility="gone"
        app:srcCompat="@android:drawable/ic_dialog_email" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

activity_main. xml - Добавьте сюда панель инструментов и макет main_drawer.

<androidx.appcompat.widget.LinearLayoutCompat 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:fitsSystemWindows="true"
>

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


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

</androidx.appcompat.widget.LinearLayoutCompat>

MainActivity - Добавьте это, чтобы переключатель меню все еще работал

toolbar.setNavigationOnClickListener {
            if(drawerLayout.isDrawerOpen(GravityCompat.START)){
                drawerLayout.closeDrawer(GravityCompat.START)
            }
            else{
                drawerLayout.openDrawer(GravityCompat.START)
            }
        }

Конечный результат должен выглядеть примерно так например:

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 своей деятельности ( setUpWithNavController ):

    toolbar.setupWithNavController(findNavController(R.id.nav_host_fragment),drawerLayout)

Наконец, удалите эту строку из файла стилей. xml (v21), чтобы строка состояния не закрывалась:

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

enter image description here

...