Repository: mikepenz/MaterialDrawer Branch: develop Commit: c6e3f78e0e0f Files: 219 Total size: 639.4 KB Directory structure: gitextract_to5pn2i8/ ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE.md │ ├── ci-gradle.properties │ ├── config/ │ │ └── configuration.json │ ├── dependabot.yml │ └── workflows/ │ ├── ci.yml │ └── gradle-dependency-submission.yml ├── .gitignore ├── Dangerfile ├── FAQ/ │ ├── accountheader_single_profile_without_dropdown.md │ ├── howto_modify_add_custom_draweritems.md │ ├── howto_use_different_sub_library_version.md │ ├── opening-drawer-from-espresso.md │ └── when_to_use_this_library.md ├── FAQ.md ├── Gemfile ├── LICENSE ├── MIGRATION.md ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle.kts │ ├── gradle.properties │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── com/ │ │ └── mikepenz/ │ │ └── materialdrawer/ │ │ └── app/ │ │ ├── ActionBarActivity.kt │ │ ├── AdvancedActivity.kt │ │ ├── CollapsingToolbarActivity.kt │ │ ├── CompactHeaderDrawerActivity.kt │ │ ├── CrossfadeDrawerLayoutActvitiy.kt │ │ ├── CustomApplication.kt │ │ ├── DrawerActivity.kt │ │ ├── EmbeddedDrawerActivity.kt │ │ ├── FragmentActivity.kt │ │ ├── FullscreenDrawerActivity.kt │ │ ├── MenuDrawerActivity.kt │ │ ├── MiniDrawerActivity.kt │ │ ├── MultiDrawerActivity.kt │ │ ├── NavControllerActivity.kt │ │ ├── PersistentDrawerActivity.kt │ │ ├── drawerItems/ │ │ │ ├── AccountDividerDrawerItem.kt │ │ │ ├── CustomBaseViewHolder.kt │ │ │ ├── CustomCenteredPrimaryDrawerItem.kt │ │ │ ├── CustomPrimaryDrawerItem.kt │ │ │ ├── CustomUrlBasePrimaryDrawerItem.kt │ │ │ ├── CustomUrlPrimaryDrawerItem.kt │ │ │ ├── GmailDrawerItem.kt │ │ │ ├── IconDrawerItem.kt │ │ │ └── OverflowMenuDrawerItem.kt │ │ ├── fragment/ │ │ │ ├── DemoFragment.kt │ │ │ ├── DemoMessageFragment.kt │ │ │ ├── DrawerFragment.kt │ │ │ └── SecondDrawerFragment.kt │ │ ├── utils/ │ │ │ ├── CrossfadeWrapper.kt │ │ │ ├── SystemUtils.kt │ │ │ └── UIUtils.kt │ │ └── widget/ │ │ └── CrossfadeDrawerLayout.kt │ └── res/ │ ├── layout/ │ │ ├── activity_embedded.xml │ │ ├── activity_mini_drawer.xml │ │ ├── activity_multi_sample.xml │ │ ├── activity_persistent_drawer.xml │ │ ├── activity_sample.xml │ │ ├── activity_sample_actionbar.xml │ │ ├── activity_sample_collapsing_toolbar.xml │ │ ├── activity_sample_crossfader.xml │ │ ├── activity_sample_fragment.xml │ │ ├── activity_sample_fullscreen.xml │ │ ├── activity_sample_nav.xml │ │ ├── footer.xml │ │ ├── fragment_message_sample.xml │ │ ├── fragment_sample.xml │ │ ├── fragment_simple_sample.xml │ │ ├── header.xml │ │ ├── material_drawer_compact_persistent_header.xml │ │ ├── material_drawer_item_icon_only.xml │ │ ├── material_drawer_item_overflow_menu_primary.xml │ │ └── material_drawer_item_primary_centered.xml │ ├── menu/ │ │ ├── cab.xml │ │ ├── embedded.xml │ │ ├── example_menu.xml │ │ ├── fragment_menu.xml │ │ └── main.xml │ ├── mipmap-anydpi-v26/ │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ ├── navigation/ │ │ └── navigation.xml │ └── values/ │ ├── colors.xml │ ├── dimens.xml │ ├── ic_launcher_background.xml │ ├── ids.xml │ ├── strings.xml │ ├── styles.xml │ └── themes.xml ├── build.gradle.kts ├── gradle/ │ ├── libs.versions.toml │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── materialdrawer/ │ ├── .gitignore │ ├── build.gradle.kts │ ├── gradle.properties │ ├── proguard-rules.txt │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── com/ │ │ └── mikepenz/ │ │ └── materialdrawer/ │ │ ├── holder/ │ │ │ ├── BadgeStyle.kt │ │ │ ├── ColorHolder.kt │ │ │ ├── DimenHolder.kt │ │ │ ├── ImageHolder.kt │ │ │ └── StringHolder.kt │ │ ├── interfaces/ │ │ │ ├── ICrossfader.kt │ │ │ ├── OnCheckedChangeListener.kt │ │ │ └── OnPostBindViewListener.kt │ │ ├── model/ │ │ │ ├── AbstractBadgeableDrawerItem.kt │ │ │ ├── AbstractDrawerItem.kt │ │ │ ├── AbstractSwitchableDrawerItem.kt │ │ │ ├── AbstractToggleableDrawerItem.kt │ │ │ ├── BaseDescribeableDrawerItem.kt │ │ │ ├── BaseDrawerItem.kt │ │ │ ├── BaseViewHolder.kt │ │ │ ├── ContainerDrawerItem.kt │ │ │ ├── DividerDrawerItem.kt │ │ │ ├── ExpandableBadgeDrawerItem.kt │ │ │ ├── ExpandableDrawerItem.kt │ │ │ ├── MiniDrawerItem.kt │ │ │ ├── MiniProfileDrawerItem.kt │ │ │ ├── PrimaryDrawerItem.kt │ │ │ ├── ProfileDrawerItem.kt │ │ │ ├── ProfileSettingDrawerItem.kt │ │ │ ├── SecondaryDrawerItem.kt │ │ │ ├── SecondarySwitchDrawerItem.kt │ │ │ ├── SecondaryToggleDrawerItem.kt │ │ │ ├── SectionDrawerItem.kt │ │ │ ├── SwitchDrawerItem.kt │ │ │ ├── ToggleDrawerItem.kt │ │ │ ├── interfaces/ │ │ │ │ ├── Badgeable.kt │ │ │ │ ├── Checkable.kt │ │ │ │ ├── ColorfulBadgeable.kt │ │ │ │ ├── Describable.kt │ │ │ │ ├── DescribableColor.kt │ │ │ │ ├── IDrawerItem.kt │ │ │ │ ├── IProfile.kt │ │ │ │ ├── Iconable.kt │ │ │ │ ├── Nameable.kt │ │ │ │ ├── NameableColor.kt │ │ │ │ ├── SelectIconable.kt │ │ │ │ ├── Selectable.kt │ │ │ │ ├── SelectableColor.kt │ │ │ │ ├── Tagable.kt │ │ │ │ └── Typefaceable.kt │ │ │ └── utils/ │ │ │ ├── BadgeDrawableBuilder.kt │ │ │ └── DrawerItemExtensions.kt │ │ ├── util/ │ │ │ ├── AbstractDrawerImageLoader.kt │ │ │ ├── DrawerImageLoader.kt │ │ │ ├── DrawerItemViewHelper.kt │ │ │ ├── DrawerUtils.kt │ │ │ ├── Extensions.kt │ │ │ ├── FixStateListDrawable.kt │ │ │ ├── MaterialDrawerSliderViewExtensions.kt │ │ │ ├── MenuDrawerUtils.kt │ │ │ └── Utils.kt │ │ ├── view/ │ │ │ └── BezelImageView.kt │ │ └── widget/ │ │ ├── AccountHeaderView.kt │ │ ├── MaterialDrawerSliderView.kt │ │ └── MiniDrawerSliderView.kt │ └── res/ │ ├── color/ │ │ └── color_drawer_item_text.xml │ ├── drawable/ │ │ ├── material_drawer_badge.xml │ │ ├── material_drawer_circle_mask.xml │ │ ├── material_drawer_ico_account_layer.xml │ │ ├── material_drawer_ico_chevron_down.xml │ │ ├── material_drawer_ico_menu_down.xml │ │ ├── material_drawer_rectangle_mask.xml │ │ ├── material_drawer_shadow_bottom.xml │ │ └── material_drawer_shadow_top.xml │ ├── drawable-v21/ │ │ └── material_drawer_ico_account.xml │ ├── layout/ │ │ ├── material_drawer.xml │ │ ├── material_drawer_compact_header.xml │ │ ├── material_drawer_fits_not.xml │ │ ├── material_drawer_header.xml │ │ ├── material_drawer_inner_shadow.xml │ │ ├── material_drawer_item_container.xml │ │ ├── material_drawer_item_divider.xml │ │ ├── material_drawer_item_expandable.xml │ │ ├── material_drawer_item_expandable_badge.xml │ │ ├── material_drawer_item_mini.xml │ │ ├── material_drawer_item_mini_profile.xml │ │ ├── material_drawer_item_primary.xml │ │ ├── material_drawer_item_profile.xml │ │ ├── material_drawer_item_profile_setting.xml │ │ ├── material_drawer_item_secondary.xml │ │ ├── material_drawer_item_secondary_switch.xml │ │ ├── material_drawer_item_secondary_toggle.xml │ │ ├── material_drawer_item_section.xml │ │ ├── material_drawer_item_switch.xml │ │ ├── material_drawer_item_toggle.xml │ │ └── material_drawer_recycler_view.xml │ ├── values/ │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── ids.xml │ │ ├── strings.xml │ │ └── styles.xml │ ├── values-fr/ │ │ └── strings.xml │ ├── values-pt/ │ │ └── strings.xml │ └── values-sw600dp/ │ └── dimens.xml ├── materialdrawer-iconics/ │ ├── .gitignore │ ├── build.gradle.kts │ ├── gradle.properties │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ └── java/ │ └── com/ │ └── mikepenz/ │ └── materialdrawer/ │ └── iconics/ │ ├── IconicsExtension.kt │ └── IconicsImageHolder.kt ├── materialdrawer-nav/ │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── gradle.properties │ ├── proguard-rules.pro │ ├── proguard-rules.txt │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ └── java/ │ └── com/ │ └── mikepenz/ │ └── materialdrawer/ │ ├── model/ │ │ └── NavigationDrawerItem.kt │ └── util/ │ └── DrawerNavigationUI.kt └── settings.gradle.kts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: [mikepenz] ================================================ FILE: .github/ISSUE_TEMPLATE.md ================================================ ## About this issue - Briefly describe the issue - How can the issue be reproduced / sample code ## Details - [ ] Used library version - [ ] Used support library version - [ ] Used gradle build tools version - [ ] Used tooling / Android Studio version - [ ] Other used libraries, potential conflicting libraries ## Checklist - [ ] Searched for [similar issues](https://github.com/mikepenz/MaterialDrawer/issues) - [ ] Checked out the [sample application](https://github.com/mikepenz/MaterialDrawer/tree/develop/app) - [ ] Read the [README](https://github.com/mikepenz/MaterialDrawer/blob/develop/README.md) - [ ] Checked out the [CHANGELOG](https://github.com/mikepenz/MaterialDrawer/releases) - [ ] Read the [FAQ](https://github.com/mikepenz/MaterialDrawer/blob/develop/FAQ.md) - [ ] Checked out the [MIGRATION GUIDE](https://github.com/mikepenz/MaterialDrawer/blob/develop/MIGRATION.md) ================================================ FILE: .github/ci-gradle.properties ================================================ org.gradle.daemon=true org.gradle.parallel=true org.gradle.workers.max=2 org.gradle.jvmargs=-Xmx6G org.gradle.caching=true org.gradle.configureondemand=true # parallel kapt kapt.use.worker.api=true ================================================ FILE: .github/config/configuration.json ================================================ { "categories": [ { "title": "## 🚀 Features", "labels": [ "feature" ] }, { "title": "## 🐛 Fixes", "labels": [ "fix" ] }, { "title": "## 🧪 Tests", "labels": [ "test" ] }, { "title": "## 💬 Other", "labels": [ "other", "dependencies" ] } ] } ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" ================================================ FILE: .github/workflows/ci.yml ================================================ # Thanks to https://github.com/coil-kt/coil/blob/master/.github/workflows/ci.yml name: CI on: push: tags: - '*' pull_request: jobs: build: name: Build runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v6 with: fetch-depth: 100 - uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: | 11 15 17 - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 - name: Validate gradle wrapper uses: gradle/actions/wrapper-validation@v4 - name: Copy CI gradle.properties run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties - name: Build Debug run: ./gradlew clean app:assembleDebug - name: Run Lint if: github.event_name == 'pull_request' run: ./gradlew lintDebug - name: Setup Ruby if: github.event_name == 'pull_request' uses: ruby/setup-ruby@v1 with: ruby-version: '3.3' bundler-cache: true - name: Run Danger if: github.event_name == 'pull_request' run: | gem install danger bundle exec danger --dangerfile=Dangerfile --danger_id=danger-pr env: DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Prepare Keystore and Local. if: startsWith(github.ref, 'refs/tags/') run: | echo "${{ secrets.KEYSTORE }}" > opensource.jks.asc gpg -d --passphrase "${{ secrets.KEYSTORE_PASSPHRASE }}" --batch "opensource.jks.asc" > "app/opensource.jks" - name: Build Release App if: startsWith(github.ref, 'refs/tags/') run: ./gradlew app:assembleRelease app:bundleRelease -P"com.mikepenz.android.signing.enabled"="true" -P"com.mikepenz.android.signing.storeFile"="opensource.jks" -P"com.mikepenz.android.signing.storePassword"="${{ secrets.STORE_PASSWORD }}" -P"com.mikepenz.android.signing.keyAlias"="${{ secrets.KEY_ALIAS }}" -P"com.mikepenz.android.signing.keyPassword"="${{ secrets.KEY_PASSWORD }}" - name: Relase Sonatype if: startsWith(github.ref, 'refs/tags/') run: | ./gradlew build -x test -x lint ./gradlew materialdrawer:publishAllPublicationsToMavenCentralRepository -x test -x lint -Plibrary_only --no-configure-on-demand --no-parallel ./gradlew materialdrawer-nav:publishAllPublicationsToMavenCentralRepository -x test -x lint -Plibrary_nav_only --no-configure-on-demand --no-parallel ./gradlew materialdrawer-iconics:publishAllPublicationsToMavenCentralRepository -x test -x lint -Plibrary_iconics_only --no-configure-on-demand --no-parallel env: ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.NEXUS_USERNAME }} ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.NEXUS_PASSWORD }} ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_KEY_ID }} ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_PRIVATE_KEY }} ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }} - name: Collect artifacts run: | COLLECT_PWD=${PWD} mkdir -p "artifacts" find . -name "*.apk" -type f -exec cp {} "artifacts" \; find . -name "*.aab" -type f -exec cp {} "artifacts" \; - name: Archive Artifacts uses: actions/upload-artifact@v7 with: name: "App-Artifacts" path: artifacts/* - name: Build Changelog id: github_release uses: mikepenz/release-changelog-builder-action@v6 if: startsWith(github.ref, 'refs/tags/') with: configuration: ".github/config/configuration.json" ignorePreReleases: ${{ !contains(github.ref, '-') }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Release uses: mikepenz/action-gh-release@v2 if: startsWith(github.ref, 'refs/tags/') with: body: ${{steps.github_release.outputs.changelog}} prerelease: ${{ contains(github.ref, '-rc') || contains(github.ref, '-b') || contains(github.ref, '-a') }} files: artifacts/* env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/gradle-dependency-submission.yml ================================================ name: Gradle Dependency Submission on: push: branches: - develop jobs: gradle-dependency-detection: runs-on: ubuntu-latest # The Dependency Submission API requires write permission permissions: contents: write steps: - name: 'Checkout Repository' uses: actions/checkout@v6 - uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: | 11 15 17 - name: Copy CI gradle.properties run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties - name: Checkout Gradle Build Cache uses: actions/cache@v4 with: path: | ~/.gradle/caches ~/.gradle/wrapper !~/.gradle/wrapper/dists/**/gradle*.zip key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} restore-keys: | gradle-${{ runner.os }}- - name: Submit Dependency Graph uses: mikepenz/gradle-dependency-submission@main with: gradle-build-module: :app gradle-build-configuration: debugCompileClasspath sub-module-mode: INDIVIDUAL_DEEP ================================================ FILE: .gitignore ================================================ # Built application files *.apk *.ap_ # Files for the Dalvik VM *.dex # Java class files *.class # Generated files bin/ gen/ # Gradle files .gradle/ build/ /*/build/ # Local configuration file (sdk path, etc) local.properties # Proguard folder generated by Eclipse proguard/ # Log Files *.log #IntelliJ files *.iml .idea/ functiongraphic.psd /.kotlin ================================================ FILE: Dangerfile ================================================ github.dismiss_out_of_range_messages # Make it more obvious that a PR is a work in progress and shouldn't be merged yet. has_wip_label = github.pr_labels.any? { |label| label.include? "Engineers at work" } has_wip_title = github.pr_title.include? "[WIP]" if has_wip_label || has_wip_title warn("PR is marked as Work in Progress") end # Ensure the PR is not marked as DO NOT MERGE fail("PR specifies label DO NOT MERGE") if github.pr_labels.any? { |label| label.include? "DO NOT MERGE" } # Warn when there is a big PR warn("Big PR") if git.lines_of_code > 5000 File.open("settings.gradle.kts", "r") do |file_handle| file_handle.each_line do |setting| if setting.include? "include" gradleModule = setting[10, setting.length-13] # AndroidLint androidLintFile = String.new(gradleModule + "/build/reports/lint-results.xml") androidLintDebugFile = String.new(gradleModule + "/build/reports/lint-results-debug.xml") if File.file?(androidLintFile) || File.file?(androidLintDebugFile) android_lint.skip_gradle_task = true android_lint.severity = "Warning" if File.file?(androidLintFile) android_lint.report_file = androidLintFile else android_lint.report_file = androidLintDebugFile end android_lint.filtering = true android_lint.lint(inline_mode: true) end # Detekt detektFile = String.new(gradleModule + "/build/reports/detekt.xml") if File.file?(detektFile) kotlin_detekt.report_file = detektFile kotlin_detekt.skip_gradle_task = true kotlin_detekt.severity = "warning" kotlin_detekt.filtering = true kotlin_detekt.detekt(inline_mode: true) end end end end ================================================ FILE: FAQ/accountheader_single_profile_without_dropdown.md ================================================ # How can i use the AccountHeader with just one profile and disable the dropdown? This can be simply achieved by adding `headerView.selectionListEnabledForSingleProfile = false` to the `Builder` of the `AccountHeader`. This will then disable the dropdown and hide the arrow from the header. ## Sample code ```kotlin headerView.selectionListEnabledForSingleProfile = false ``` ## Links * https://github.com/mikepenz/MaterialDrawer/issues/615 * https://github.com/mikepenz/MaterialDrawer/issues/454 * https://github.com/mikepenz/MaterialDrawer/issues/443 * https://github.com/mikepenz/MaterialDrawer/issues/350 ================================================ FILE: FAQ/howto_modify_add_custom_draweritems.md ================================================ # How do I change existing or add my own CustomDrawerItems to the MaterialDrawer? Please head over here on how to implement a proper CustomDrawerItem: - http://stackoverflow.com/a/32543209/325479 - http://stackoverflow.com/a/32542999/325479 Or you check out custom drawer item implementations here: - https://github.com/mikepenz/MaterialDrawer/tree/develop/app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems You might also find some answers here: - https://github.com/mikepenz/MaterialDrawer/issues?utf8=%E2%9C%93&q=CustomDrawerItem ================================================ FILE: FAQ/howto_use_different_sub_library_version.md ================================================ # How do I use different versions of the sub dependencies like the support libraries? This can be really easy achieved by providing a resolutionStrategy to your build. ## Sample code Simple add the following to your modules build.gradle. It allows you to define whatever version you need for the sub dependencies. ```xml configurations.all { resolutionStrategy.force "com.android.support:support-v4:${versions.androidX}" resolutionStrategy.force "com.android.support:appcompat-v7:${versions.androidX}" resolutionStrategy.force "com.android.support:cardview-v7:${versions.androidX}" resolutionStrategy.force "com.android.support:recyclerview-v7:${versions.androidX}" resolutionStrategy.force "com.android.support:design:${versions.androidX}" resolutionStrategy.force "com.android.support:support-annotations:${versions.androidX}" } ``` https://github.com/mikepenz/MaterialDrawer/blob/develop/app/build.gradle ================================================ FILE: FAQ/opening-drawer-from-espresso.md ================================================ ### Q: How to open the drawer from an instrumental test written with Espresso? ### A: First, you need a add `espresso-contrib` to your project. It has the needed `DrawerActions` class. `androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2.2'` Then, you need to open the drawer with his `openDrawer()` method and the drawer layout ID. The generated one is `R.id.material_drawer_layout` `onView(withId(R.id.material_drawer_layout)).perform(DrawerActions.open());` ================================================ FILE: FAQ/when_to_use_this_library.md ================================================ ### Developer: Since there is MaterialDrawer in Support Library, could you give a couple of points why to use your library instead of from Support Library one? ### Author: Well, that really depends on the use case of the drawer in this project, and which functionalities + which customizations are needed. The MaterialDrawer was created long before Google came up with their drawer in the design support libraries. Basically, the one of Google is definitely great and I recommend it to being used in all cases where it is enough. I am a fan of keeping things as simple as possible, as it will have the great effect on the user experience. So if this project only needs a very minimal drawer implementation, with just `Main` items, no `profile` functionality, and no great flexibility (no custom items, no custom styles, ... no advanced API for doing stuff programmatically) then you should definitely consider using the one from the design library. If you have a more advanced use case, like using the profile switcher, the profile page, custom items like different sizes, or checkboxes, etc then you might want to stay with my library. ================================================ FILE: FAQ.md ================================================ # FAQ / WIKI This is the official **MaterialDrawer** FAQ/Wiki. People can contribute to it through pull requests. Each question and it's answer is hosted in a separate file within the FAQ folder. ## MaterialDrawer * [Should I use this library or Material Drawer from the Support library?](FAQ/when_to_use_this_library.md) * [How do I make the drawer appear underneath the Toolbar?](FAQ/howto_show_drawer_under_toolbar.md) * [How do I create a Multi-pane layout with MaterialDrawer for tablets?](FAQ/howto_show_drawer_in_tablet_multipane.md) * [Why is there whitespace where the status bar should be while my theme is set as fullscreen ?](FAQ/status_bar_whitespace.md) * [How do I change existing or add my own CustomDrawerItems to the MaterialDrawer?](FAQ/howto_modify_add_custom_draweritems.md) * [How to use different dependency library versions](FAQ/howto_use_different_sub_library_version.md) ## AccountHeader * [How can I use the AccountHeader with just one profile and disable the dropdown?](FAQ/accountheader_single_profile_without_dropdown.md) ## Testing * [How can I open the drawer from an instrumental test written with Espresso?](FAQ/opening-drawer-from-espresso.md) ## CustomDrawerItem's * [A custom SecondaryDrawerItem that takes different name when its on disabled state](https://gist.github.com/AngleV/400377184386193c985d905bd97f2d40) ## Asked super frequently ### How can i create a drawer without a default selection ```kotlin //just set the selection to -1 slider.setSelectionAtPosition(-1) ``` ### Can I lock the Drawer As the MaterialDrawer will just create a normal DrawerLayout (with some magic around it) everything a normal DrawerLayout can do is also available in the MaterialDrawer. ```kotlin drawerLayout.setDrawerLockMode(int lockMode); //or (int lockMode, int edgeGravity) ``` ================================================ FILE: Gemfile ================================================ # frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem 'danger' gem 'danger-android_lint' gem 'danger-kotlin_detekt' ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2021 Mike Penz Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: MIGRATION.md ================================================ ### Upgrade Notes #### v8.0.0 - Ground up refactor of the way the `MaterialDrawer` is used and integrated into the app. - Please consider carefully before upgrading to this version. - Prior to v8 the `Drawer` would automatically inject the `DrawerLayout` into the layout hierarchy, apply window flags, and take over control of the `ActionBarDrawerToggle`. - This may seem convenient for easy usecases, but created big problems for more advanced implementations where taking over window insets is expected - v8 will no longer do any of this, and gives back all the control to the developer, no more unexpected layout flags, changes to the layout hierarchy or anything similar. - The core principle behind v8 is to offer just the UI and give back all control to developers. - Additionally v8 eliminates dependencies on `Materialize`, `Android-Iconics` - v8 also now comes with better theming support and better dark mode support - As v8 is ground up different in the way it is set up it is recommended to re-read the README and check out the sample again - Basic upgrade procedure: - Add `DrawerLayout` into your layout - Add `MaterialDrawerSliderView` as child to the `DrawerLayout` - Find the reference to the `MaterialDrawerSliderView` in your `Activity` / `Fragment` - Use the `MaterialDrawerSliderView` to fill the list / do updates - Basic upgrade prodedure for the `AccountHeader`: - Create an instance of the `AccountHeaderView` - Attach to the slider via `attachToSliderView(slider)` - Additionally v8 is more optimized for Kotlin meaning all legacy `with(*)` methods were replaced (kept as extension functions as legacy support) with properties ##### Note - Please report if additional upgrade notes are required #### v7.0.0 Now library is kotlin-first. * this release contains a big amount of changes, including many breaking API changes to make its implementation easier, and make the APIs better compatible with kotlin. * please note that the interface for items changed in the `FastAdapter` as such migrating to the new version will require more effort. * Update `FastAdapter` to v4 and make all relevant adjustments to the provided `DrawerItem`s * Check the `FastAdapter` changelog and [migration guide](https://github.com/mikepenz/FastAdapter/blob/develop/MIGRATION.md) * Update `Android-Iconics` to v4 * Ensure to update `Android-Iconics` for your project, and use the updated kotlin icon dependencies * See the migration notes for `Android-Iconics` if you run into problems * The general interfaces and everything stayed the same, and mainly everything was migrated to kotlin If you have any issues during the migration, or any questions come up please open a github issue so we can improve the migration guide or the documentation. #### v6.1.1 * Further adjustments for the theme to properly meet the new material 2 design guidelines. ```xml @color/material_drawer_header_selection_subtext ``` #### v6.1.0-rc01.2 * With the introduction of the material 2 design behaviour, new theme attributes were added. ```xml @color/material_drawer_selected true ``` * Reworked the header views to be a lot more simple by using a `ConstraintLayout` * Any previously custom headers require to be adjusted to the new structure. (The statusbar `Guideline` is required, for example) * The viewHolder.item has no longer the item itself as tag directly. It is now defined with an id `R.id.material_drawer_item`. `ViewHolder.itemView.getTag(R.id.material_drawer_item)` will now return the `IDrawerItem`. #### v6.1.0-rc01 * Final upgrade to the new shiny androidX dependencies :) #### v6.0.3 **IMPORTANT IF YOU USE THE FASTADAPTER OR ABOUTLIBRARIES** * You have to update your FastAdapter dependency to v3.2.1 with this release * See the MIGRATION information of the FastAdapter https://github.com/mikepenz/FastAdapter/blob/develop/MIGRATION.md #### v6.0.0 **IMPORTANT IF YOU USE THE FASTADAPTER OR ABOUTLIBRARIES** * You have to update your FastAdapter dependency to v3.0.0 with this release * See the MIGRATION information of the FastAdapter https://github.com/mikepenz/FastAdapter/blob/develop/MIGRATION.md #### v5.9.0 & v5.9.2 **IMPORTANT IF YOU USE THE FASTADAPTER OR ABOUTLIBRARIES** * You have to update your FastAdapter dependency to v2.5.0 with this release * See the MIGRATION information of the FastAdapter https://github.com/mikepenz/FastAdapter/blob/develop/MIGRATION.md #### v5.8.0 **IMPORTANT IF YOU USE THE FASTADAPTER OR ABOUTLIBRARIES** * You have to update your FastAdapter dependency to v2.1.0 with this release * See the MIGRATION information of the FastAdapter https://github.com/mikepenz/FastAdapter/blob/develop/MIGRATION.md #### v5.7.0 **IMPORTANT IF YOU IMPLEMENT CUSTOM-DRAWER-ITEMS OR USE THE FASTADAPTER** * You have to update your `FastAdapter` dependency to v2.0.0 with this release * If you have `CustomDrawerItem`'s not based on the `AbstractDrawerITems` make sure you implement the `unbindView` method, and the new required methods * See the MIGRATION information of the **FastAdapter** https://github.com/mikepenz/FastAdapter/blob/develop/MIGRATION.md #### v5.6.0 **IMPORTANT IF YOU IMPLEMENT CUSTOM-DRAWER-ITEMS OR USE THE FASTADAPTER** * This release brings a breaking interface change. Your items now have to implement `bindView(ViewHolder holder, List payloads)` instead of `bindView(VH holder)`. * The additional payload can be used to implement a more performant view updating when only parts of the item have changed. Please also refer to the `DiffUtils` which may provide the payload. #### v5.5.1 * add `void set(ImageView imageView, Uri uri, Drawable placeholder, String tag);` to `IDrawerImageLoader` interface, similar to the `tag` provided in the placeholder method #### v5.5.0 * **Dropping support for API < 14. New MinSdkVersion is 14** #### v5.3.3 -> 5.3.4 * If you use the `FastAdapter` please read the upgrade notes for v1.6.0 (https://github.com/mikepenz/FastAdapter/releases/tag/v1.6.0) #### v5.3.1 -> v5.3.2 * the `withOnMiniDrawerItemClickListener` was renamed to `withOnMiniDrawerItemOnClickListener` * added new separate `OnMiniDrawerItemClickListener` which allows to hook into the default behavior, and prevent it if necessary * NOTE: this one now uses the `withOnMiniDrawerItemClickListener` method. #### v5.2.0 -> v5.2.1 * the `SecondaryDrawerItem` is now a subclass of the `PrimaryDrawerItem` (extends `PrimaryDrawerItem`). If you have an `if` which checks for the type with `instanceOf` make sure you check for the `SecondaryDrawerItem` first. (`secondaryDrawerItem instanceOf PrimaryDrawerItem == true`) #### v5.1.6 -> 5.1.8 * if you use the `FastAdapter` please check out the release notes of v1.4.0 (https://github.com/mikepenz/FastAdapter/releases/tag/v1.4.0) #### v5.0.0 -> 5.0.5 * the `expanding` functionality is now handled by the `FastAdapter` so the toggling code is no longer needed. See the following diff for the change (just the `DrawerActivity`) https://github.com/mikepenz/MaterialDrawer/commit/88e9bdf8cccaac5aaf567ac6ffe682aeccba4f29 #### v4.6.0 -> v5.0.0 * the identifier was changed from `int` to `long` as the internal adapter (FastAdapter) uses `long` to identify items (as the `Adapter` does) * v5.0.0 no longer sets the `FULL_SCREEN` flag to get the drawer below the `StatusBar` it now uses the `fitsSystemWindows` everywhere. This should improve compatiblity with a lot of things like the `CoordinatorLayout` and should also improve compatiblity with future Android updates * removed the following methods: * DrawerUIUtils.getScreenWidth -> moved to UIUtils from the `Materialize` library * DrawerBuilder.withTranslucentStatusBarProgrammatically -> no longer necessary as we now depend on the `fitsSystemWindows` flag * `StatusBarColor` can now be set via the `Drawer.getDrawerLayout().setStatusBarBackgroundColor(color)` * DrawerBuilder.keyboardSupportEnabled -> `KeyboardUtil` should no longer be necessary * `StatusBar` on **API < 21** is no longer colored, because of the changed way how we display the `Drawer` under the `StatusBar` * `DrawerItems` changed. Please take a look at the `CustomDrawerItems` from the sample or the default ones, to add the changes to your `CustomDrawerItems` * ... #### v4.5.9 -> v4.6.0 * it is now possible to let the `Drawer` manage the `MiniDrawer`. Enable this via `withGenerateMiniDrawer(true)`. Afterwards remove the `MiniDrawer` calls inside the listeners, those are now done within the `Drawer`. You can get the `MiniDrawer` result object via `Drawer.getMiniDrawer();` #### v4.3.7 -> v4.4.3 * added new method `withHeaderPadding` to the drawer and `withPaddingBelowHeader` to the header to control the padding separately from the `divider`which can be controlled via `withHeaderDivider` #### v4.3.7 * depends on the latest `v23.1.0` **support libraries**. Those also require you to have `compileSDKVersion 23` #### v4.2.0 -> v4.3.0 * new `placeholder(Context ctx, String tag)` to the `IDrawerImageLoader` interface * new `AbstractDrawerImageLoader` to simplify the `DrawerImageLoader` usage. See the new implementation in the `CustomApplication` * to keep the old behavior just change from `new DrawerImageLoader.IDrawerImageLoader() {` to `new AbstractDrawerImageLoader() {` for the `DrawerImageLoader.init` * add new `tag` to the placeholder, to be able to define different placeholders for different targets #### v4.2.0 * no more need to define an identifier for the items, they get one automatically. if you do not have logics which require you to do so, you are safe to forget about the identifier now. #### v4.0.2 -> v4.0.7 * renamed `setDivider()` to `withDivider` * remove `setTypeface()` use `withTypeface()` instead #### v4.0.0 -> v4.0.2 * `getCurrentSelection()` will now return the `identifier` of the current selection or `null` * `getCurrentSelectedPosition()` was added * renamed all `*Footer*` methods to `*StickyFooter*` to prevent confusion #### < v4.0.0 ##### Common changes * depends on the latest `v23` **support libraries**. Those also require you to have `compileSDKVersion 23` * change the `onItemClick` listener to `onItemClick(View view, int i, IDrawerItem iDrawerItem)` * modify the import of the `AccountHeader` and `AccountHeaderBuilder` to ```gradle import com.mikepenz.materialdrawer.AccountHeader import com.mikepenz.materialdrawer.AccountHeaderBuilder ``` * the `identifier` should now be set for the `DrawerItems` as it is used now as default for all update/modify/.. actions * rename `withCheckable()` to `withSelectable()` * rename `set*` methods of the `DrawerItems` to `with*` methods as those were renamed * rename all methods like `setSelection`, `setFooterSelection`, `removeItem`, ... to `*ByPosition` (added the **ByPosition**) * rename all methods like `setSelectionByIdentifier`, `setFooterSelectionByIdentifier`, ... to `setSelection`, `setFooterSelection` (removed the **ByIdentifier**) * change `updateName`, `updateIcon`, `updateBadge` those methods take now an `identifier` and the specific `Holder` object * all `get*` methods of the `DrawerItems` will now return a `Holder` object for the specific type, making it easier to work with types like `String`, `StringRes`, `Color`, `ColorRes`, `ColorInt`, .. ##### Android-Iconics (icon font) * the MaterialDrawer now only includes the `core` of the Android-Iconics project * add the fonts you use https://github.com/mikepenz/Android-Iconics#2-choose-your-desired-fonts * pre MaterialDrawer v4.0.0 following fonts were included ```gradle compile 'com.mikepenz:google-material-typeface:1.2.0.1@aar' //Google Material Design Icons compile 'com.mikepenz:fontawesome-typeface:4.4.0.1@aar' //FontAwesome **NOTE:** the packagename changed for this font ``` ##### Advanced usage changes * changed the `ListView` to a `RecyclerView` * rename methods with `*ListView*` to `*RecyclerView*` * the `IDrawerItem` interface was extended to better reflect a `RecyclerView` and to improve performance * added an `AbstractDrawerItem` to implement some common methods * see the [SectionDrawerItem](https://github.com/mikepenz/MaterialDrawer/blob/feature/refactoring/library/src/main/java/com/mikepenz/materialdrawer/model/SectionDrawerItem.java) for an easy example ================================================ FILE: README.md ================================================ # MaterialDrawer ... the flexible, easy to use, all in one drawer library for your Android project. -------

What's included 🚀Setup 🛠️Migration Guide 🧬WIKI / FAQ 📖Used bySample App

------- ### What's included 🚀 - **the easiest possible integration** - **uses the androidX support libraries** - compatible down to **API Level 16** - includes an **AccountSwitcher** - quick and simple api - follows the **NEW Google Material Design Guidelines** - use **vector** (.svg) icons and **icon fonts** via the [Android-Iconics](https://github.com/mikepenz/Android-Iconics) integration - **Google Material Design Icons**, Google **Material Community** Design Icons, FontAwesome and more - comes with various **themes** which help to get your own themes clean - modify the colors on the go - comes with multiple default drawer items - based on a **RecyclerView** - **RTL** support - Gmail like **MiniDrawer** - expandable items - **badge** support - define custom drawer items - tested and **stable** - sticky footer or headers - **absolutely NO limits** - NavController support by @petretiandrea > If you upgrade from < 8.0.0 follow the [MIGRATION GUIDE](https://github.com/mikepenz/MaterialDrawer/blob/develop/MIGRATION.md) # Preview ## Screenshots 🎉 ![Image](DEV/github/screenshots_combined.jpg) # Setup ## Latest releases 🛠 - Kotlin && M3 && JVM 17 | [v10.0.0-b01](https://github.com/mikepenz/MaterialDrawer/tree/v10.0.0-b01) - Kotlin && Material 3 | [v9.0.2](https://github.com/mikepenz/MaterialDrawer/tree/v9.0.2) - Kotlin | [v8.4.5](https://github.com/mikepenz/MaterialDrawer/tree/v8.4.5) (Provided as-is only) - Java && AndroidX | [v6.1.2](https://github.com/mikepenz/MaterialDrawer/tree/v6.1.2) (Provided as-is only) - Java && AppCompat | [v6.0.9](https://github.com/mikepenz/MaterialDrawer/tree/v6.0.9) (Provided as-is only) ### 1. Provide the gradle dependency The latest release is available on [Maven Central](https://search.maven.org/artifact/com.mikepenz/materialdrawer/9.0.1/aar). ```gradle implementation("com.mikepenz:materialdrawer:${latestRelease}") ``` ```gradle //required support lib modules implementation "androidx.appcompat:appcompat:${versions.appcompat}" implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}" implementation "androidx.annotation:annotation:${versions.annotation}" implementation "com.google.android.material:material:1.5.0-alpha05" // requires at least 1.5.0-x implementation "androidx.constraintlayout:constraintlayout:${versions.constraintLayout}" ``` [NavController Support @ Maven Central](https://search.maven.org/artifact/com.mikepenz/materialdrawer-nav/9.0.1/aar). ```gradle // Add for NavController support implementation "com.mikepenz:materialdrawer-nav:${lastestMaterialDrawerRelease}" ``` [Android-Iconics Support @ Maven Central](https://search.maven.org/artifact/com.mikepenz/materialdrawer-iconics/9.0.1/aar) . ```gradle // Add for Android-Iconics support implementation "com.mikepenz:materialdrawer-iconics:${lastestMaterialDrawerRelease}" ``` ### 2. Add the `Drawer` into the XML The `MaterialDrawerSliderView` has to be provided as child of the `DrawerLayout` and will as such act as the slider ```kotlin ... your content ... ``` ### 3. Add the `DrawerStyle` to your theme ```xml ``` Great. Your drawer is now ready to use. ### Note > Using v9.x with Material 3 theming requires a `Material3` theme as base for the activity. # Additional Setup ### Add items and adding some functionality ```kotlin //if you want to update the items at a later time it is recommended to keep it in a variable val item1 = PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_home; identifier = 1 } val item2 = SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_settings; identifier = 2 } // get the reference to the slider and add the items slider.itemAdapter.add( item1, DividerDrawerItem(), item2, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_settings } ) // specify a click listener slider.onDrawerItemClickListener = { v, drawerItem, position -> // do something with the clicked item :D false } ``` ### Selecting an item ```kotlin //set the selection to the item with the identifier 1 slider.setSelection(1) //set the selection to the item with the identifier 2 slider.setSelection(item2) //set the selection and also fire the `onItemClick`-listener slider.setSelection(1, true) ``` By default, when a drawer item is clicked, it becomes the new selected item. If this isn't the expected behavior, you can disable it for this item using `isSelectable = false`: ```kotlin SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_dialog; isSelectable = false } ``` ### Modify items or the drawer ```kotlin //modify an item of the drawer item1.apply { nameText = "A new name for this drawerItem"; badge = StringHolder("19") badgeStyle = BadgeStyle().apply { textColor = ColorHolder.fromColor(Color.WHITE); color = ColorHolder.fromColorRes(R.color.md_red_700) } } //notify the drawer about the updated element. it will take care about everything else slider.updateItem(item1) //to update only the name, badge, icon you can also use one of the quick methods slider.updateName(1, "A new name") //the result object also allows you to add new items, remove items, add footer, sticky footer, .. slider.addItem(DividerDrawerItem()) slider.addStickyFooterItem(PrimaryDrawerItem().apply { nameTest = "StickyFooter" }) //remove items with an identifier slider.removeItem(2) //open / close the drawer slider.drawerLayout?.openDrawer(slider) slider.drawerLayout?.closeDrawer(slider) //get the reference to the `DrawerLayout` itself slider.drawerLayout ``` ### Add profiles and an AccountHeader ```kotlin // Create the AccountHeader headerView = AccountHeaderView(this).apply { attachToSliderView(slider) // attach to the slider addProfiles( ProfileDrawerItem().apply { nameText = "Mike Penz"; descriptionText = "mikepenz@gmail.com"; iconRes = R.drawable.profile; identifier = 102 } ) onAccountHeaderListener = { view, profile, current -> // react to profile changes false } withSavedInstance(savedInstanceState) } ``` ### Android-Iconics support The MaterialDrawer provides an extension for the [Android-Iconics](https://github.com/mikepenz/Android-Iconics) library. This allows you to create your `DrawerItems` with an icon from any font. Choose the fonts you need. [Available Fonts](https://github.com/mikepenz/Android-Iconics#2-choose-your-desired-fonts) ```gradle // Add for Android-Iconics support implementation "com.mikepenz:materialdrawer-iconics:${lastestMaterialDrawerRelease}" // fonts implementation 'com.mikepenz:google-material-typeface:x.y.z@aar' //Google Material Icons implementation 'com.mikepenz:fontawesome-typeface:x.y.z@aar' //FontAwesome ``` ```kotlin //now you can simply use any icon of the Google Material Icons font PrimaryDrawerItem().apply { iconicsIcon = GoogleMaterial.Icon.gmd_wb_sunny } //Or an icon from FontAwesome SecondaryDrawerItem().apply { iconicsIcon = FontAwesomeBrand.Icon.fab_github } ``` # Advanced Setup For advanced usecases. Please have a look at the provided sample activities. ## Load images via url The MaterialDrawer supports fetching images from URLs and setting them for the Profile icons. As the MaterialDrawer does not contain an ImageLoading library the dev can choose his own implementation (Picasso, Glide, ...). This has to be done, before the first image should be loaded via URL. (Should be done in the Application, but any other spot before loading the first image is working too) * SAMPLE using [PICASSO](https://github.com/square/picasso) * [SAMPLE](https://github.com/mikepenz/MaterialDrawer/blob/develop/app/src/main/java/com/mikepenz/materialdrawer/app/CustomApplication.kt) using [GLIDE](https://github.com/bumptech/glide) ```kotlin //initialize and create the image loader logic DrawerImageLoader.init(object : AbstractDrawerImageLoader() { override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable) { Picasso.get().load(uri).placeholder(placeholder).into(imageView) } override fun cancel(imageView: ImageView) { Picasso.get().cancelRequest(imageView) } /* override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) { super.set(imageView, uri, placeholder, tag) } override fun placeholder(ctx: Context): Drawable { return super.placeholder(ctx) } override fun placeholder(ctx: Context, tag: String?): Drawable { return super.placeholder(ctx, tag) } */ }) ``` An implementation with [GLIDE v4](https://github.com/mikepenz/MaterialDrawer/blob/develop/app/src/main/java/com/mikepenz/materialdrawer/app/CustomApplication.kt) (See tag v6.1.1 for glide v3 sample) can be found in the sample application ## JVM Target 1.8 ``` // Since 8.1.0 the drawer includes core ktx 1.3.0 which requires jvm 1.8 kotlinOptions { jvmTarget = "1.8" } ``` ## Style the drawer 🖌️ ### Custom style - styles.xml Create your custom style. If you don't need a custom theme see the next section, how you can set the colors just by overwriting the original colors. ```xml // define a custom drawer style // define a custom header style // define the custom styles for the theme ``` ### Adjust BezelImageView style Overwrite the Style of the BezelImageView for the whole MaterialDrawer ```xml ``` # Used by (feel free to send me new projects) * [Screener](https://play.google.com/store/apps/details?id=de.toastcode.screener) * [Meldmail](https://play.google.com/store/apps/details?id=com.meldmail) * [Academic Schedule](https://play.google.com/store/apps/details?id=com.auebcsschedule.ppt) * [Sprit Club](https://play.google.com/store/apps/details?id=at.idev.spritpreise) * [StickyNotes](https://play.google.com/store/apps/details?id=com.jsvmsoft.stickynotes) * [MLManager](https://github.com/javiersantos/MLManager) * [Fimpl](https://play.google.com/store/apps/details?id=com.danielZET.fimpl) * [Teacher Gradebook](https://play.google.com/store/apps/details?id=com.apolosoft.cuadernoprofesor) * [AS Sales Management](https://play.google.com/store/apps/details?id=com.armsoft.mtrade) * [Sporza Voetbal](http://play.google.com/store/apps/details?id=be.vrt.mobile.android.sporza.voetbal) * [Atmosphere](https://play.google.com/store/apps/details?id=com.peakpocketstudios.atmosphere) * [Fitness Challenge](https://play.google.com/store/apps/details?id=com.isidroid.fitchallenge) * [I'm Reading Quran - Kur'an Okuyorum](https://play.google.com/store/apps/details?id=com.homemade.kuranokuma) * [Makota Money Manager](https://play.google.com/store/apps/details?id=be.jatra.makota) * [Companion for Band](https://github.com/adithya321/Companion-for-Band) * [Recipedia](https://play.google.com/store/apps/details?id=com.md.recipedia) * [Right Сourse - ruble course](https://play.google.com/store/apps/details?id=com.currency.work.currencychecker) * [Gameru](https://play.google.com/store/apps/details?id=net.gameru) * [Boost for reddit](https://play.google.com/store/apps/details?id=com.rubenmayayo.reddit) * [Calendula](https://github.com/citiususc/calendula) * [MyTimes](https://github.com/debo1994/MyTimes) * [VoIP By Antisip](https://play.google.com/store/apps/details?id=com.antisip.vbyantisip) * [MBox - One Place for Entertainment](https://play.google.com/store/apps/details?id=com.paperwrrk.android.mbox) * [D Notes - Smart and Material Note Taking](https://play.google.com/store/apps/details?id=com.dvdb.bergnotes) * [Moviebase](https://play.google.com/store/apps/details?id=com.moviebase) * [MyFuelLog2](https://play.google.com/store/apps/details?id=com.acty.myfuellog2) * [MECSol](https://play.google.com/store/apps/details?id=tk.rlta.mecsol) * [3D Geeks: Thingiverse Browser for 3D Printing](https://play.google.com/store/apps/details?id=work.twob.threed) * [Tusky: Mastodon Client for Android](https://github.com/tuskyapp/Tusky) * [Tibia Live](https://tibia.space/) * [Walkaholic](https://play.google.com/store/apps/details?id=com.walkaholic.hikeapp) * [Pachli: Mastodon Client](https://pachli.app) # Articles about the MaterialDrawer * [java-help.ru - MaterialDrawer tutorial](http://java-help.ru/material-navigationdrawer/) * [MaterialDrawer in multiple activities](https://android.jlelse.eu/android-using-navigation-drawer-across-multiple-activities-the-easiest-way-b011f152aebd) # Credits - Mirosław Stanek - [GitHub](https://github.com/frogermcs) - For his InstaMaterial concept and the idea of inflating the drawerLayout [InstaMaterial Concept](http://frogermcs.github.io/InstaMaterial-concept-part-7-navigation-drawer/) - Lunae Luman - [Behance](https://www.behance.net/gallery/18526001/Material-Wallpaper) for the Header Image # Developed By - Mike Penz - [mikepenz.dev](https://mikepenz.dev) - [blog.mikepenz.dev](https://blog.mikepenz.dev) - - [paypal.me/mikepenz](http://paypal.me/mikepenz) - [Automatic changelog generation action](https://github.com/marketplace/actions/release-changelog-builder) # License Copyright 2021 Mike Penz Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: app/.gitignore ================================================ /build ================================================ FILE: app/build.gradle.kts ================================================ plugins { id("com.mikepenz.convention.android-application") id("com.mikepenz.convention.kotlin") id("com.mikepenz.aboutlibraries.plugin") id("androidx.navigation.safeargs.kotlin") } android { namespace = "com.mikepenz.materialdrawer.app" defaultConfig { multiDexEnabled = true setProperty("archivesBaseName", "MaterialDrawer-v$versionName-c$versionCode") } productFlavors { } buildFeatures { viewBinding = true } packaging { resources { excludes.add("META-INF/library-core_release.kotlin_module") excludes.add("META-INF/library_release.kotlin_module") } } } dependencies { implementation(project(":materialdrawer")) implementation(project(":materialdrawer-iconics")) implementation(project(":materialdrawer-nav")) implementation(libs.google.material) implementation(libs.androidx.cardView) implementation(libs.androidx.recyclerView) implementation(libs.androidx.navigation.fragment) implementation(libs.androidx.navigation.ui) // used to showcase how to load images implementation("io.coil-kt:coil:2.7.0") //used to provide different itemAnimators for the RecyclerView //https://github.com/mikepenz/ItemAnimators implementation(libs.itemAnimators.core) // used to provide out of the box icon font support. simplifies development, // and provides scalable icons. the core is very very light // https://github.com/mikepenz/Android-Iconics implementation(libs.iconics.core) // used to generate the Open Source section // https://github.com/mikepenz/AboutLibraries implementation(baseLibs.aboutlibraries.view) // used to provide the MiniDrawer to normal Drawer crossfade effect via a SlidingPane layout // --> https://github.com/mikepenz/MaterialDrawer/blob/develop/app/src/main/java/com/mikepenz/materialdrawer/app/MiniDrawerActivity.java // https://github.com/mikepenz/Crossfader implementation("com.mikepenz:crossfader:1.6.0@aar") // used to provide the two step crossfade DrawerLayout. Which allows to have a mini layout which transforms to a normal layout within the drawer // --> https://github.com/mikepenz/MaterialDrawer/blob/develop/app/src/main/java/com/mikepenz/materialdrawer/app/CrossfadeDrawerLayoutActvitiy.java // https://github.com/mikepenz/CrossfadeDrawerLayout implementation("com.mikepenz:crossfadedrawerlayout:1.1.0@aar") // icon fonts used inside the sample // https://github.com/mikepenz/Android-Iconics implementation("com.mikepenz:google-material-typeface:4.0.0.2-kotlin@aar") implementation("com.mikepenz:fontawesome-typeface:5.13.3.0-kotlin@aar") implementation("com.mikepenz:octicons-typeface:11.1.0.0-kotlin@aar") implementation("androidx.multidex:multidex:2.0.1") implementation("androidx.slidingpanelayout:slidingpanelayout:1.1.0") { version { strictly("1.1.0") } } implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") } configurations.configureEach { resolutionStrategy.force(libs.fastAdapter.core) resolutionStrategy.force(libs.iconics.core) } ================================================ FILE: app/gradle.properties ================================================ com.mikepenz.compose.enabled=false ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /Entwicklung/android-sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/ActionBarActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.os.Bundle import android.view.MenuItem import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.materialdrawer.app.databinding.ActivitySampleActionbarBinding import com.mikepenz.materialdrawer.iconics.iconicsIcon import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.SecondaryDrawerItem import com.mikepenz.materialdrawer.model.interfaces.Nameable import com.mikepenz.materialdrawer.model.interfaces.nameRes class ActionBarActivity : AppCompatActivity() { private lateinit var binding: ActivitySampleActionbarBinding override fun onCreate(savedInstanceState: Bundle?) { //supportRequestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); super.onCreate(savedInstanceState) binding = ActivitySampleActionbarBinding.inflate(layoutInflater).also { setContentView(it.root) } setTitle(R.string.drawer_item_action_bar_drawer) binding.slider.apply { itemAdapter.add( PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_home iconicsIcon = FontAwesome.Icon.faw_home }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_settings iconicsIcon = FontAwesome.Icon.faw_cog } ) onDrawerItemClickListener = { _, drawerItem, _ -> if (drawerItem is Nameable) { Toast.makeText(this@ActionBarActivity, (drawerItem as Nameable).name!!.getText(this@ActionBarActivity), Toast.LENGTH_SHORT).show() } false } setSavedInstance(savedInstanceState) } supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setHomeButtonEnabled(false) } override fun onSaveInstanceState(_outState: Bundle) { //add the values which need to be saved from the drawer to the bundle super.onSaveInstanceState(binding.slider.saveInstanceState(_outState)) } override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { android.R.id.home -> { onBackPressed() true } else -> super.onOptionsItemSelected(item) } } override fun onBackPressed() { //handle the back press :D close the drawer first and if the drawer is closed close the activity if (binding.root.isDrawerOpen(binding.slider)) { binding.root.closeDrawer(binding.slider) } else { super.onBackPressed() } } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/AdvancedActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.content.res.Configuration import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.widget.Toast import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.PopupMenu import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesomeBrand import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.iconics.utils.actionBar import com.mikepenz.iconics.utils.backgroundColorRes import com.mikepenz.iconics.utils.paddingDp import com.mikepenz.iconics.utils.sizeDp import com.mikepenz.materialdrawer.app.databinding.ActivitySampleBinding import com.mikepenz.materialdrawer.app.drawerItems.CustomPrimaryDrawerItem import com.mikepenz.materialdrawer.app.drawerItems.CustomUrlPrimaryDrawerItem import com.mikepenz.materialdrawer.app.drawerItems.OverflowMenuDrawerItem import com.mikepenz.materialdrawer.holder.ColorHolder import com.mikepenz.materialdrawer.holder.ImageHolder import com.mikepenz.materialdrawer.holder.StringHolder import com.mikepenz.materialdrawer.iconics.iconicsIcon import com.mikepenz.materialdrawer.model.* import com.mikepenz.materialdrawer.model.interfaces.* import com.mikepenz.materialdrawer.util.addStickyDrawerItems import com.mikepenz.materialdrawer.widget.AccountHeaderView class AdvancedActivity : AppCompatActivity() { private lateinit var binding: ActivitySampleBinding private lateinit var headerView: AccountHeaderView private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle private lateinit var profile: IProfile private lateinit var profile2: IProfile private lateinit var profile3: IProfile private lateinit var profile4: IProfile private lateinit var profile5: IProfile override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivitySampleBinding.inflate(layoutInflater).also { setContentView(it.root) } // Handle Toolbar setSupportActionBar(binding.toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setHomeButtonEnabled(true) supportActionBar?.setTitle(R.string.drawer_item_advanced_drawer) actionBarDrawerToggle = ActionBarDrawerToggle(this, binding.root, binding.toolbar, com.mikepenz.materialdrawer.R.string.material_drawer_open, com.mikepenz.materialdrawer.R.string.material_drawer_close) // Create a few sample profile profile = ProfileDrawerItem().apply { nameText = "Mike Penz"; descriptionText = "mikepenz@gmail.com"; iconRes = R.drawable.profile } profile2 = ProfileDrawerItem().apply { nameText = "Max Muster"; descriptionText = "max.mustermann@gmail.com"; iconRes = R.drawable.profile2; identifier = 2 } profile3 = ProfileDrawerItem().apply { nameText = "Felix House"; descriptionText = "felix.house@gmail.com"; iconRes = R.drawable.profile3 } profile4 = ProfileDrawerItem().apply { nameText = "Mr. X"; descriptionText = "mister.x.super@gmail.com"; iconRes = R.drawable.profile4; identifier = 4 } profile5 = ProfileDrawerItem().apply { nameText = "Batman"; descriptionText = "batman@gmail.com"; iconRes = R.drawable.profile5 } // Create the AccountHeader buildHeader(false, savedInstanceState) binding.slider.apply { itemAdapter.add( PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_home; iconicsIcon = FontAwesome.Icon.faw_home }, //here we use a customPrimaryDrawerItem we defined in our sample app //this custom DrawerItem extends the PrimaryDrawerItem so it just overwrites some methods OverflowMenuDrawerItem().apply { nameRes = R.string.drawer_item_menu_drawer_item; descriptionRes = R.string.drawer_item_menu_drawer_item_desc; menu = R.menu.fragment_menu onMenuItemClickListener = PopupMenu.OnMenuItemClickListener { item -> Toast.makeText(this@AdvancedActivity, item.title, Toast.LENGTH_SHORT).show() false } iconicsIcon = GoogleMaterial.Icon.gmd_filter_center_focus }, CustomPrimaryDrawerItem().apply { nameRes = R.string.drawer_item_free_play; iconicsIcon = FontAwesome.Icon.faw_gamepad; background = ColorHolder.fromColorRes(R.color.colorAccent) }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_custom; descriptionText = "This is a description"; iconicsIcon = FontAwesome.Icon.faw_eye }, CustomUrlPrimaryDrawerItem().apply { nameRes = R.string.drawer_item_fragment_drawer; description = StringHolder(R.string.drawer_item_fragment_drawer_desc); iconUrl = "https://avatars3.githubusercontent.com/u/1476232?v=3&s=460" }, SectionDrawerItem().apply { nameRes = R.string.drawer_item_section_header }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_settings; iconicsIcon = FontAwesome.Icon.faw_cart_plus }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_help; iconicsIcon = FontAwesome.Icon.faw_database; isEnabled = false }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_open_source; iconicsIcon = FontAwesomeBrand.Icon.fab_github }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_contact; tag = "Bullhorn"; iconDrawable = IconicsDrawable(this@AdvancedActivity, GoogleMaterial.Icon.gmd_add).apply { actionBar(); paddingDp = 5 }; isIconTinted = true }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_help; iconicsIcon = FontAwesome.Icon.faw_question; isEnabled = false } ) addStickyDrawerItems( SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_settings; iconicsIcon = FontAwesome.Icon.faw_cog; identifier = 10 }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_open_source; iconicsIcon = FontAwesomeBrand.Icon.fab_github } ) onDrawerItemClickListener = { _, drawerItem, _ -> if (drawerItem is Nameable) { Toast.makeText(this@AdvancedActivity, drawerItem.name?.getText(this@AdvancedActivity), Toast.LENGTH_SHORT).show() } false } setSavedInstance(savedInstanceState) } } /** * small helper method to reuse the logic to build the AccountHeader * this will be used to replace the header of the drawer with a compact/normal header * * @param compact * @param savedInstanceState */ private fun buildHeader(compact: Boolean, savedInstanceState: Bundle?) { // Create the AccountHeader headerView = AccountHeaderView(this, compact = compact).apply { attachToSliderView(binding.slider) headerBackground = ImageHolder(R.drawable.header) addProfiles( profile, profile2, profile3, profile4, profile5, //don't ask but google uses 14dp for the add account icon in gmail but 20dp for the normal icons (like manage account) ProfileSettingDrawerItem().apply { nameText = "Add Account"; descriptionText = "Add new GitHub Account"; iconDrawable = IconicsDrawable(this@AdvancedActivity, GoogleMaterial.Icon.gmd_add).apply { actionBar(); paddingDp = 5 }; identifier = PROFILE_SETTING.toLong() }, ProfileSettingDrawerItem().apply { nameText = "Manage Account"; iconicsIcon = GoogleMaterial.Icon.gmd_settings } ) onAccountHeaderListener = { _, profile, _ -> //sample usage of the onProfileChanged listener //if the clicked item has the identifier 1 add a new profile ;) if (profile is IDrawerItem<*> && (profile as IDrawerItem<*>).identifier == PROFILE_SETTING.toLong()) { val newProfile = ProfileDrawerItem().apply { nameText = "Batman"; descriptionText = "batman@gmail.com"; iconRes = R.drawable.profile5; isNameShown = true } val profiles = headerView.profiles if (profiles != null) { //we know that there are 2 setting elements. set the new profile above them ;) headerView.addProfile(newProfile, profiles.size - 2) } else { headerView.addProfiles(newProfile) } } //false if you have not consumed the event and it should close the drawer false } withSavedInstance(savedInstanceState) } } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) actionBarDrawerToggle.onConfigurationChanged(newConfig) } override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) actionBarDrawerToggle.syncState() } override fun onCreateOptionsMenu(menu: Menu): Boolean { val inflater = menuInflater inflater.inflate(R.menu.main, menu) return true } override fun onOptionsItemSelected(item: MenuItem): Boolean { // Handle item selection when (item.itemId) { R.id.menu_1 -> { //update the profile2 and set a new image. profile2.iconDrawable = IconicsDrawable(this, GoogleMaterial.Icon.gmd_android).apply { backgroundColorRes = R.color.colorAccent; paddingDp = 4; sizeDp = 48 } headerView.updateProfile(profile2) return true } R.id.menu_4 -> { //we want to replace our current header with a compact header //build the new compact header buildHeader(true, null) return true } R.id.menu_5 -> { //we want to replace our current header with a normal header //build the new compact header buildHeader(false, null) binding.slider.invalidate() return true } else -> { return actionBarDrawerToggle.onOptionsItemSelected(item) } } } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values which need to be saved from the drawer to the bundle outState = binding.slider.saveInstanceState(outState) //add the values which need to be saved from the accountHeader to the bundle outState = headerView.saveInstanceState(outState) super.onSaveInstanceState(outState) } override fun onBackPressed() { //handle the back press :D close the drawer first and if the drawer is closed close the activity if (binding.root.isDrawerOpen(binding.slider)) { binding.root.closeDrawer(binding.slider) } else { super.onBackPressed() } } companion object { private const val PROFILE_SETTING = 1 } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/CollapsingToolbarActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.graphics.Color import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import coil.load import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesomeBrand import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.iconics.utils.actionBar import com.mikepenz.iconics.utils.colorInt import com.mikepenz.materialdrawer.app.databinding.ActivitySampleCollapsingToolbarBinding import com.mikepenz.materialdrawer.app.utils.convertDpToPixel import com.mikepenz.materialdrawer.holder.ImageHolder import com.mikepenz.materialdrawer.iconics.iconicsIcon import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.SecondaryDrawerItem import com.mikepenz.materialdrawer.model.SectionDrawerItem import com.mikepenz.materialdrawer.model.interfaces.nameRes import com.mikepenz.materialdrawer.util.removeAllItems import com.mikepenz.materialdrawer.widget.AccountHeaderView import com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView class CollapsingToolbarActivity : AppCompatActivity() { private lateinit var binding: ActivitySampleCollapsingToolbarBinding private lateinit var headerView: AccountHeaderView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivitySampleCollapsingToolbarBinding.inflate(layoutInflater).also { setContentView(it.root) } setSupportActionBar(binding.toolbar) binding.collapsingToolbar.title = getString(R.string.drawer_item_collapsing_toolbar_drawer) binding.materialDrawerSwipeRefresh.setProgressViewOffset(true, 0, convertDpToPixel(48f, this).toInt()) binding.materialDrawerSwipeRefresh.setOnRefreshListener { binding.materialDrawerSwipeRefresh.postDelayed({ binding.slider.setDrawerItems() binding.slider.setSelection(5, false) binding.materialDrawerSwipeRefresh.isRefreshing = false }, 3000) } // Create the AccountHeader headerView = AccountHeaderView(this).apply { attachToSliderView(binding.slider) headerBackground = ImageHolder(R.drawable.header) withSavedInstance(savedInstanceState) } binding.slider.apply { setDrawerItems() setSelection(1, false) setSavedInstance(savedInstanceState) } fillFab() loadBackdrop() } private fun MaterialDrawerSliderView.setDrawerItems() { removeAllItems() itemAdapter.add( PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_home; iconicsIcon = FontAwesome.Icon.faw_home; identifier = 1 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_free_play; iconicsIcon = FontAwesome.Icon.faw_gamepad }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_custom; iconicsIcon = FontAwesome.Icon.faw_eye; identifier = 5 }, SectionDrawerItem().apply { nameRes = R.string.drawer_item_section_header }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_settings; iconicsIcon = FontAwesome.Icon.faw_cog }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_help; iconicsIcon = FontAwesome.Icon.faw_question; isEnabled = false }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_open_source; iconicsIcon = FontAwesomeBrand.Icon.fab_github }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_contact; iconicsIcon = FontAwesome.Icon.faw_bullhorn } ) } private fun loadBackdrop() { binding.backdrop.load("https://unsplash.it/600/300/?random") } private fun fillFab() { binding.floatingActionButton.setImageDrawable(IconicsDrawable(this, GoogleMaterial.Icon.gmd_favorite).apply { actionBar(); colorInt = Color.WHITE }) } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values which need to be saved from the drawer to the bundle outState = binding.slider.saveInstanceState(outState) //add the values which need to be saved from the accountHeader to the bundle outState = headerView.saveInstanceState(outState) super.onSaveInstanceState(outState) } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/CompactHeaderDrawerActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.content.Context import android.content.res.Configuration import android.graphics.Color import android.os.Build import android.os.Bundle import android.util.TypedValue import android.view.Menu import android.view.MenuItem import androidx.annotation.AttrRes import androidx.annotation.ColorInt import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.view.ActionMode import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesomeBrand import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.iconics.utils.actionBar import com.mikepenz.iconics.utils.paddingDp import com.mikepenz.materialdrawer.app.databinding.ActivitySampleBinding import com.mikepenz.materialdrawer.holder.BadgeStyle import com.mikepenz.materialdrawer.holder.ColorHolder import com.mikepenz.materialdrawer.iconics.iconicsIcon import com.mikepenz.materialdrawer.iconics.withIcon import com.mikepenz.materialdrawer.model.* import com.mikepenz.materialdrawer.model.interfaces.* import com.mikepenz.materialdrawer.widget.AccountHeaderView class CompactHeaderDrawerActivity : AppCompatActivity() { private lateinit var binding: ActivitySampleBinding //save our header or result private lateinit var headerView: AccountHeaderView private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivitySampleBinding.inflate(layoutInflater).also { setContentView(it.root) } // Handle Toolbar setSupportActionBar(binding.toolbar) supportActionBar?.setTitle(R.string.drawer_item_compact_header) supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setHomeButtonEnabled(true) actionBarDrawerToggle = ActionBarDrawerToggle(this, binding.root, binding.toolbar, com.mikepenz.materialdrawer.R.string.material_drawer_open, com.mikepenz.materialdrawer.R.string.material_drawer_close) // Create a few sample profile val profile = ProfileDrawerItem().apply { nameText = "Mike Penz"; descriptionText = "mikepenz@gmail.com"; iconRes = R.drawable.profile; badgeText = "123" badgeStyle = BadgeStyle().apply { textColor = ColorHolder.fromColor(Color.WHITE) color = ColorHolder.fromColorRes(R.color.colorAccent) } } val profile2 = ProfileDrawerItem().apply { nameText = "Max Muster"; descriptionText = "max.mustermann@gmail.com"; iconRes = R.drawable.profile2 } val profile3 = ProfileDrawerItem().apply { nameText = "Felix House"; descriptionText = "felix.house@gmail.com"; iconRes = R.drawable.profile3 } val profile4 = ProfileDrawerItem().apply { nameText = "Mr. X"; descriptionText = "mister.x.super@gmail.com"; iconRes = R.drawable.profile4 } val profile5 = ProfileDrawerItem().apply { nameText = "Batman"; descriptionText = "batman@gmail.com"; iconRes = R.drawable.profile5 } // Create the AccountHeader headerView = AccountHeaderView(this).apply { attachToSliderView(binding.slider) addProfiles( profile, profile2, profile3, profile4, profile5, //don't ask but google uses 14dp for the add account icon in gmail but 20dp for the normal icons (like manage account) ProfileSettingDrawerItem().withName("Add Account").withDescription("Add new GitHub Account").withIcon(IconicsDrawable(context, GoogleMaterial.Icon.gmd_add).apply { actionBar(); paddingDp = 5 }).withIconTinted(true).withIdentifier(PROFILE_SETTING.toLong()), ProfileSettingDrawerItem().withName("Manage Account").withIcon(GoogleMaterial.Icon.gmd_settings).withIdentifier(100001) ) withSavedInstance(savedInstanceState) } binding.slider.apply { itemAdapter.add( PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_home; iconicsIcon = FontAwesome.Icon.faw_home; identifier = 1 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_free_play; iconicsIcon = FontAwesome.Icon.faw_gamepad }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_custom; iconicsIcon = FontAwesome.Icon.faw_eye; identifier = 5 }, SectionDrawerItem().apply { nameRes = R.string.drawer_item_section_header }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_settings; iconicsIcon = FontAwesome.Icon.faw_cog }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_help; iconicsIcon = FontAwesome.Icon.faw_question; isEnabled = false }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_open_source; iconicsIcon = FontAwesomeBrand.Icon.fab_github }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_contact; iconicsIcon = FontAwesome.Icon.faw_bullhorn } ) onDrawerItemClickListener = { _, drawerItem, _ -> if (drawerItem.identifier == 1L) { startSupportActionMode(ActionBarCallBack()) } if (drawerItem is Nameable) { binding.toolbar.title = drawerItem.name?.getText(this@CompactHeaderDrawerActivity) } false } setSavedInstance(savedInstanceState) } // set the selection to the item with the identifier 5 if (savedInstanceState == null) { binding.slider.setSelection(5, false) } } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) actionBarDrawerToggle.onConfigurationChanged(newConfig) } override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) actionBarDrawerToggle.syncState() } override fun onOptionsItemSelected(item: MenuItem): Boolean { if (actionBarDrawerToggle.onOptionsItemSelected(item)) { return true } return super.onOptionsItemSelected(item) } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values which need to be saved from the drawer to the bundle outState = binding.slider.saveInstanceState(outState) //add the values which need to be saved from the accountHeader to the bundle outState = headerView.saveInstanceState(outState) super.onSaveInstanceState(outState) } override fun onBackPressed() { //handle the back press :D close the drawer first and if the drawer is closed close the activity if (binding.root.isDrawerOpen(binding.slider)) { binding.root.closeDrawer(binding.slider) } else { super.onBackPressed() } } internal inner class ActionBarCallBack : ActionMode.Callback { override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { return false } override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { window.statusBarColor = getThemeColor(android.R.attr.colorPrimaryDark, ContextCompat.getColor(this@CompactHeaderDrawerActivity, R.color.colorPrimaryDark)) } mode.menuInflater.inflate(R.menu.cab, menu) return true } override fun onDestroyActionMode(mode: ActionMode) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { window.statusBarColor = Color.TRANSPARENT } } override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { return false } private fun Context.getThemeColor(@AttrRes attr: Int, @ColorInt def: Int = 0): Int { val tv = TypedValue() return if (theme.resolveAttribute(attr, tv, true)) { if (tv.resourceId != 0) ResourcesCompat.getColor(resources, tv.resourceId, theme) else tv.data } else def } } companion object { private const val PROFILE_SETTING = 1 } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/CrossfadeDrawerLayoutActvitiy.kt ================================================ package com.mikepenz.materialdrawer.app import android.content.res.Configuration import android.os.Bundle import android.view.MenuItem import android.widget.Toast import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import androidx.core.view.GravityCompat import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesomeBrand import com.mikepenz.materialdrawer.app.databinding.ActivitySampleCrossfaderBinding import com.mikepenz.materialdrawer.iconics.iconicsIcon import com.mikepenz.materialdrawer.interfaces.ICrossfader import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.ProfileDrawerItem import com.mikepenz.materialdrawer.model.SecondaryDrawerItem import com.mikepenz.materialdrawer.model.SectionDrawerItem import com.mikepenz.materialdrawer.model.interfaces.* import com.mikepenz.materialdrawer.util.getOptimalDrawerWidth import com.mikepenz.materialdrawer.widget.AccountHeaderView class CrossfadeDrawerLayoutActvitiy : AppCompatActivity() { private lateinit var binding: ActivitySampleCrossfaderBinding private lateinit var headerView: AccountHeaderView private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivitySampleCrossfaderBinding.inflate(layoutInflater).also { setContentView(it.root) } // Handle Toolbar setSupportActionBar(binding.toolbar) //set the back arrow in the toolbars supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setHomeButtonEnabled(true) supportActionBar?.setTitle(R.string.drawer_item_crossfade_drawer_layout_drawer) actionBarDrawerToggle = ActionBarDrawerToggle(this, binding.root, binding.toolbar, com.mikepenz.materialdrawer.R.string.material_drawer_open, com.mikepenz.materialdrawer.R.string.material_drawer_close) // Create a few sample profile val profile = ProfileDrawerItem().apply { nameText = "Mike Penz"; descriptionText = "mikepenz@gmail.com"; iconRes = R.drawable.profile } val profile2 = ProfileDrawerItem().apply { nameText = "Max Muster"; descriptionText = "max.mustermann@gmail.com"; iconRes = R.drawable.profile2 } val profile3 = ProfileDrawerItem().apply { nameText = "Felix House"; descriptionText = "felix.house@gmail.com"; iconRes = R.drawable.profile3 } val profile4 = ProfileDrawerItem().apply { nameText = "Mr. X"; descriptionText = "mister.x.super@gmail.com"; iconRes = R.drawable.profile4 } val profile5 = ProfileDrawerItem().apply { nameText = "Batman"; descriptionText = "batman@gmail.com"; iconRes = R.drawable.profile5 } // Create the AccountHeader headerView = AccountHeaderView(this).apply { attachToSliderView(binding.crossFadeLargeView) addProfiles( profile, profile2, profile3, profile4, profile5 ) withSavedInstance(savedInstanceState) } binding.crossFadeLargeView.apply { itemAdapter.add( PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_home; iconicsIcon = FontAwesome.Icon.faw_home; identifier = 1 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_free_play; iconicsIcon = FontAwesome.Icon.faw_gamepad }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_custom; iconicsIcon = FontAwesome.Icon.faw_eye; identifier = 5 }, SectionDrawerItem().apply { nameRes = R.string.drawer_item_section_header }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_settings; iconicsIcon = FontAwesome.Icon.faw_cog }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_help; iconicsIcon = FontAwesome.Icon.faw_question; isEnabled = false }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_open_source; iconicsIcon = FontAwesomeBrand.Icon.fab_github }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_contact; iconicsIcon = FontAwesome.Icon.faw_bullhorn } ) onDrawerItemClickListener = { v, drawerItem, position -> if (drawerItem is Nameable) { Toast.makeText(this@CrossfadeDrawerLayoutActvitiy, drawerItem.name?.getText(this@CrossfadeDrawerLayoutActvitiy), Toast.LENGTH_SHORT).show() } false } setSavedInstance(savedInstanceState) } binding.crossFadeSmallView.drawer = binding.crossFadeLargeView //define maxDrawerWidth binding.root.maxWidthPx = getOptimalDrawerWidth(this) binding.crossFadeSmallView.background = binding.crossFadeLargeView.background //define the crossfader to be used with the miniDrawer. This is required to be able to automatically toggle open / close binding.crossFadeSmallView.crossFader = object : ICrossfader { override val isCrossfaded: Boolean get() = binding.root.isCrossfaded override fun crossfade() { val isFaded = isCrossfaded binding.root.crossfade(400) //only close the drawer if we were already faded and want to close it now if (isFaded) { binding.root.closeDrawer(GravityCompat.START) } } } // set the selection to the item with the identifier 5 if (savedInstanceState == null) { binding.crossFadeLargeView.setSelection(5, false) } } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) actionBarDrawerToggle.onConfigurationChanged(newConfig) } override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) actionBarDrawerToggle.syncState() } override fun onOptionsItemSelected(item: MenuItem): Boolean { if (actionBarDrawerToggle.onOptionsItemSelected(item)) { return true } return super.onOptionsItemSelected(item) } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values which need to be saved from the drawer to the bundle outState = binding.crossFadeLargeView.saveInstanceState(outState) //add the values which need to be saved from the accountHeader to the bundle outState = headerView.saveInstanceState(outState) super.onSaveInstanceState(outState) } override fun onBackPressed() { //handle the back press :D close the drawer first and if the drawer is closed close the activity if (binding.root.isDrawerOpen(binding.crossFadeSlider)) { binding.root.closeDrawer(binding.crossFadeSlider) } else { super.onBackPressed() } } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/CustomApplication.kt ================================================ package com.mikepenz.materialdrawer.app import android.content.Context import android.graphics.drawable.Drawable import android.net.Uri import android.widget.ImageView import androidx.multidex.MultiDexApplication import coil.dispose import coil.load import com.google.android.material.color.DynamicColors import com.mikepenz.iconics.Iconics import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.utils.backgroundColorRes import com.mikepenz.iconics.utils.sizeDp import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader import com.mikepenz.materialdrawer.util.DrawerImageLoader import com.mikepenz.materialdrawer.util.getPlaceHolder /** * Created by mikepenz on 27.03.15. */ class CustomApplication : MultiDexApplication() { override fun onCreate() { super.onCreate() Iconics.init(this) DynamicColors.applyToActivitiesIfAvailable(this) //initialize and create the image loader logic /* DrawerImageLoader.init(object : AbstractDrawerImageLoader() { override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable) { Picasso.get().load(uri).placeholder(placeholder).into(imageView) } override fun cancel(imageView: ImageView) { Picasso.get().cancelRequest(imageView) } }) */ //initialize and create the image loader logic DrawerImageLoader.init(object : AbstractDrawerImageLoader() { override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) { imageView.load(uri) { allowHardware(false) placeholder(placeholder) } } override fun cancel(imageView: ImageView) { imageView.dispose() } override fun placeholder(ctx: Context, tag: String?): Drawable { //define different placeholders for different imageView targets //default tags are accessible via the DrawerImageLoader.Tags //custom ones can be checked via string. see the CustomUrlBasePrimaryDrawerItem LINE 111 return when (tag) { DrawerImageLoader.Tags.PROFILE.name -> getPlaceHolder(ctx) DrawerImageLoader.Tags.ACCOUNT_HEADER.name -> IconicsDrawable(ctx, " ").apply { backgroundColorRes = R.color.colorPrimary; sizeDp = 56 } "customUrlItem" -> IconicsDrawable(ctx, " ").apply { backgroundColorRes = R.color.colorAccent; sizeDp = 56 } //we use the default one for //DrawerImageLoader.Tags.PROFILE_DRAWER_ITEM.name() else -> super.placeholder(ctx, tag) } } }) } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/DrawerActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.content.Intent import android.content.res.Configuration import android.graphics.Color import android.os.Bundle import android.view.MenuItem import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import com.mikepenz.aboutlibraries.LibsBuilder import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesomeBrand import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.iconics.utils.actionBar import com.mikepenz.iconics.utils.paddingDp import com.mikepenz.materialdrawer.app.databinding.ActivitySampleBinding import com.mikepenz.materialdrawer.holder.BadgeStyle import com.mikepenz.materialdrawer.holder.ColorHolder import com.mikepenz.materialdrawer.holder.StringHolder import com.mikepenz.materialdrawer.iconics.iconicsIcon import com.mikepenz.materialdrawer.model.* import com.mikepenz.materialdrawer.model.interfaces.* import com.mikepenz.materialdrawer.util.addItems import com.mikepenz.materialdrawer.util.updateBadge import com.mikepenz.materialdrawer.widget.AccountHeaderView class DrawerActivity : AppCompatActivity() { private lateinit var binding: ActivitySampleBinding private lateinit var headerView: AccountHeaderView private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivitySampleBinding.inflate(layoutInflater).also { setContentView(it.root) } // Handle Toolbar setSupportActionBar(binding.toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(false) supportActionBar?.setHomeButtonEnabled(true) actionBarDrawerToggle = ActionBarDrawerToggle( this, binding.root, binding.toolbar, com.mikepenz.materialdrawer.R.string.material_drawer_open, com.mikepenz.materialdrawer.R.string.material_drawer_close ) binding.root.addDrawerListener(actionBarDrawerToggle) // Create a few sample profile // NOTE you have to define the loader logic too. See the CustomApplication for more details val profile = ProfileDrawerItem().apply { nameText = "Mike Penz"; descriptionText = "mikepenz@gmail.com"; iconUrl = "https://avatars3.githubusercontent.com/u/1476232?v=3&s=460"; identifier = 100 } val profile2 = ProfileDrawerItem().apply { nameText = "Demo User"; descriptionText = "demo@github.com"; iconUrl = "https://avatars2.githubusercontent.com/u/3597376?v=3&s=460"; identifier = 101 } val profile3 = ProfileDrawerItem().apply { nameText = "Max Muster"; descriptionText = "max.mustermann@gmail.com"; iconRes = R.drawable.profile2; identifier = 102 } val profile4 = ProfileDrawerItem().apply { nameText = "Felix House"; descriptionText = "felix.house@gmail.com"; iconRes = R.drawable.profile3; identifier = 103 } val profile5 = ProfileDrawerItem().apply { nameText = "Mr. X"; descriptionText = "mister.x.super@gmail.com"; iconRes = R.drawable.profile4; identifier = 104 } val profile6 = ProfileDrawerItem().apply { nameText = "Batman"; descriptionText = "batman@gmail.com"; iconRes = R.drawable.profile5; identifier = 105; badgeText = "123" badgeStyle = BadgeStyle().apply { textColor = ColorHolder.fromColor(Color.BLACK) color = ColorHolder.fromColor(Color.WHITE) } } // Create the AccountHeader headerView = AccountHeaderView(this).apply { attachToSliderView(binding.slider) addProfiles( profile, profile2, profile3, profile4, profile5, profile6, //don't ask but google uses 14dp for the add account icon in gmail but 20dp for the normal icons (like manage account) ProfileSettingDrawerItem().apply { nameText = "Add Account"; descriptionText = "Add new GitHub Account"; iconDrawable = IconicsDrawable(context, GoogleMaterial.Icon.gmd_add).apply { actionBar(); paddingDp = 5 }.mutate(); isIconTinted = true; identifier = PROFILE_SETTING.toLong() }, ProfileSettingDrawerItem().apply { nameText = "Manage Account"; iconicsIcon = GoogleMaterial.Icon.gmd_settings; identifier = 100001 } ) onAccountHeaderListener = { view, profile, current -> //sample usage of the onProfileChanged listener //if the clicked item has the identifier 1 add a new profile ;) if (profile is IDrawerItem<*> && profile.identifier == PROFILE_SETTING.toLong()) { val count = 100 + (profiles?.size ?: 0) + 1 val newProfile = ProfileDrawerItem().withNameShown(true).withName("Batman$count").withEmail("batman$count@gmail.com").withIcon(R.drawable.profile5) .withIdentifier(count.toLong()) profiles?.let { //we know that there are 2 setting elements. set the new profile above them ;) addProfile(newProfile, it.size - 2) } ?: addProfiles(newProfile) } //false if you have not consumed the event and it should close the drawer false } withSavedInstance(savedInstanceState) } binding.slider.apply { addItems( PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_compact_header; descriptionRes = R.string.drawer_item_compact_header_desc; iconicsIcon = GoogleMaterial.Icon.gmd_brightness_5; isSelectable = false; identifier = 1 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_action_bar_drawer; descriptionRes = R.string.drawer_item_action_bar_drawer_desc; iconicsIcon = FontAwesome.Icon.faw_home; isSelectable = false; identifier = 2 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_multi_drawer; descriptionRes = R.string.drawer_item_multi_drawer_desc; iconicsIcon = FontAwesome.Icon.faw_gamepad; isSelectable = false; identifier = 3 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_advanced_drawer; descriptionRes = R.string.drawer_item_advanced_drawer_desc; iconicsIcon = GoogleMaterial.Icon.gmd_adb; isSelectable = false; identifier = 5 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_embedded_drawer; descriptionRes = R.string.drawer_item_embedded_drawer_desc; iconicsIcon = GoogleMaterial.Icon.gmd_battery_full; isSelectable = false; identifier = 7 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_fullscreen_drawer; descriptionRes = R.string.drawer_item_fullscreen_drawer_desc; iconicsIcon = GoogleMaterial.Icon.gmd_label; isSelectable = false; identifier = 8 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_menu_drawer; descriptionRes = R.string.drawer_item_menu_drawer_desc; iconicsIcon = GoogleMaterial.Icon.gmd_filter_list; isSelectable = false; identifier = 10 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_mini_drawer; descriptionRes = R.string.drawer_item_mini_drawer_desc; iconicsIcon = GoogleMaterial.Icon.gmd_battery_charging_full; isSelectable = false; identifier = 11 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_fragment_drawer; descriptionRes = R.string.drawer_item_fragment_drawer_desc; iconicsIcon = GoogleMaterial.Icon.gmd_disc_full; isSelectable = false; identifier = 12 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_collapsing_toolbar_drawer; descriptionRes = R.string.drawer_item_collapsing_toolbar_drawer_desc; iconicsIcon = GoogleMaterial.Icon.gmd_camera_rear; isSelectable = false; identifier = 13 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_persistent_compact_header; descriptionRes = R.string.drawer_item_persistent_compact_header_desc; iconicsIcon = GoogleMaterial.Icon.gmd_brightness_5; isSelectable = false; identifier = 14 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_crossfade_drawer_layout_drawer; descriptionRes = R.string.drawer_item_crossfade_drawer_layout_drawer_desc; iconicsIcon = GoogleMaterial.Icon.gmd_format_bold; isSelectable = false; identifier = 15 }, PrimaryDrawerItem().apply { nameRes = R.string.drawer_item_navigation_drawer; descriptionRes = R.string.drawer_item_navigation_drawer_desc; iconicsIcon = GoogleMaterial.Icon.gmd_navigation; isSelectable = false; identifier = 1305 }, ExpandableBadgeDrawerItem().apply { nameText = "Collapsable Badge"; iconicsIcon = GoogleMaterial.Icon.gmd_format_bold; identifier = 18; isSelectable = false; badge = StringHolder("100") badgeStyle = BadgeStyle().apply { textColor = ColorHolder.fromColor(Color.WHITE); color = ColorHolder.fromColorRes(R.color.colorAccent) } subItems = mutableListOf( SecondaryDrawerItem().apply { nameText = "CollapsableItem"; level = 2; iconicsIcon = GoogleMaterial.Icon.gmd_format_bold; identifier = 2000 }, SecondaryDrawerItem().apply { nameText = "CollapsableItem 2"; level = 2; iconicsIcon = GoogleMaterial.Icon.gmd_format_bold; identifier = 2001 } ) }, ExpandableDrawerItem().apply { nameText = "Collapsable"; iconicsIcon = GoogleMaterial.Icon.gmd_filter_list; identifier = 19; isSelectable = false subItems = mutableListOf( SecondaryDrawerItem().apply { nameText = "CollapsableItem"; level = 2; iconicsIcon = GoogleMaterial.Icon.gmd_filter_list; identifier = 2002 }, SecondaryDrawerItem().apply { nameText = "CollapsableItem 2"; level = 2; iconicsIcon = GoogleMaterial.Icon.gmd_filter_list; identifier = 2003 } ) }, SectionDrawerItem().apply { nameRes = R.string.drawer_item_section_header }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_open_source; iconicsIcon = FontAwesomeBrand.Icon.fab_github; identifier = 20; isSelectable = false }, SecondaryDrawerItem().apply { nameRes = R.string.drawer_item_contact; iconicsIcon = GoogleMaterial.Icon.gmd_format_color_fill; identifier = 21; isSelectable = false } /*, DividerDrawerItem () SwitchDrawerItem ().withName("Switch").withIcon(Octicons.Icon.oct_tools).withChecked(true).withOnCheckedChangeListener(onCheckedChangeListener) SwitchDrawerItem ().withName("Switch2").withIcon(Octicons.Icon.oct_tools).withChecked(true).withOnCheckedChangeListener(onCheckedChangeListener).withSelectable(false) ToggleDrawerItem ().withName("Toggle").withIcon(Octicons.Icon.oct_tools).withChecked(true).withOnCheckedChangeListener(onCheckedChangeListener) DividerDrawerItem () SecondarySwitchDrawerItem ().withName("Secondary switch").withIcon(Octicons.Icon.oct_tools).withChecked(true).withOnCheckedChangeListener(onCheckedChangeListener) SecondarySwitchDrawerItem ().withName("Secondary Switch2").withIcon(Octicons.Icon.oct_tools).withChecked(true).withOnCheckedChangeListener(onCheckedChangeListener).withSelectable(false) SecondaryToggleDrawerItem ().withName("Secondary toggle").withIcon(Octicons.Icon.oct_tools).withChecked(true).withOnCheckedChangeListener(onCheckedChangeListener) */ ) onDrawerItemClickListener = { _, drawerItem, _ -> //check if the drawerItem is set. //there are different reasons for the drawerItem to be null //--> click on the header //--> click on the footer //those items don't contain a drawerItem var intent: Intent? = null when { drawerItem.identifier == 1L -> intent = Intent(this@DrawerActivity, CompactHeaderDrawerActivity::class.java) drawerItem.identifier == 2L -> intent = Intent(this@DrawerActivity, ActionBarActivity::class.java) drawerItem.identifier == 3L -> intent = Intent(this@DrawerActivity, MultiDrawerActivity::class.java) drawerItem.identifier == 5L -> intent = Intent(this@DrawerActivity, AdvancedActivity::class.java) drawerItem.identifier == 7L -> intent = Intent(this@DrawerActivity, EmbeddedDrawerActivity::class.java) drawerItem.identifier == 8L -> intent = Intent(this@DrawerActivity, FullscreenDrawerActivity::class.java) drawerItem.identifier == 10L -> intent = Intent(this@DrawerActivity, MenuDrawerActivity::class.java) drawerItem.identifier == 11L -> intent = Intent(this@DrawerActivity, MiniDrawerActivity::class.java) drawerItem.identifier == 12L -> intent = Intent(this@DrawerActivity, FragmentActivity::class.java) drawerItem.identifier == 13L -> intent = Intent(this@DrawerActivity, CollapsingToolbarActivity::class.java) drawerItem.identifier == 14L -> intent = Intent(this@DrawerActivity, PersistentDrawerActivity::class.java) drawerItem.identifier == 15L -> intent = Intent(this@DrawerActivity, CrossfadeDrawerLayoutActvitiy::class.java) drawerItem.identifier == 1305L -> intent = Intent(this@DrawerActivity, NavControllerActivity::class.java) drawerItem.identifier == 20L -> intent = LibsBuilder().intent(this@DrawerActivity) } if (intent != null) { this@DrawerActivity.startActivity(intent) } false } setSavedInstance(savedInstanceState) } //slider.withStickyHeader(R.layout.header) //slider.addStickyDrawerItems( // SecondaryDrawerItem().withName(R.string.drawer_item_settings).withIcon(FontAwesome.Icon.faw_cog).withIdentifier(10), // SecondaryDrawerItem().withName(R.string.drawer_item_open_source).withIcon(FontAwesomeBrand.Icon.fab_github) //) //only set the active selection or active profile if we do not recreate the activity if (savedInstanceState == null) { // set the selection to the item with the identifier 11 binding.slider.setSelection(21, false) //set the active profile headerView.activeProfile = profile3 } binding.slider.updateBadge(4, StringHolder(10.toString() + "")) } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) actionBarDrawerToggle.onConfigurationChanged(newConfig) } override fun onResume() { super.onResume() actionBarDrawerToggle.syncState() } override fun onOptionsItemSelected(item: MenuItem): Boolean { if (actionBarDrawerToggle.onOptionsItemSelected(item)) { return true } return super.onOptionsItemSelected(item) } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values which need to be saved from the drawer to the bundle outState = binding.slider.saveInstanceState(outState) //add the values which need to be saved from the accountHeader to the bundle outState = headerView.saveInstanceState(outState) super.onSaveInstanceState(outState) } override fun onBackPressed() { //handle the back press :D close the drawer first and if the drawer is closed close the activity if (binding.root.isDrawerOpen(binding.slider)) { binding.root.closeDrawer(binding.slider) } else { super.onBackPressed() } } companion object { private const val PROFILE_SETTING = 100000 } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/EmbeddedDrawerActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.graphics.Color import android.net.Uri import android.os.Bundle import android.util.Log import android.view.MenuItem import android.view.ViewGroup import android.widget.CompoundButton import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesomeBrand import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.iconics.utils.actionBar import com.mikepenz.iconics.utils.paddingDp import com.mikepenz.materialdrawer.app.databinding.ActivityEmbeddedBinding import com.mikepenz.materialdrawer.holder.BadgeStyle import com.mikepenz.materialdrawer.iconics.withIcon import com.mikepenz.materialdrawer.interfaces.OnCheckedChangeListener import com.mikepenz.materialdrawer.model.* import com.mikepenz.materialdrawer.model.interfaces.* import com.mikepenz.materialdrawer.widget.AccountHeaderView class EmbeddedDrawerActivity : AppCompatActivity() { private lateinit var binding: ActivityEmbeddedBinding private lateinit var headerView: AccountHeaderView private val onCheckedChangeListener = object : OnCheckedChangeListener { override fun onCheckedChanged(drawerItem: IDrawerItem<*>, buttonView: CompoundButton, isChecked: Boolean) { if (drawerItem is Nameable) { Log.i("material-drawer", "DrawerItem: " + (drawerItem as Nameable).name + " - toggleChecked: " + isChecked) } else { Log.i("material-drawer", "toggleChecked: $isChecked") } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityEmbeddedBinding.inflate(layoutInflater).also { setContentView(it.root) } // Handle Toolbar setSupportActionBar(binding.toolbar) //set the back arrow in the toolbar supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setTitle(R.string.drawer_item_embedded_drawer) // Create a few sample profile // NOTE you have to define the loader logic too. See the CustomApplication for more details val profile = ProfileDrawerItem().withName("Mike Penz").withEmail("mikepenz@gmail.com").withIcon("https://avatars3.githubusercontent.com/u/1476232?v=3&s=460") val profile2 = ProfileDrawerItem().withName("Bernat Borras").withEmail("alorma@github.com").withIcon(Uri.parse("https://avatars3.githubusercontent.com/u/887462?v=3&s=460")) val profile3 = ProfileDrawerItem().withName("Max Muster").withEmail("max.mustermann@gmail.com").withIcon(resources.getDrawable(R.drawable.profile2)) val profile4 = ProfileDrawerItem().withName("Felix House").withEmail("felix.house@gmail.com").withIcon(resources.getDrawable(R.drawable.profile3)) val profile5 = ProfileDrawerItem().withName("Mr. X").withEmail("mister.x.super@gmail.com").withIcon(resources.getDrawable(R.drawable.profile4)).withIdentifier(4) val profile6 = ProfileDrawerItem().withName("Batman").withEmail("batman@gmail.com").withIcon(resources.getDrawable(R.drawable.profile5)) // Create the AccountHeader headerView = AccountHeaderView(this).apply { attachToSliderView(binding.slider) addProfiles( profile, profile2, profile3, profile4, profile5, profile6, //don't ask but google uses 14dp for the add account icon in gmail but 20dp for the normal icons (like manage account) ProfileSettingDrawerItem().withName("Add Account").withDescription("Add new GitHub Account").withIcon(IconicsDrawable(context, GoogleMaterial.Icon.gmd_add).apply { actionBar(); paddingDp = 5 }).withIconTinted(true).withIdentifier(PROFILE_SETTING.toLong()), ProfileSettingDrawerItem().withName("Manage Account").withIcon(GoogleMaterial.Icon.gmd_settings).withIdentifier(100001) ) onAccountHeaderListener = { view, profile, current -> //sample usage of the onProfileChanged listener //if the clicked item has the identifier 1 add a new profile ;) if (profile is IDrawerItem<*> && (profile as IDrawerItem<*>).identifier == PROFILE_SETTING.toLong()) { val newProfile = ProfileDrawerItem().withNameShown(true).withName("Batman").withEmail("batman@gmail.com").withIcon(resources.getDrawable(R.drawable.profile5)) headerView.profiles?.let { //we know that there are 2 setting elements. set the new profile above them ;) headerView.addProfile(newProfile, it.size - 2) } ?: headerView.addProfiles(newProfile) } //false if you have not consumed the event and it should close the drawer false } withSavedInstance(savedInstanceState) } binding.slider.apply { customWidth = ViewGroup.LayoutParams.MATCH_PARENT itemAdapter.add( PrimaryDrawerItem().withName(R.string.drawer_item_compact_header).withIcon(GoogleMaterial.Icon.gmd_brightness_5).withIdentifier(1), PrimaryDrawerItem().withName(R.string.drawer_item_action_bar_drawer).withIcon(FontAwesome.Icon.faw_home).withBadge("22") .withBadgeStyle(BadgeStyle(Color.RED, Color.RED)).withIdentifier(2), PrimaryDrawerItem().withName(R.string.drawer_item_multi_drawer).withIcon(FontAwesome.Icon.faw_gamepad).withIdentifier(3), PrimaryDrawerItem().withName(R.string.drawer_item_non_translucent_status_drawer).withIcon(FontAwesome.Icon.faw_eye).withIdentifier(4), PrimaryDrawerItem().withDescription("A more complex sample").withName(R.string.drawer_item_advanced_drawer) .withIcon(GoogleMaterial.Icon.gmd_adb).withIdentifier(5), SectionDrawerItem().withName(R.string.drawer_item_section_header), SecondaryDrawerItem().withName(R.string.drawer_item_open_source).withIcon(FontAwesomeBrand.Icon.fab_github), SecondaryDrawerItem().withName(R.string.drawer_item_contact).withIcon(GoogleMaterial.Icon.gmd_format_color_fill).withTag("Bullhorn"), DividerDrawerItem(), SwitchDrawerItem().withName("Switch").withIcon(GoogleMaterial.Icon.gmd_pan_tool).withChecked(true) .withOnCheckedChangeListener(onCheckedChangeListener), ToggleDrawerItem().withName("Toggle").withIcon(GoogleMaterial.Icon.gmd_pan_tool).withChecked(true) .withOnCheckedChangeListener(onCheckedChangeListener) ) onDrawerItemClickListener = { v, drawerItem, position -> if (drawerItem is Nameable) { Toast.makeText(this@EmbeddedDrawerActivity, drawerItem.name?.getText(this@EmbeddedDrawerActivity), Toast.LENGTH_SHORT).show() } false } setSavedInstance(savedInstanceState) } } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values which need to be saved from the drawer to the bundle outState = binding.slider.saveInstanceState(outState) //add the values which need to be saved from the accountHeader to the bundle outState = headerView.saveInstanceState(outState) super.onSaveInstanceState(outState) } override fun onOptionsItemSelected(item: MenuItem): Boolean { //handle the click on the back arrow click return when (item.itemId) { android.R.id.home -> { onBackPressed() true } else -> super.onOptionsItemSelected(item) } } companion object { private const val PROFILE_SETTING = 1 } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/FragmentActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.os.Bundle import android.view.Menu import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity import com.mikepenz.materialdrawer.app.databinding.ActivitySampleFragmentBinding import com.mikepenz.materialdrawer.app.fragment.DrawerFragment import com.mikepenz.materialdrawer.app.fragment.SecondDrawerFragment class FragmentActivity : AppCompatActivity() { private lateinit var binding: ActivitySampleFragmentBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivitySampleFragmentBinding.inflate(layoutInflater).also { setContentView(it.root) } // Handle Toolbar setSupportActionBar(binding.toolbar) supportActionBar?.setTitle(R.string.drawer_item_fragment_drawer) //ignore the DemoFragment and it's layout it's just to showcase the handle with an keyboard if (savedInstanceState == null) { val f = DrawerFragment.newInstance("Demo") supportFragmentManager.beginTransaction().replace(R.id.fragment_container, f).commit() } } override fun onCreateOptionsMenu(menu: Menu): Boolean { val inflater = menuInflater inflater.inflate(R.menu.fragment_menu, menu) return true } override fun onOptionsItemSelected(item: MenuItem): Boolean { //handle the click on the back arrow click when (item.itemId) { R.id.menu_1 -> { val f = DrawerFragment.newInstance("Demo") supportFragmentManager.beginTransaction().replace(R.id.fragment_container, f).commit() return true } R.id.menu_2 -> { val f2 = SecondDrawerFragment.newInstance("Demo 2") supportFragmentManager.beginTransaction().replace(R.id.fragment_container, f2).commit() return true } android.R.id.home -> { onBackPressed() return true } else -> return super.onOptionsItemSelected(item) } } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/FullscreenDrawerActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.content.res.Configuration import android.graphics.Color import android.os.Bundle import android.view.MenuItem import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.updatePadding import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesomeBrand import com.mikepenz.materialdrawer.app.databinding.ActivitySampleFullscreenBinding import com.mikepenz.materialdrawer.iconics.withIcon import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.SecondaryDrawerItem import com.mikepenz.materialdrawer.model.SectionDrawerItem import com.mikepenz.materialdrawer.model.interfaces.withEnabled import com.mikepenz.materialdrawer.model.interfaces.withIdentifier import com.mikepenz.materialdrawer.model.interfaces.withName class FullscreenDrawerActivity : AppCompatActivity() { private lateinit var binding: ActivitySampleFullscreenBinding private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivitySampleFullscreenBinding.inflate(layoutInflater).also { setContentView(it.root) } // Handle Toolbar setSupportActionBar(binding.toolbar) binding.toolbar.setBackgroundColor(Color.BLACK) binding.toolbar.background.alpha = 90 supportActionBar?.setTitle(R.string.drawer_item_fullscreen_drawer) supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setHomeButtonEnabled(true) actionBarDrawerToggle = ActionBarDrawerToggle(this, binding.root, binding.toolbar, com.mikepenz.materialdrawer.R.string.material_drawer_open, com.mikepenz.materialdrawer.R.string.material_drawer_close) binding.slider.apply { itemAdapter.add( PrimaryDrawerItem().withName(R.string.drawer_item_home).withIcon(FontAwesome.Icon.faw_home).withIdentifier(1), PrimaryDrawerItem().withName(R.string.drawer_item_free_play).withIcon(FontAwesome.Icon.faw_gamepad), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), //add some more items to get a scrolling list SectionDrawerItem().withName(R.string.drawer_item_section_header), SecondaryDrawerItem().withName(R.string.drawer_item_settings).withIcon(FontAwesome.Icon.faw_cog), SecondaryDrawerItem().withName(R.string.drawer_item_help).withIcon(FontAwesome.Icon.faw_question).withEnabled(false), SecondaryDrawerItem().withName(R.string.drawer_item_open_source).withIcon(FontAwesomeBrand.Icon.fab_github), SecondaryDrawerItem().withName(R.string.drawer_item_contact).withIcon(FontAwesome.Icon.faw_bullhorn), SectionDrawerItem().withName(R.string.drawer_item_section_header), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye) ) setSavedInstance(savedInstanceState) } ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets -> binding.toolbar.updatePadding(top = insets.systemWindowInsetTop) insets } } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) actionBarDrawerToggle.onConfigurationChanged(newConfig) } override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) actionBarDrawerToggle.syncState() } override fun onOptionsItemSelected(item: MenuItem): Boolean { if (actionBarDrawerToggle.onOptionsItemSelected(item)) { return true } return super.onOptionsItemSelected(item) } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values which need to be saved from the drawer to the bundle outState = binding.slider.saveInstanceState(outState) super.onSaveInstanceState(outState) } override fun onBackPressed() { //handle the back press :D close the drawer first and if the drawer is closed close the activity if (binding.root.isDrawerOpen(binding.slider)) { binding.root.closeDrawer(binding.slider) } else { super.onBackPressed() } } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/MenuDrawerActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.content.res.Configuration import android.os.Bundle import android.view.MenuItem import android.widget.Toast import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import com.mikepenz.materialdrawer.app.databinding.ActivitySampleBinding import com.mikepenz.materialdrawer.model.interfaces.Nameable import com.mikepenz.materialdrawer.util.inflateMenu class MenuDrawerActivity : AppCompatActivity() { private lateinit var binding: ActivitySampleBinding private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivitySampleBinding.inflate(layoutInflater).also { setContentView(it.root) } // Handle Toolbar setSupportActionBar(binding.toolbar) supportActionBar?.setTitle(R.string.drawer_item_menu_drawer) supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setHomeButtonEnabled(true) actionBarDrawerToggle = ActionBarDrawerToggle(this, binding.root, binding.toolbar, com.mikepenz.materialdrawer.R.string.material_drawer_open, com.mikepenz.materialdrawer.R.string.material_drawer_close) binding.slider.apply { inflateMenu(R.menu.example_menu) onDrawerItemClickListener = { v, drawerItem, position -> if (drawerItem is Nameable) { Toast.makeText(this@MenuDrawerActivity, (drawerItem as Nameable).name!!.getText(this@MenuDrawerActivity), Toast.LENGTH_SHORT).show() } false } setSavedInstance(savedInstanceState) } // set the selection to the item with the identifier 5 if (savedInstanceState == null) { binding.slider.setSelection(5, false) } } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) actionBarDrawerToggle.onConfigurationChanged(newConfig) } override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) actionBarDrawerToggle.syncState() } override fun onOptionsItemSelected(item: MenuItem): Boolean { if (actionBarDrawerToggle.onOptionsItemSelected(item)) { return true } return super.onOptionsItemSelected(item) } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values which need to be saved from the drawer to the bundle outState = binding.slider.saveInstanceState(outState) super.onSaveInstanceState(outState) } override fun onBackPressed() { //handle the back press :D close the drawer first and if the drawer is closed close the activity if (binding.root.isDrawerOpen(binding.slider)) { binding.root.closeDrawer(binding.slider) } else { super.onBackPressed() } } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/MiniDrawerActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.content.res.Configuration import android.graphics.Color import android.net.Uri import android.os.Bundle import android.util.Log import android.view.Menu import android.view.MenuItem import android.view.View import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.widget.CompoundButton import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.mikepenz.crossfader.Crossfader import com.mikepenz.crossfader.util.UIUtils import com.mikepenz.crossfader.view.CrossFadeSlidingPaneLayout import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesomeBrand import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.iconics.utils.actionBar import com.mikepenz.iconics.utils.colorInt import com.mikepenz.materialdrawer.app.databinding.ActivityMiniDrawerBinding import com.mikepenz.materialdrawer.app.utils.CrossfadeWrapper import com.mikepenz.materialdrawer.app.utils.SystemUtils import com.mikepenz.materialdrawer.holder.BadgeStyle import com.mikepenz.materialdrawer.iconics.withIcon import com.mikepenz.materialdrawer.interfaces.OnCheckedChangeListener import com.mikepenz.materialdrawer.model.* import com.mikepenz.materialdrawer.model.interfaces.* import com.mikepenz.materialdrawer.model.utils.withIsHiddenInMiniDrawer import com.mikepenz.materialdrawer.widget.AccountHeaderView import com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView import com.mikepenz.materialdrawer.widget.MiniDrawerSliderView class MiniDrawerActivity : AppCompatActivity() { private lateinit var binding: ActivityMiniDrawerBinding //save our header or result private lateinit var headerView: AccountHeaderView private lateinit var miniSliderView: MiniDrawerSliderView private lateinit var sliderView: MaterialDrawerSliderView private lateinit var crossFader: Crossfader<*> private val onCheckedChangeListener = object : OnCheckedChangeListener { override fun onCheckedChanged(drawerItem: IDrawerItem<*>, buttonView: CompoundButton, isChecked: Boolean) { if (drawerItem is Nameable) { Log.i("material-drawer", "DrawerItem: " + (drawerItem as Nameable).name + " - toggleChecked: " + isChecked) } else { Log.i("material-drawer", "toggleChecked: $isChecked") } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMiniDrawerBinding.inflate(layoutInflater).also { setContentView(it.root) } // Handle Toolbar setSupportActionBar(binding.toolbar) //set the back arrow in the toolbar supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setTitle(R.string.drawer_item_mini_drawer) // Create a few sample profile // NOTE you have to define the loader logic too. See the CustomApplication for more details val profile = ProfileDrawerItem().withName("Mike Penz").withEmail("mikepenz@gmail.com").withIcon("https://avatars3.githubusercontent.com/u/1476232?v=3&s=460") val profile2 = ProfileDrawerItem().withName("Bernat Borras").withEmail("alorma@github.com").withIcon(Uri.parse("https://avatars3.githubusercontent.com/u/887462?v=3&s=460")) val profile3 = ProfileDrawerItem().withName("Max Muster").withEmail("max.mustermann@gmail.com").withIcon(resources.getDrawable(R.drawable.profile2)) val profile4 = ProfileDrawerItem().withName("Felix House").withEmail("felix.house@gmail.com").withIcon(resources.getDrawable(R.drawable.profile3)) val profile5 = ProfileDrawerItem().withName("Mr. X").withEmail("mister.x.super@gmail.com").withIcon(resources.getDrawable(R.drawable.profile4)).withIdentifier(4) val profile6 = ProfileDrawerItem().withName("Batman").withEmail("batman@gmail.com").withIcon(resources.getDrawable(R.drawable.profile5)) // Create the AccountHeader headerView = AccountHeaderView(this).apply { addProfiles( profile, profile2, profile3, profile4, profile5, profile6, //don't ask but google uses 14dp for the add account icon in gmail but 20dp for the normal icons (like manage account) ProfileSettingDrawerItem().withName("Add Account").withDescription("Add new GitHub Account").withIcon(GoogleMaterial.Icon.gmd_add).withIdentifier(PROFILE_SETTING.toLong()), ProfileSettingDrawerItem().withName("Manage Account").withIcon(GoogleMaterial.Icon.gmd_settings) ) onAccountHeaderListener = { view, profile, current -> //sample usage of the onProfileChanged listener //if the clicked item has the identifier 1 add a new profile ;) if (profile is IDrawerItem<*> && (profile as IDrawerItem<*>).identifier == PROFILE_SETTING.toLong()) { val newProfile = ProfileDrawerItem().withNameShown(true).withName("Batman").withEmail("batman@gmail.com").withIcon(resources.getDrawable(R.drawable.profile5)) headerView.profiles?.let { //we know that there are 2 setting elements. set the new profile above them ;) headerView.addProfile(newProfile, it.size - 2) } ?: headerView.addProfiles(newProfile) } //false if you have not consumed the event and it should close the drawer false } withSavedInstance(savedInstanceState) } sliderView = MaterialDrawerSliderView(this).apply { accountHeader = this@MiniDrawerActivity.headerView customWidth = MATCH_PARENT itemAdapter.add( PrimaryDrawerItem().withName(R.string.drawer_item_compact_header).withIcon(GoogleMaterial.Icon.gmd_brightness_5).withIdentifier(1), PrimaryDrawerItem().withName("Item NOT in mini drawer").withIcon(GoogleMaterial.Icon.gmd_bluetooth).withIdentifier(100) .withIsHiddenInMiniDrawer(true), PrimaryDrawerItem().withName(R.string.drawer_item_action_bar_drawer).withIcon(FontAwesome.Icon.faw_home).withBadge("22") .withBadgeStyle(BadgeStyle(Color.RED, Color.RED)).withIdentifier(2).withSelectable(false), PrimaryDrawerItem().withName(R.string.drawer_item_multi_drawer).withIcon(FontAwesome.Icon.faw_gamepad).withIdentifier(3), PrimaryDrawerItem().withName(R.string.drawer_item_non_translucent_status_drawer).withIcon(FontAwesome.Icon.faw_eye).withIdentifier(4), PrimaryDrawerItem().withDescription("A more complex sample").withName(R.string.drawer_item_advanced_drawer) .withIcon(GoogleMaterial.Icon.gmd_adb).withIdentifier(5), SectionDrawerItem().withName(R.string.drawer_item_section_header), SecondaryDrawerItem().withName(R.string.drawer_item_open_source).withIcon(FontAwesomeBrand.Icon.fab_github), SecondaryDrawerItem().withName(R.string.drawer_item_contact).withIcon(GoogleMaterial.Icon.gmd_format_color_fill).withTag("Bullhorn"), DividerDrawerItem(), SwitchDrawerItem().withName("Switch").withIcon(GoogleMaterial.Icon.gmd_pan_tool).withChecked(true) .withOnCheckedChangeListener(onCheckedChangeListener), ToggleDrawerItem().withName("Toggle").withIcon(GoogleMaterial.Icon.gmd_pan_tool).withChecked(true) .withOnCheckedChangeListener(onCheckedChangeListener) ) onDrawerItemClickListener = { v, item, position -> if (item is Nameable) { Toast.makeText(this@MiniDrawerActivity, item.name?.getText(this@MiniDrawerActivity), Toast.LENGTH_SHORT).show() } false } } miniSliderView = MiniDrawerSliderView(this).apply { drawer = sliderView } //get the widths in px for the first and second panel val firstWidth = UIUtils.convertDpToPixel(300f, this).toInt() val secondWidth = UIUtils.convertDpToPixel(72f, this).toInt() //create and build our crossfader (see the MiniDrawer is also builded in here, as the build method returns the view to be used in the crossfader) //the crossfader library can be found here: https://github.com/mikepenz/Crossfader crossFader = Crossfader() .withContent(findViewById(R.id.crossfade_content)) .withFirst(sliderView, firstWidth) .withSecond(miniSliderView, secondWidth) .withSavedInstance(savedInstanceState) .build() //define the crossfader to be used with the miniDrawer. This is required to be able to automatically toggle open / close miniSliderView.crossFader = CrossfadeWrapper(crossFader) //define a shadow (this is only for normal LTR layouts if you have a RTL app you need to define the other one crossFader.getCrossFadeSlidingPaneLayout().setShadowResourceLeft(com.mikepenz.materialdrawer.R.drawable.material_drawer_shadow_left) } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values, which need to be saved from the drawer to the bundle if (::sliderView.isInitialized) { outState = sliderView.saveInstanceState(outState) } //add the values, which need to be saved from the accountHeader to the bundle if (::headerView.isInitialized) { outState = headerView.saveInstanceState(outState) } //add the values, which need to be saved from the crossFader to the bundle if (::crossFader.isInitialized) { outState = crossFader.saveInstanceState(outState) } super.onSaveInstanceState(outState) } override fun onCreateOptionsMenu(menu: Menu): Boolean { val inflater = menuInflater if (SystemUtils.screenOrientation == Configuration.ORIENTATION_LANDSCAPE) { inflater.inflate(R.menu.embedded, menu) menu.findItem(R.id.menu_1).icon = IconicsDrawable(this, GoogleMaterial.Icon.gmd_sort).apply { actionBar(); colorInt = Color.WHITE } } return true } override fun onBackPressed() { //handle the back press :D close the drawer first and if the drawer is closed close the activity if (crossFader.isCrossFaded) { crossFader.crossFade() } else { super.onBackPressed() } } override fun onOptionsItemSelected(item: MenuItem): Boolean { //handle the click on the back arrow click return when (item.itemId) { R.id.menu_1 -> { crossFader.crossFade() true } android.R.id.home -> { onBackPressed() true } else -> super.onOptionsItemSelected(item) } } companion object { private const val PROFILE_SETTING = 1 } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/MultiDrawerActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.os.Bundle import android.view.MenuItem import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesomeBrand import com.mikepenz.materialdrawer.app.databinding.ActivityMultiSampleBinding import com.mikepenz.materialdrawer.app.drawerItems.GmailDrawerItem import com.mikepenz.materialdrawer.iconics.withIcon import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.SecondaryDrawerItem import com.mikepenz.materialdrawer.model.SectionDrawerItem import com.mikepenz.materialdrawer.model.interfaces.* import com.mikepenz.materialdrawer.util.updateItem class MultiDrawerActivity : AppCompatActivity() { private lateinit var binding: ActivityMultiSampleBinding override fun onCreate(savedInstanceState: Bundle?) { //supportRequestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); super.onCreate(savedInstanceState) binding = ActivityMultiSampleBinding.inflate(layoutInflater).also { setContentView(it.root) } // Handle Toolbar setSupportActionBar(binding.toolbar) supportActionBar?.setTitle(R.string.drawer_item_multi_drawer) binding.slider.apply { itemAdapter.add( GmailDrawerItem().withName(R.string.drawer_item_home).withIcon(FontAwesome.Icon.faw_home).withIdentifier(1), GmailDrawerItem().withName(R.string.drawer_item_free_play).withIcon(FontAwesome.Icon.faw_gamepad), GmailDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye).withIdentifier(5), SectionDrawerItem().withName(R.string.drawer_item_section_header), SecondaryDrawerItem().withName(R.string.drawer_item_settings).withIcon(FontAwesome.Icon.faw_cog), SecondaryDrawerItem().withName(R.string.drawer_item_help).withIcon(FontAwesome.Icon.faw_question).withEnabled(false), SecondaryDrawerItem().withName(R.string.drawer_item_open_source).withIcon(FontAwesomeBrand.Icon.fab_github), SecondaryDrawerItem().withName(R.string.drawer_item_contact).withIcon(FontAwesome.Icon.faw_bullhorn) ) adapter.onClickListener = { v, adapter, drawerItem, position -> if (drawerItem is Badgeable) { if (drawerItem.badge != null) { //note don't do this if your badge contains a "+" //only use toString() if you set the test as String val badge = Integer.valueOf(drawerItem.badge?.toString() ?: "0") if (badge > 0) { drawerItem.withBadge((badge - 1).toString()) binding.slider.updateItem(drawerItem) } } } if (drawerItem is Nameable) { Toast.makeText(this@MultiDrawerActivity, drawerItem.name?.getText(this@MultiDrawerActivity), Toast.LENGTH_SHORT).show() } false } setSavedInstance(savedInstanceState) setSelectionAtPosition(0) } binding.sliderEnd.apply { stickyHeaderView = layoutInflater.inflate(R.layout.header, null) itemAdapter.add( PrimaryDrawerItem().withName(R.string.drawer_item_home).withIcon(FontAwesome.Icon.faw_home).withIdentifier(1), PrimaryDrawerItem().withName(R.string.drawer_item_free_play).withIcon(FontAwesome.Icon.faw_gamepad), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye).withIdentifier(5), SectionDrawerItem().withName(R.string.drawer_item_section_header), SecondaryDrawerItem().withName(R.string.drawer_item_settings).withIcon(FontAwesome.Icon.faw_cog), SecondaryDrawerItem().withName(R.string.drawer_item_help).withIcon(FontAwesome.Icon.faw_question).withEnabled(false), SecondaryDrawerItem().withName(R.string.drawer_item_open_source).withIcon(FontAwesomeBrand.Icon.fab_github), SecondaryDrawerItem().withName(R.string.drawer_item_contact).withIcon(FontAwesome.Icon.faw_bullhorn) ) adapter.onClickListener = { v, adapter, drawerItem, position -> if (drawerItem is Nameable) { Toast.makeText(this@MultiDrawerActivity, drawerItem.name?.getText(this@MultiDrawerActivity), Toast.LENGTH_SHORT).show() } false } savedInstanceKey = "end" setSavedInstance(savedInstanceState) } //set the back arrow in the toolbar supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setHomeButtonEnabled(false) } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values which need to be saved from the drawer to the bundle outState = binding.slider.saveInstanceState(outState) //add the values which need to be saved from the drawer to the bundle outState = binding.sliderEnd.saveInstanceState(outState) super.onSaveInstanceState(outState) } override fun onBackPressed() { //handle the back press :D close the drawer first and if the drawer is closed close the activity when { binding.root.isDrawerOpen(binding.slider) -> binding.root.closeDrawer(binding.slider) binding.root.isDrawerOpen(binding.sliderEnd) -> binding.root.closeDrawer(binding.sliderEnd) else -> super.onBackPressed() } } override fun onOptionsItemSelected(item: MenuItem): Boolean { //handle the click on the back arrow click return when (item.itemId) { android.R.id.home -> { onBackPressed() true } else -> super.onOptionsItemSelected(item) } } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/NavControllerActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.core.os.bundleOf import androidx.navigation.findNavController import com.mikepenz.aboutlibraries.LibsBuilder import com.mikepenz.materialdrawer.app.databinding.ActivitySampleNavBinding import com.mikepenz.materialdrawer.model.DividerDrawerItem import com.mikepenz.materialdrawer.model.NavigationDrawerItem import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.interfaces.withName import com.mikepenz.materialdrawer.util.addItems import com.mikepenz.materialdrawer.util.addStickyDrawerItems import com.mikepenz.materialdrawer.util.setupWithNavController import java.io.Serializable class NavControllerActivity : AppCompatActivity() { private lateinit var binding: ActivitySampleNavBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivitySampleNavBinding.inflate(layoutInflater).also { setContentView(it.root) } val toolbar = findViewById(R.id.toolbar) setSupportActionBar(toolbar) val navController = findNavController(R.id.nav_host_fragment) binding.slider.apply { addItems( NavigationDrawerItem(R.id.action_global_fragmentHome, PrimaryDrawerItem().withName("Home"), null, null), DividerDrawerItem(), NavigationDrawerItem(R.id.messageFragment1, PrimaryDrawerItem().withName("Fragment1")), NavigationDrawerItem(R.id.messageFragment2, PrimaryDrawerItem().withName("Fragment2")) ) addStickyDrawerItems( NavigationDrawerItem(R.id.messageFragment3, PrimaryDrawerItem().withName("Fragment3")), NavigationDrawerItem(R.id.about_libraries, PrimaryDrawerItem().withName("AboutLibs"), bundleOf("data" to (LibsBuilder() as Serializable))) ) } // setup the drawer with navigation controller binding.slider.setupWithNavController(navController) } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/PersistentDrawerActivity.kt ================================================ package com.mikepenz.materialdrawer.app import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.updatePadding import com.mikepenz.crossfader.Crossfader import com.mikepenz.crossfader.util.UIUtils import com.mikepenz.crossfader.view.CrossFadeSlidingPaneLayout import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesomeBrand import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.sizeDp import com.mikepenz.materialdrawer.app.databinding.ActivityPersistentDrawerBinding import com.mikepenz.materialdrawer.app.utils.CrossfadeWrapper import com.mikepenz.materialdrawer.holder.ImageHolder import com.mikepenz.materialdrawer.iconics.withIcon import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.ProfileDrawerItem import com.mikepenz.materialdrawer.model.SecondaryDrawerItem import com.mikepenz.materialdrawer.model.SectionDrawerItem import com.mikepenz.materialdrawer.model.interfaces.* import com.mikepenz.materialdrawer.widget.AccountHeaderView import com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView import com.mikepenz.materialdrawer.widget.MiniDrawerSliderView class PersistentDrawerActivity : AppCompatActivity() { private lateinit var binding: ActivityPersistentDrawerBinding //save our header or result private lateinit var headerView: AccountHeaderView private lateinit var miniSliderView: MiniDrawerSliderView private lateinit var sliderView: MaterialDrawerSliderView private lateinit var crossFader: Crossfader<*> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityPersistentDrawerBinding.inflate(layoutInflater).also { setContentView(it.root) } //Remove line to test RTL support // getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL); //example how to implement a persistentDrawer as shown in the google material design guidelines //https://material-design.storage.googleapis.com/publish/material_v_4/material_ext_publish/0Bx4BSt6jniD7YVdKQlF3TEo2S3M/patterns_navdrawer_behavior_persistent2.png //https://www.google.com/design/spec/patterns/navigation-drawer.html#navigation-drawer-behavior // Handle Toolbar setSupportActionBar(binding.toolbar) supportActionBar?.setTitle(R.string.drawer_item_persistent_compact_header) // Create a few sample profile val profile = ProfileDrawerItem().withName("Mike Penz").withEmail("mikepenz@gmail.com").withIcon(R.drawable.profile) val profile2 = ProfileDrawerItem().withName("Max Muster").withEmail("max.mustermann@gmail.com").withIcon(R.drawable.profile2) val profile3 = ProfileDrawerItem().withName("Felix House").withEmail("felix.house@gmail.com").withIcon(R.drawable.profile3) val profile4 = ProfileDrawerItem().withName("Mr. X").withEmail("mister.x.super@gmail.com").withIcon(R.drawable.profile4) val profile5 = ProfileDrawerItem().withName("Batman").withEmail("batman@gmail.com").withIcon(R.drawable.profile5) // Create the AccountHeader headerView = AccountHeaderView(this).apply { addProfiles( profile, profile2, profile3, profile4, profile5 ) headerBackground = ImageHolder(ColorDrawable(Color.parseColor("#FDFDFD"))) } // UIUtils.getActionBarHeight(this)) //.withAccountHeader(R.layout.material_drawer_compact_persistent_header) //Create the drawer sliderView = MaterialDrawerSliderView(this).apply { accountHeader = this@PersistentDrawerActivity.headerView customWidth = ViewGroup.LayoutParams.MATCH_PARENT itemAdapter.add( PrimaryDrawerItem().withName(R.string.drawer_item_home).withIcon(FontAwesome.Icon.faw_home).withIdentifier(1), PrimaryDrawerItem().withName(R.string.drawer_item_free_play).withIcon(FontAwesome.Icon.faw_gamepad), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), SectionDrawerItem().withName(R.string.drawer_item_section_header), SecondaryDrawerItem().withName(R.string.drawer_item_settings).withIcon(FontAwesome.Icon.faw_cog), SecondaryDrawerItem().withName(R.string.drawer_item_help).withIcon(FontAwesome.Icon.faw_question).withEnabled(false), SecondaryDrawerItem().withName(R.string.drawer_item_open_source).withIcon(FontAwesomeBrand.Icon.fab_github), SecondaryDrawerItem().withName(R.string.drawer_item_contact).withIcon(FontAwesome.Icon.faw_bullhorn) ) } // create the MiniDrawer and define the drawer and header to be used (it will automatically use the items from them) miniSliderView = MiniDrawerSliderView(this).apply { includeSecondaryDrawerItems = true drawer = sliderView } //set the back arrow in the toolbar supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setHomeButtonEnabled(false) //get the widths in px for the first and second panel val firstWidth = UIUtils.convertDpToPixel(300f, this).toInt() val secondWidth = UIUtils.convertDpToPixel(72f, this).toInt() //create and build our crossfader (see the MiniDrawer is also builded in here, as the build method returns the view to be used in the crossfader) crossFader = Crossfader() .withContent(findViewById(R.id.crossfade_content)) .withFirst(sliderView as View, firstWidth) .withSecond(miniSliderView, secondWidth) .withSavedInstance(savedInstanceState) .build() //define the crossfader to be used with the miniDrawer. This is required to be able to automatically toggle open / close miniSliderView.crossFader = CrossfadeWrapper(crossFader) //define and create the arrow ;) val toggle = headerView.findViewById(R.id.material_drawer_account_header_toggle) //for RTL you would have to define the other arrow toggle.setImageDrawable(IconicsDrawable(this, GoogleMaterial.Icon.gmd_chevron_left).apply { sizeDp = 16; colorInt = Color.BLACK }) toggle.setOnClickListener { crossFader.crossFade() } ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets -> binding.toolbar.updatePadding(top = insets.systemWindowInsetTop) insets } } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values, which need to be saved from the drawer to the bundle if (::sliderView.isInitialized) { outState = sliderView.saveInstanceState(outState) } //add the values, which need to be saved from the accountHeader to the bundle if (::headerView.isInitialized) { outState = headerView.saveInstanceState(outState) } //add the values, which need to be saved from the crossFader to the bundle if (::crossFader.isInitialized) { outState = crossFader.saveInstanceState(outState) } super.onSaveInstanceState(outState) } override fun onOptionsItemSelected(item: MenuItem): Boolean { //handle the click on the back arrow click return when (item.itemId) { android.R.id.home -> { onBackPressed() true } else -> super.onOptionsItemSelected(item) } } override fun onBackPressed() { //handle the back press :D close the drawer first and if the drawer is closed close the activity if (crossFader.isCrossFaded) { crossFader.crossFade() } else { super.onBackPressed() } } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/AccountDividerDrawerItem.kt ================================================ package com.mikepenz.materialdrawer.app.drawerItems import android.content.res.ColorStateList import android.view.View import androidx.annotation.LayoutRes import androidx.core.view.ViewCompat import androidx.recyclerview.widget.RecyclerView import com.mikepenz.materialdrawer.app.R import com.mikepenz.materialdrawer.holder.ImageHolder import com.mikepenz.materialdrawer.holder.StringHolder import com.mikepenz.materialdrawer.model.AbstractDrawerItem import com.mikepenz.materialdrawer.model.interfaces.IProfile import com.mikepenz.materialdrawer.util.getDividerColor class AccountDividerDrawerItem : AbstractDrawerItem(), IProfile { override val type: Int get() = R.id.material_drawer_profile_item_divider override val layoutRes: Int @LayoutRes get() = com.mikepenz.materialdrawer.R.layout.material_drawer_item_divider override var name: StringHolder? = null override var description: StringHolder? = null override var icon: ImageHolder? = null override var iconColor: ColorStateList? = null override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) val ctx = holder.itemView.context //set the identifier from the drawerItem here. It can be used to run tests holder.itemView.id = hashCode() //define how the divider should look like holder.view.isClickable = false holder.view.isEnabled = false holder.view.minimumHeight = 1 ViewCompat.setImportantForAccessibility(holder.view, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO) //set the color for the divider holder.divider.setBackgroundColor(ctx.getDividerColor()) //call the onPostBindView method to trigger post bind view actions (like the listener to modify the item if required) onPostBindView(this, holder.itemView) } override fun getViewHolder(v: View): ViewHolder { return ViewHolder(v) } class ViewHolder internal constructor(internal val view: View) : RecyclerView.ViewHolder(view) { internal val divider: View = view.findViewById(com.mikepenz.materialdrawer.R.id.material_drawer_divider) } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/CustomBaseViewHolder.kt ================================================ package com.mikepenz.materialdrawer.app.drawerItems import android.view.View import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.mikepenz.materialdrawer.app.R open class CustomBaseViewHolder(var view: View) : RecyclerView.ViewHolder(view) { var icon: ImageView = view.findViewById(R.id.material_drawer_icon) var name: TextView = view.findViewById(R.id.material_drawer_name) var description: TextView = view.findViewById(R.id.material_drawer_description) } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/CustomCenteredPrimaryDrawerItem.kt ================================================ package com.mikepenz.materialdrawer.app.drawerItems import com.mikepenz.materialdrawer.app.R import com.mikepenz.materialdrawer.model.PrimaryDrawerItem class CustomCenteredPrimaryDrawerItem : PrimaryDrawerItem() { override val layoutRes: Int get() = R.layout.material_drawer_item_primary_centered override val type: Int get() = R.id.material_drawer_item_centered_primary } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/CustomPrimaryDrawerItem.kt ================================================ package com.mikepenz.materialdrawer.app.drawerItems import com.mikepenz.materialdrawer.holder.ColorHolder import com.mikepenz.materialdrawer.model.AbstractBadgeableDrawerItem class CustomPrimaryDrawerItem : AbstractBadgeableDrawerItem() { var background: ColorHolder? = null fun withBackgroundColor(backgroundColor: Int): CustomPrimaryDrawerItem { this.background = ColorHolder.fromColor(backgroundColor) return this } fun withBackgroundRes(backgroundRes: Int): CustomPrimaryDrawerItem { this.background = ColorHolder.fromColorRes(backgroundRes) return this } override fun bindView(holder: AbstractBadgeableDrawerItem.ViewHolder, payloads: List) { super.bindView(holder, payloads) background?.applyToBackground(holder.itemView) } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/CustomUrlBasePrimaryDrawerItem.kt ================================================ package com.mikepenz.materialdrawer.app.drawerItems import android.net.Uri import androidx.annotation.StringRes import androidx.recyclerview.widget.RecyclerView import com.mikepenz.materialdrawer.holder.ColorHolder import com.mikepenz.materialdrawer.holder.ImageHolder import com.mikepenz.materialdrawer.holder.StringHolder import com.mikepenz.materialdrawer.model.BaseDrawerItem import com.mikepenz.materialdrawer.util.DrawerImageLoader import com.mikepenz.materialdrawer.util.setDrawerVerticalPadding import com.mikepenz.materialdrawer.util.themeDrawerItem /** * Created by mikepenz on 03.02.15. */ abstract class CustomUrlBasePrimaryDrawerItem : BaseDrawerItem() { var description: StringHolder? = null var descriptionTextColor: ColorHolder? = null fun withIcon(url: String): T { this.icon = ImageHolder(url) return this as T } fun withIcon(uri: Uri): T { this.icon = ImageHolder(uri) return this as T } fun withDescription(description: String): T { this.description = StringHolder(description) return this as T } fun withDescription(@StringRes descriptionRes: Int): T { this.description = StringHolder(descriptionRes) return this as T } /** * a helper method to have the logic for all secondaryDrawerItems only once * * @param viewHolder */ protected fun bindViewHelper(viewHolder: CustomBaseViewHolder) { val ctx = viewHolder.itemView.context //set the identifier from the drawerItem here. It can be used to run tests viewHolder.itemView.id = hashCode() //get the correct color for the background val selectedColor = getSelectedColor(ctx) //get the correct color for the text val color = getColor(ctx) val shapeAppearanceModel = getShapeAppearanceModel(ctx) //set the background for the item themeDrawerItem(ctx, viewHolder.view, selectedColor, isSelectedBackgroundAnimated, shapeAppearanceModel, isSelected = isSelected) //set the text for the name StringHolder.applyTo(this.name, viewHolder.name) //set the text for the description or hide StringHolder.applyToOrHide(this.description, viewHolder.description) //set the colors for textViews viewHolder.name.setTextColor(color) //set the description text color descriptionTextColor?.applyToOr(viewHolder.description, color) //define the typeface for our textViews if (typeface != null) { viewHolder.name.typeface = typeface viewHolder.description.typeface = typeface } //we make sure we reset the image first before setting the new one in case there is an empty one DrawerImageLoader.instance.cancelImage(viewHolder.icon) viewHolder.icon.setImageBitmap(null) //get the drawables for our icon and set it icon?.applyTo(viewHolder.icon, "customUrlItem") //for android API 17 --> Padding not applied via xml setDrawerVerticalPadding(viewHolder.view) //set the item selected if it is viewHolder.itemView.isSelected = isSelected } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/CustomUrlPrimaryDrawerItem.kt ================================================ package com.mikepenz.materialdrawer.app.drawerItems import android.view.View import android.widget.TextView import androidx.annotation.LayoutRes import com.mikepenz.materialdrawer.app.R import com.mikepenz.materialdrawer.holder.BadgeStyle import com.mikepenz.materialdrawer.holder.StringHolder import com.mikepenz.materialdrawer.model.interfaces.ColorfulBadgeable /** * Created by mikepenz on 03.02.15. */ class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItem(), ColorfulBadgeable { override var badge: StringHolder? = null override var badgeStyle: BadgeStyle? = BadgeStyle() override val type: Int get() = R.id.material_drawer_item_custom_url_item override val layoutRes: Int @LayoutRes get() = com.mikepenz.materialdrawer.R.layout.material_drawer_item_primary override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) val ctx = holder.itemView.context //bind the basic view parts bindViewHelper(holder) //set the text for the badge or hide val badgeVisible = StringHolder.applyToOrHide(badge, holder.badge) //style the badge if it is visible if (badgeVisible) { badgeStyle!!.style(holder.badge, getColor(ctx)) holder.badge.visibility = View.VISIBLE } else { holder.badge.visibility = View.GONE } //define the typeface for our textViews if (typeface != null) { holder.badge.typeface = typeface } //call the onPostBindView method to trigger post bind view actions (like the listener to modify the item if required) onPostBindView(this, holder.itemView) } override fun getViewHolder(v: View): ViewHolder { return ViewHolder(v) } class ViewHolder(view: View) : CustomBaseViewHolder(view) { internal val badge: TextView = view.findViewById(R.id.material_drawer_badge) } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/GmailDrawerItem.kt ================================================ package com.mikepenz.materialdrawer.app.drawerItems import android.content.Context import android.view.View import com.google.android.material.shape.CornerFamily import com.google.android.material.shape.ShapeAppearanceModel import com.mikepenz.materialdrawer.app.R import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem import com.mikepenz.materialdrawer.util.themeDrawerItem /** * Describes the main [IDrawerItem] bing used as primary item, following the guidelines */ open class GmailDrawerItem : PrimaryDrawerItem() { override val type: Int get() = R.id.material_drawer_item_gmail_item override fun applyDrawerItemTheme(ctx: Context, view: View, selected_color: Int, animate: Boolean, shapeAppearanceModel: ShapeAppearanceModel) { themeDrawerItem(ctx, view, selected_color, animate, shapeAppearanceModel, R.dimen.gmail_material_drawer_item_background_padding_top_bottom, R.dimen.gmail_material_drawer_item_background_padding_start, R.dimen.gmail_material_drawer_item_background_padding_end, isSelected = isSelected) } override fun getShapeAppearanceModel(ctx: Context): ShapeAppearanceModel { val cornerRadius = ctx.resources.getDimensionPixelSize(R.dimen.gmail_material_drawer_item_corner_radius) return ShapeAppearanceModel.builder() .setTopRightCorner(CornerFamily.ROUNDED, cornerRadius.toFloat()) .setBottomRightCorner(CornerFamily.ROUNDED, cornerRadius.toFloat()) .build() } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/IconDrawerItem.kt ================================================ package com.mikepenz.materialdrawer.app.drawerItems import android.content.Context import android.content.res.ColorStateList import android.view.View import android.widget.ImageView import androidx.annotation.LayoutRes import androidx.recyclerview.widget.RecyclerView import com.mikepenz.materialdrawer.app.R import com.mikepenz.materialdrawer.holder.ImageHolder import com.mikepenz.materialdrawer.model.AbstractDrawerItem import com.mikepenz.materialdrawer.model.interfaces.Iconable import com.mikepenz.materialdrawer.model.interfaces.SelectIconable import com.mikepenz.materialdrawer.util.createDrawerItemColorStateList /** * Created by mikepenz on 03.02.15. */ class IconDrawerItem : AbstractDrawerItem(), Iconable, SelectIconable { override var icon: ImageHolder? = null override var iconColor: ColorStateList? = null override var selectedIcon: ImageHolder? = null override var isIconTinted = false override val type: Int get() = R.id.material_drawer_item_icon_only override val layoutRes: Int @LayoutRes get() = R.layout.material_drawer_item_icon_only override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) val ctx = holder.itemView.context //set the identifier from the drawerItem here. It can be used to run tests holder.itemView.id = hashCode() //get the correct color for the icon val iconColor = this.iconColor ?: ctx.getPrimaryDrawerIconColor() //get the drawables for our icon and set it) val icon = ImageHolder.decideIcon(icon, ctx, iconColor, isIconTinted, 1) val selectedIcon = ImageHolder.decideIcon(selectedIcon, ctx, iconColor, isIconTinted, 1) ImageHolder.applyMultiIconTo(icon, selectedIcon, iconColor, isIconTinted, holder.icon) //call the onPostBindView method to trigger post bind view actions (like the listener to modify the item if required) onPostBindView(this, holder.itemView) } override fun getViewHolder(v: View): ViewHolder { return ViewHolder(v) } class ViewHolder internal constructor(private val view: View) : RecyclerView.ViewHolder(view) { var icon: ImageView = view.findViewById(R.id.material_drawer_icon) } } internal fun Context.getPrimaryDrawerIconColor(): ColorStateList { return createDrawerItemColorStateList(this, com.mikepenz.materialdrawer.R.styleable.MaterialDrawerSliderView_materialDrawerPrimaryIcon)!! } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/OverflowMenuDrawerItem.kt ================================================ package com.mikepenz.materialdrawer.app.drawerItems import android.view.View import android.widget.ImageButton import androidx.annotation.LayoutRes import androidx.appcompat.widget.PopupMenu import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.iconics.utils.sizeDp import com.mikepenz.materialdrawer.app.R import com.mikepenz.materialdrawer.model.BaseDescribeableDrawerItem import com.mikepenz.materialdrawer.model.BaseViewHolder /** * Created by mikepenz on 03.02.15. */ class OverflowMenuDrawerItem : BaseDescribeableDrawerItem() { var menu: Int = 0 var onMenuItemClickListener: PopupMenu.OnMenuItemClickListener? = null var onDismissListener: PopupMenu.OnDismissListener? = null override val type: Int get() = R.id.material_drawer_item_overflow_menu override val layoutRes: Int @LayoutRes get() = R.layout.material_drawer_item_overflow_menu_primary @Deprecated("Use property setter instead") fun withMenu(menu: Int): OverflowMenuDrawerItem { this.menu = menu return this } @Deprecated("Use property setter instead") fun withOnMenuItemClickListener(onMenuItemClickListener: PopupMenu.OnMenuItemClickListener): OverflowMenuDrawerItem { this.onMenuItemClickListener = onMenuItemClickListener return this } @Deprecated("Use property setter instead") fun withOnDismissListener(onDismissListener: PopupMenu.OnDismissListener): OverflowMenuDrawerItem { this.onDismissListener = onDismissListener return this } override fun bindView(holder: ViewHolder, payloads: List) { super.bindView(holder, payloads) val ctx = holder.itemView.context //bind the basic view parts bindViewHelper(holder) //handle menu click holder.menu.setOnClickListener { view -> val popup = PopupMenu(view.context, view) val inflater = popup.menuInflater inflater.inflate(menu, popup.menu) popup.setOnMenuItemClickListener(onMenuItemClickListener) popup.setOnDismissListener(onDismissListener) popup.show() } //handle image holder.menu.setImageDrawable(IconicsDrawable(ctx, GoogleMaterial.Icon.gmd_more_vert).apply { sizeDp = 12; colorList = getIconColor(ctx) }) //call the onPostBindView method to trigger post bind view actions (like the listener to modify the item if required) onPostBindView(this, holder.itemView) } override fun getViewHolder(v: View): ViewHolder { return ViewHolder(v) } class ViewHolder(view: View) : BaseViewHolder(view) { internal val menu: ImageButton = view.findViewById(R.id.material_drawer_menu_overflow) } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/fragment/DemoFragment.kt ================================================ package com.mikepenz.materialdrawer.app.fragment import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import com.mikepenz.materialdrawer.app.databinding.FragmentSampleBinding /** * A simple [Fragment] subclass. * This is just a demo fragment with a long scrollable view of editTexts. Don't see this as a reference for anything */ class DemoFragment : Fragment() { private var _binding: FragmentSampleBinding? = null private val binding get() = _binding!! override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { // Inflate the layout for this fragment // don't look at this layout it's just a listView to show how to handle the keyboard _binding = FragmentSampleBinding.inflate(inflater, container, false) binding.title.text = arguments?.getString(KEY_TITLE) return binding.root } companion object { private val KEY_TITLE = "title" fun newInstance(title: String): DemoFragment { return DemoFragment().apply { arguments = Bundle().apply { putString(KEY_TITLE, title) } } } } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/fragment/DemoMessageFragment.kt ================================================ package com.mikepenz.materialdrawer.app.fragment import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import com.mikepenz.materialdrawer.app.R import com.mikepenz.materialdrawer.app.databinding.FragmentMessageSampleBinding class DemoMessageFragment : Fragment() { private var _binding: FragmentMessageSampleBinding? = null private val binding get() = _binding!! private var message: String? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { message = arguments?.let { DemoMessageFragmentArgs.fromBundle(it).message } _binding = FragmentMessageSampleBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.messageTextView.text = "$message" binding.btnFragmentHome.setOnClickListener { navigateTo(R.id.fragmentHome) } binding.btnFragment1.setOnClickListener { navigateTo(R.id.messageFragment1) } binding.btnFragment2.setOnClickListener { navigateTo(R.id.messageFragment2) } binding.btnFragment3.setOnClickListener { navigateTo(R.id.messageFragment3) } binding.btnPopup.setOnClickListener { navigateTo(R.id.action_global_fragmentHome) } } private fun navigateTo(destination: Int) { findNavController().navigate(destination) } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/fragment/DrawerFragment.kt ================================================ package com.mikepenz.materialdrawer.app.fragment import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesomeBrand import com.mikepenz.materialdrawer.app.R import com.mikepenz.materialdrawer.app.databinding.FragmentSimpleSampleBinding import com.mikepenz.materialdrawer.iconics.withIcon import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.SecondaryDrawerItem import com.mikepenz.materialdrawer.model.SectionDrawerItem import com.mikepenz.materialdrawer.model.interfaces.withEnabled import com.mikepenz.materialdrawer.model.interfaces.withIdentifier import com.mikepenz.materialdrawer.model.interfaces.withName /** * A simple [Fragment] subclass. * This is just a demo fragment with a long scrollable view of editTexts. Don't see this as a reference for anything */ class DrawerFragment : Fragment() { private var _binding: FragmentSimpleSampleBinding? = null private val binding get() = _binding!! override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { // Inflate the layout for this fragment // don't look at this layout it's just a listView to show how to handle the keyboard _binding = FragmentSimpleSampleBinding.inflate(inflater, container, false) binding.title.text = arguments?.getString(KEY_TITLE) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.slider.apply { itemAdapter.add( PrimaryDrawerItem().withName(R.string.drawer_item_home).withIcon(FontAwesome.Icon.faw_home).withIdentifier(1), PrimaryDrawerItem().withName(R.string.drawer_item_free_play).withIcon(FontAwesome.Icon.faw_gamepad), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye), SectionDrawerItem().withName(R.string.drawer_item_section_header), SecondaryDrawerItem().withName(R.string.drawer_item_settings).withIcon(FontAwesome.Icon.faw_cog), SecondaryDrawerItem().withName(R.string.drawer_item_help).withIcon(FontAwesome.Icon.faw_question).withEnabled(false), SecondaryDrawerItem().withName(R.string.drawer_item_open_source).withIcon(FontAwesomeBrand.Icon.fab_github), SecondaryDrawerItem().withName(R.string.drawer_item_contact).withIcon(FontAwesome.Icon.faw_bullhorn) ) setSelection(1) setSavedInstance(savedInstanceState) } } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values which need to be saved from the drawer to the bundle outState = binding.slider.saveInstanceState(outState) super.onSaveInstanceState(outState) } companion object { private const val KEY_TITLE = "title" fun newInstance(title: String): DrawerFragment { return DrawerFragment().apply { arguments = Bundle().apply { putString(KEY_TITLE, title) } } } } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/fragment/SecondDrawerFragment.kt ================================================ package com.mikepenz.materialdrawer.app.fragment import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome import com.mikepenz.materialdrawer.app.R import com.mikepenz.materialdrawer.app.databinding.FragmentSimpleSampleBinding import com.mikepenz.materialdrawer.iconics.withIcon import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.interfaces.withIdentifier import com.mikepenz.materialdrawer.model.interfaces.withName /** * A simple [Fragment] subclass. * This is just a demo fragment with a long scrollable view of editTexts. Don't see this as a reference for anything */ class SecondDrawerFragment : Fragment() { private var _binding: FragmentSimpleSampleBinding? = null private val binding get() = _binding!! override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { // Inflate the layout for this fragment // don't look at this layout it's just a listView to show how to handle the keyboard _binding = FragmentSimpleSampleBinding.inflate(inflater, container, false) binding.title.text = arguments?.getString(KEY_TITLE) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.slider.apply { itemAdapter.add( PrimaryDrawerItem().withName(R.string.drawer_item_home).withIcon(FontAwesome.Icon.faw_home).withIdentifier(1), PrimaryDrawerItem().withName(R.string.drawer_item_free_play).withIcon(FontAwesome.Icon.faw_gamepad), PrimaryDrawerItem().withName(R.string.drawer_item_custom).withIcon(FontAwesome.Icon.faw_eye) ) setSavedInstance(savedInstanceState) setSelection(1) } } override fun onSaveInstanceState(_outState: Bundle) { var outState = _outState //add the values which need to be saved from the drawer to the bundle outState = binding.slider.saveInstanceState(outState) super.onSaveInstanceState(outState) } companion object { private val KEY_TITLE = "title" fun newInstance(title: String): SecondDrawerFragment { return SecondDrawerFragment().apply { arguments = Bundle().apply { putString(KEY_TITLE, title) } } } } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/utils/CrossfadeWrapper.kt ================================================ package com.mikepenz.materialdrawer.app.utils import com.mikepenz.crossfader.Crossfader import com.mikepenz.materialdrawer.interfaces.ICrossfader /** * Created by mikepenz on 18.07.15. */ class CrossfadeWrapper(private val crossfader: Crossfader<*>) : ICrossfader { override val isCrossfaded: Boolean get() = crossfader.isCrossFaded() override fun crossfade() { crossfader.crossFade() } } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/utils/SystemUtils.kt ================================================ package com.mikepenz.materialdrawer.app.utils import android.content.res.Resources object SystemUtils { val screenOrientation: Int get() = Resources.getSystem().configuration.orientation } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/utils/UIUtils.kt ================================================ package com.mikepenz.materialdrawer.app.utils import android.content.Context import android.content.res.Resources import android.util.DisplayMetrics /** * This method converts dp unit to equivalent pixels, depending on device density. * * @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels * @param context Context to get resources and device specific display metrics * @return A float value to represent px equivalent to dp depending on device density */ fun convertDpToPixel(dp: Float, context: Context): Float { val resources: Resources = context.resources val metrics: DisplayMetrics = resources.displayMetrics return dp * (metrics.densityDpi / 160f) } ================================================ FILE: app/src/main/java/com/mikepenz/materialdrawer/app/widget/CrossfadeDrawerLayout.kt ================================================ package com.mikepenz.materialdrawer.app.widget import android.content.Context import android.util.AttributeSet import android.view.MotionEvent import android.view.View import android.view.ViewGroup import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.ViewCompat import androidx.drawerlayout.widget.DrawerLayout import com.mikepenz.crossfadedrawerlayout.ApplyTransformationListener import com.mikepenz.crossfadedrawerlayout.animation.ResizeWidthAnimation import com.mikepenz.materialdrawer.app.R import com.mikepenz.materialdrawer.app.utils.convertDpToPixel /** * Created by mikepenz on 20.10.15. */ open class CrossfadeDrawerLayout : DrawerLayout { var drawerOpened = false private set private var touchDown = -1f private var prevTouch = -1f //remember the previous width to optimize performance private var prevWidth = -1 var crossfadeListener: ((containerView: View?, currentSlidePercentage: Float, slideOffset: Int) -> Unit)? = null var minWidthPx = 0 var maxWidthPx = 0 lateinit var container: ConstraintLayout private set lateinit var smallView: ViewGroup private set lateinit var largeView: ViewGroup private set var isCrossfaded = false private set var sliderOnRight = false constructor(context: Context) : super(context) { init(context) } constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { init(context) } constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) { init(context) } private fun init(ctx: Context) { super.addDrawerListener(innerDrawerListener) //define default valuse for min and max minWidthPx = convertDpToPixel(72f, ctx).toInt() maxWidthPx = convertDpToPixel(200f, ctx).toInt() } override fun addView(child: View, index: Int) { super.addView(wrapSliderContent(child, index), index) } override fun addView(child: View, index: Int, params: ViewGroup.LayoutParams?) { super.addView(wrapSliderContent(child, index), index, params) } /** * this will wrap the view which is added to the slider into another layout so we can then overlap the small and large view * * @param child * @param index * @return */ private fun wrapSliderContent(child: View, index: Int): View? { if (child.id == R.id.crossFadeSlider) { container = child as ConstraintLayout largeView = child.findViewById(R.id.crossFadeLargeView) largeView.alpha = 0f largeView.visibility = View.GONE smallView = child.findViewById(R.id.crossFadeSmallView) return container } return child } private var innerDrawerListener = object : DrawerListener { override fun onDrawerSlide(drawerView: View, slideOffset: Float) { drawerOpened = slideOffset == 1f } override fun onDrawerOpened(drawerView: View) { drawerOpened = true } override fun onDrawerClosed(drawerView: View) { val lp = drawerView.layoutParams as MarginLayoutParams lp.width = minWidthPx drawerView.layoutParams = lp //revert alpha :D smallView.alpha = 1f smallView.bringToFront() largeView.alpha = 0f drawerOpened = false } override fun onDrawerStateChanged(newState: Int) {} } override fun dispatchTouchEvent(motionEvent: MotionEvent): Boolean { if (drawerOpened) { if (motionEvent.action == MotionEvent.ACTION_DOWN) { touchDown = motionEvent.x prevTouch = motionEvent.x return super.dispatchTouchEvent(motionEvent) } else if (motionEvent.action == MotionEvent.ACTION_UP) { val click = touchDown == prevTouch touchDown = -1f prevTouch = -1f val lp = container.layoutParams as MarginLayoutParams val percentage = calculatePercentage(lp.width) if (percentage > 50) { fadeUp(DEFAULT_ANIMATION) } else { fadeDown(DEFAULT_ANIMATION) } return if (click) { super.dispatchTouchEvent(motionEvent) } else { true } } else if (motionEvent.action == MotionEvent.ACTION_MOVE && touchDown != -1f) { val lp = container.layoutParams as MarginLayoutParams //the current drawer width var diff = motionEvent.x - touchDown if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL || sliderOnRight) { diff *= -1 } if (diff == 0f) { //no difference nothing to do //return super.dispatchTouchEvent(motionEvent); } else if (diff > 0 && lp.width <= maxWidthPx && lp.width + diff < maxWidthPx && lp.width >= minWidthPx) { lp.width = (lp.width + diff).toInt() container.layoutParams = lp touchDown = motionEvent.x overlapViews(lp.width) } else if (diff < 0 && lp.width >= minWidthPx && lp.width + diff > minWidthPx) { lp.width = (lp.width + diff).toInt() container.layoutParams = lp touchDown = motionEvent.x overlapViews(lp.width) } else if (lp.width < minWidthPx) { lp.width = minWidthPx container.layoutParams = lp drawerOpened = false touchDown = -1f overlapViews(minWidthPx) } else if (lp.width + diff < minWidthPx) { //return super.dispatchTouchEvent(motionEvent); } //return true; } } return super.dispatchTouchEvent(motionEvent) } override fun onTouchEvent(motionEvent: MotionEvent): Boolean { try { return super.onTouchEvent(motionEvent) } catch (ex: RuntimeException) { ex.printStackTrace() } return false } override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { try { return super.onInterceptTouchEvent(ev) } catch (ex: IllegalArgumentException) { ex.printStackTrace() } return false } override fun openDrawer(gravity: Int) { drawerOpened = true super.openDrawer(gravity) } override fun openDrawer(drawerView: View) { drawerOpened = true super.openDrawer(drawerView) } override fun openDrawer(drawerView: View, animate: Boolean) { drawerOpened = true super.openDrawer(drawerView, animate) } override fun openDrawer(gravity: Int, animate: Boolean) { drawerOpened = true super.openDrawer(gravity, animate) } override fun closeDrawer(drawerView: View) { drawerOpened = false container.clearAnimation() super.closeDrawer(drawerView) } override fun closeDrawer(drawerView: View, animate: Boolean) { drawerOpened = false container.clearAnimation() super.closeDrawer(drawerView, animate) } override fun closeDrawer(gravity: Int) { drawerOpened = false container.clearAnimation() super.closeDrawer(gravity) } override fun closeDrawer(gravity: Int, animate: Boolean) { drawerOpened = false container.clearAnimation() super.closeDrawer(gravity, animate) } /** * crossfade the small to the large view (with default animation time) */ @JvmOverloads fun crossfade(duration: Int = DEFAULT_ANIMATION) { if (isCrossfaded) { fadeDown(duration) } else { fadeUp(duration) } } /** * animate to the large view * * @param duration */ fun fadeUp(duration: Int) { //animate up container.clearAnimation() val anim = ResizeWidthAnimation(container, maxWidthPx, ApplyTransformationListener { width -> overlapViews(width) }) anim.duration = duration.toLong() container.startAnimation(anim) } /** * animate to the small view * * @param duration */ fun fadeDown(duration: Int) { //fade down container.clearAnimation() val anim = ResizeWidthAnimation(container, minWidthPx, ApplyTransformationListener { width -> overlapViews(width) }) anim.duration = duration.toLong() container.startAnimation(anim) } /** * calculate the percentage to how many percent the slide is already visible * * @param width * @return */ private fun calculatePercentage(width: Int): Float { val absolute = maxWidthPx - minWidthPx val current = width - minWidthPx val percentage = 100.0f * current / absolute //we can assume that we are crossfaded if the percentage is > 90 isCrossfaded = percentage > 90 return percentage } /** * overlap the views and provide the crossfade effect * * @param width */ private fun overlapViews(width: Int) { if (width == prevWidth) { return } //remember this width so it is't processed twice prevWidth = width val percentage = calculatePercentage(width) val alpha = percentage / 100 smallView.alpha = 1f smallView.isClickable = false largeView.bringToFront() largeView.alpha = alpha largeView.isClickable = true largeView.visibility = if (alpha > 0.01f) View.VISIBLE else View.GONE //notify the crossfadeListener crossfadeListener?.invoke(container, calculatePercentage(width), width) } companion object { private const val DEFAULT_ANIMATION = 200 } } ================================================ FILE: app/src/main/res/layout/activity_embedded.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_mini_drawer.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_multi_sample.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_persistent_drawer.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_sample.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_sample_actionbar.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_sample_collapsing_toolbar.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_sample_crossfader.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_sample_fragment.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_sample_fullscreen.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_sample_nav.xml ================================================ ================================================ FILE: app/src/main/res/layout/footer.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_message_sample.xml ================================================