1

Probably you have seen the side Navigation drawer of apps like Gmail. But how do you make such a drawer with custom widgets for example I present a navigation drawer that has some widgets placed randomly inside:

enter image description here

I'd like to use the constraintLayout inside the navigation view. Basically, I'd like it to be a normal layout/view that occupies a certain percentage of screen and has slide in and slide out animation.

Edit

If you don't add app:menu=@menu/menu_nav then it basically crashes and if you add a blank menu then you can't put just the constraintLayout inside of the navigation menu, you have to have the constraintLayout inside a FrameLayout and.... finally it doesn't work properly, say you use a match constraint in an imageView then the image doesn't display, although hardcoded strings are being ok for now, but that isn't really solving the problem of views being dynamic.

halfer
  • 19,824
  • 17
  • 99
  • 186
juztcode
  • 1,196
  • 2
  • 21
  • 46
  • Does this answer your question? [How to create a custom navigation drawer in android](https://stackoverflow.com/questions/21796209/how-to-create-a-custom-navigation-drawer-in-android) – Zain Feb 19 '20 at 05:05
  • @Zain, I think it's a bit different since I'd like to be able to use constraintLayout inside the navigation drawer – juztcode Feb 19 '20 at 05:09
  • I seriously don't get why people downvote – juztcode Feb 19 '20 at 09:49
  • @justcode I believe they must say what's wrong... I think you should have some try although I didn't downvote.. Wish you find a solution – Zain Feb 19 '20 at 10:14
  • @Zain , ofcourse I've tried look at the discussion below, I even enrolled for coursera's lectures, but I don't know if this thing should be done in opengl from scratch , don't know if it's possible with surfaceView or anything since Im just strting out this android and it provides no learning framework whatsoever – juztcode Feb 19 '20 at 10:45
  • @Zain , the tutorials that you point also tell you how to make a navigation bar, but android provides good tools to do that I don't know any reason why would we want to create our own. What I want was a drawer style view that contains other items. IT's as simple as a layout just sliding in on a gesture which would just be changing location of the layout, but how do I do that on top of an already existing layout, is changing location even possible? – juztcode Feb 19 '20 at 10:47
  • You are right, android APIs lack for this basic thing; I am not totally sure about something to post it as a solution; but I am curios about it; if you find a solution please drop me a tag :) – Zain Feb 19 '20 at 10:53
  • sure, I'll be sure to document it here on stackexchange – juztcode Feb 19 '20 at 11:12
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/208138/discussion-between-zain-and-juztcode). – Zain Feb 19 '20 at 16:36

1 Answers1

5

In order to use a custom layout for the NavigationDrawer, you can wrap your custom layout within the NavigationView, so that your layout structure will look like the below:

<?xml version="1.0" encoding="utf-8"?>

<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">


    <!--  MainActivity Layout -->
    <include
        layout="@layout/activity_main_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />



    <!--    NavigationView -->
    <com.google.android.material.navigation.NavigationView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start">

        <!--   Custom NavigationView Layout-->

    </com.google.android.material.navigation.NavigationView>



</androidx.drawerlayout.widget.DrawerLayout>

With that in place, you can freely customize your NavigationView layout as you want, like putting ConstraintLayout or any layout as you like. And you can also add buttons' listeners like you can do with a normal layout.

Here is a demo that you can start from, the credits of the VerticalButton back to this tutorial

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ADADAD"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">


    <!--  Main Layout -->
    <include
        layout="@layout/activity_main_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!--    NavigationView Layout-->
    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#666666">

            <!--  Header Layout -->
            <include
                android:id="@+id/include"
                layout="@layout/nav_header_main" />

            <Button
                android:id="@+id/button1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="16dp"
                android:background="#ffff00"
                android:onClick="onNavigationButtonClick"
                android:text="Button1"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/include" />

            <com.example.android.customnavigationdrawerconstraintlayout.VerticalButton
                android:id="@+id/button2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="24dp"
                android:layout_marginLeft="24dp"
                android:layout_marginTop="24dp"
                android:background="#ffff00"
                android:onClick="onNavigationButtonClick"
                android:text="Button2"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/button1" />

            <com.example.android.customnavigationdrawerconstraintlayout.VerticalButton
                android:id="@+id/button3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="24dp"
                android:layout_marginRight="24dp"
                android:background="#ffff00"
                android:onClick="onNavigationButtonClick"
                android:text="button3"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/button1" />

            <ImageView
                android:id="@+id/imageView2"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_marginStart="64dp"
                android:layout_marginLeft="64dp"
                android:layout_marginTop="32dp"
                android:layout_marginEnd="64dp"
                android:layout_marginRight="64dp"
                android:layout_marginBottom="16dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/button2"
                android:src="@drawable/ic_android" />

        </androidx.constraintlayout.widget.ConstraintLayout>

    </com.google.android.material.navigation.NavigationView>


</androidx.drawerlayout.widget.DrawerLayout>

activity_main_content.xml (MainActivity layout)

<?xml version="1.0" encoding="utf-8"?>

<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar_main"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

        </androidx.appcompat.widget.Toolbar>

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


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center">

        <TextView
            android:id="@+id/tv_main"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="22sp" />

    </LinearLayout>


</androidx.coordinatorlayout.widget.CoordinatorLayout>

nav_header_main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="180dp"
    android:background="@color/colorAccent"
    android:gravity="bottom"
    android:orientation="vertical"
    android:padding="16dp"
    android:theme="@style/ThemeOverlay.AppCompat.Dark">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:paddingTop="8dp"
        app:srcCompat="@drawable/ic_launcher_foreground" />


</LinearLayout>

VerticalButton

public class VerticalButton extends Button {
    final boolean topDown;

    public VerticalButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        final int gravity = getGravity();
        if (Gravity.isVertical(gravity) && (gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) {
            setGravity((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) | Gravity.TOP);
            topDown = true;
        } else
            topDown = false;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(heightMeasureSpec, widthMeasureSpec);
        setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        TextPaint textPaint = getPaint();
        textPaint.setColor(getCurrentTextColor());
        textPaint.drawableState = getDrawableState();

        canvas.save();

        if (topDown) {
            canvas.translate(getWidth(), 0);
            canvas.rotate(90);
        } else {
            canvas.translate(0, getHeight());
            canvas.rotate(-90);
        }

        canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop());
        getLayout().draw(canvas);
        canvas.restore();
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {

    DrawerLayout mDrawerLayout;
    NavigationView navView;
    Toolbar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mDrawerLayout = findViewById(R.id.drawer);
        navView = findViewById(R.id.navView);
        toolbar = findViewById(R.id.toolbar_main);

        setupDrawer();

    }


    private void setupDrawer() {
        // Show the burger button on the ActionBar
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this,
                mDrawerLayout, toolbar,
                R.string.navigation_drawer_open,
                R.string.navigation_drawer_close);

        mDrawerLayout.addDrawerListener(toggle);
        toggle.syncState();
    }


    public void onNavigationButtonClick(View view) {

        TextView tvMain = findViewById(R.id.tv_main);
        tvMain.setText(((Button) view).getText().toString());
        mDrawerLayout.closeDrawer(navView);

        switch (view.getId()) {
            case R.id.button1:
                // Do something with button 1
                break;

            case R.id.button2:
                // Do something with button 2
                break;

            case R.id.button3:
                // Do something with button 3
                break;

        }
    }
}

strings.xml

<resources>
    <string name="app_name">Custom NavigationView</string>
    <string name="navigation_drawer_open">Open navigation drawer</string>
    <string name="navigation_drawer_close">Close navigation drawer</string>
</resources>

Material design dependency

implementation 'com.google.android.material:material:1.0.0'

Preview

Zain
  • 37,492
  • 7
  • 60
  • 84
  • I tried something similar to this and if you didn't put header and menu using `app:menu="@menu/menu_nav` and `headerLayout` it crashed. I don't know if this is specific bug to kitkat though, I was targeting the platform and onwards. I'll try this one more time as you have presented here. Thanks for answering :) – juztcode Feb 19 '20 at 13:53
  • @juztcode I have tested on KitKat, it did crash and the problem was on using a Vector drawable on ImageView which is not supported; so I modified the code of nav_header_main.xml with `android:src="@drawable/ic_android"`; but you can't use xml vector drawable; instead you must use different densities (hdpi, xhdpi, xxhdpi...) for your image ... – Zain Feb 19 '20 at 15:06
  • vector drawables not supported in navigation view only? Because I have been using vectordrawables in Imageview on other places using app:srcCompat – juztcode Feb 19 '20 at 15:08
  • You can comment out those ImageViews for testing purpose to make sure your app not crashing – Zain Feb 19 '20 at 15:10
  • it's not supported on newer versions? Aren't vector drawables more newer advancement? They even have a vector assest manager to check eveerything is right with the vector image, on prelollipop using support library should do fine right? https://stackoverflow.com/questions/36867298/using-android-vector-drawables-on-pre-lollipop-crash – juztcode Feb 19 '20 at 15:12
  • Sorry, I mean lower versions below API 21 – Zain Feb 19 '20 at 15:16
  • right, so using the support library below 21 should work shouldn't it? – juztcode Feb 19 '20 at 15:16
  • should work if you use different densities rather than vector drawables .. if your app is just supported in API 21+, then you can freely use vector drawables – Zain Feb 19 '20 at 15:18
  • @juztcode I mean that I changed the .xml drawable vector and provided different densities png drawables in my app (so don't use the app launcher icon unless you provide its different densities) – Zain Feb 19 '20 at 15:36
  • it finally budged, even constraint layout works now. I really thank you mate :) But finding out something like this is really hard to a novice like me if it wasn't for good people here on forums we'd be lost(really lost). So can you give me a pointer on how people go about creating these sort of layout? What is used to create this Navigation Drawable? Did they use Canvas animations or something and how did they create two overlaps of views and arrange that xml structure i.e. any layout that comes before adding the navigation is the default shown in the page? – juztcode Feb 19 '20 at 15:42
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/208139/discussion-between-zain-and-juztcode). – Zain Feb 19 '20 at 16:45
  • @Zain can I padding hamburger menu from left to right? –  Mar 07 '21 at 19:22
  • @Skysoft13 do you mean to move it from left to right .. or add padding? – Zain Mar 08 '21 at 02:15
  • @Zain I mean like this https://stackoverflow.com/questions/66518231/how-can-i-padding-right-hamburger-button-in-android-toolbar/66518279#66518279 –  Mar 08 '21 at 07:33