Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open second drawerlayout as a sub drawerlayout over the first

Android Studio 2.1.3

I have this design I am trying to follow.

On the first drawerlayout I have a setttings options.

enter image description here

When the user clicks, it will open a second drawerlayout like this below.

enter image description here

The user can get back to the first by clicking on the arrow Main Menu.

Is this possible?

Many thanks for any suggestions

like image 822
ant2009 Avatar asked Aug 18 '16 04:08

ant2009


People also ask

How do you make DrawerLayout give an example?

To use a DrawerLayout, position your primary content view as the first child with width and height of match_parent and no layout_gravity> . Add drawers as child views after the main content view and set the layout_gravity appropriately.

How do I open a navigation drawer?

The navigation drawer is a UI panel that shows your app's main navigation menu. The drawer appears when the user touches the drawer icon in the app bar or when the user swipes a finger from the left edge of the screen. Figure 3. An open drawer displaying a navigation menu.

How do I use the same navigation drawer in all activities?

Sometimes, our app requires a common navigation drawer for all activities in the app. For implementing it, We can implement it by removing the same code from all activities and write it properly in our BaseActivity. 1. We have to add a navigation drawer and FrameLayout base_activity's XML.

What is the purpose of DrawerLayout and navigationView?

Drawer Layout is the root layout in which we define a FrameLayout and a Navigation View. In Navigation View we set the items from menu file and FrameLayout is used to replace the Fragments on the click of menu items.


1 Answers

It's unclear how exactly you wish to implement your drawer UI, so the following solution is rather generic, in that it should work with NavigationViews, RecyclerViews, or pretty much whatever type of Views you'd like.

This solution uses a custom ViewSwitcher subclass that acts as a DrawerLayout's left drawer, and holds two child Views, one being the main drawer View, and the other being the second drawer that opens over it.

The DoubleDrawerView class is a relatively simple ViewSwitcher that loads its own Animations, and juggles them appropriately to give the effect of a second drawer opening and closing over the first. It tracks its own state so that it can be restored correctly after a device rotation, etc.

public class DoubleDrawerView extends ViewSwitcher {
    private static final int NONE = -1;
    private static final int MAIN_VIEW_INDEX = 0;
    private static final int DRAWER_VIEW_INDEX = 1;

    private Animation slideInAnimation, slideOutAnimation, noAnimation;
    private boolean animating = false;

    private Animation.AnimationListener listener = new Animation.AnimationListener() {
        @Override
        public void onAnimationEnd(Animation anim) {
            animating = false;
        }

        @Override
        public void onAnimationStart(Animation anim) {}

        @Override
        public void onAnimationRepeat(Animation anim) {}
    };

    public DoubleDrawerView(Context context) {
        this(context, null);
    }

    public DoubleDrawerView(Context context, AttributeSet attrs) {
        super(context, attrs);

        slideInAnimation = AnimationUtils.loadAnimation(context, R.anim.slide_in_left);
        slideOutAnimation = AnimationUtils.loadAnimation(context, R.anim.slide_out_left);
        noAnimation = AnimationUtils.loadAnimation(context, R.anim.none);
        noAnimation.setAnimationListener(listener);
    }

    public void openInnerDrawer() {
        if (getDisplayedChild() != DRAWER_VIEW_INDEX) {
            setChildAndAnimate(DRAWER_VIEW_INDEX, true);
        }
    }

    public void closeInnerDrawer() {
        if (getDisplayedChild() != MAIN_VIEW_INDEX) {
            setChildAndAnimate(MAIN_VIEW_INDEX, true);
        }
    }

    public boolean isInnerDrawerOpen() {
        return getDisplayedChild() == DRAWER_VIEW_INDEX;
    }

    private void setChildAndAnimate(int whichChild, boolean doAnimate) {
        if (doAnimate) {
            setAnimationForChild(whichChild);
        }
        else {
            setAnimationForChild(NONE);
        }
        animating = doAnimate;
        setDisplayedChild(whichChild);
    }

    private void setAnimationForChild(int whichChild) {
        if (whichChild == DRAWER_VIEW_INDEX) {
            setInAnimation(slideInAnimation);
            setOutAnimation(noAnimation);
        }
        else if (whichChild == MAIN_VIEW_INDEX) {
            setInAnimation(noAnimation);
            setOutAnimation(slideOutAnimation);
        }
        else {
            setInAnimation(null);
            setOutAnimation(null);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (animating) {
            return true;
        }
        else {
            return super.onInterceptTouchEvent(ev);
        }
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.whichChild = getDisplayedChild();
        return ss;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());
        setChildAndAnimate(ss.whichChild, false);
    }

    private static class SavedState extends BaseSavedState {
        int whichChild;

        SavedState(Parcelable superState) {
            super(superState);
        }

        private SavedState(Parcel in) {
            super(in);
            whichChild = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(whichChild);
        }

        public static final Parcelable.Creator<SavedState>
            CREATOR = new Parcelable.Creator<SavedState>() {

            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }
}

DoubleDrawerView uses the following XML files for its Animations. These should be in your project's res/anim/ folder.

slide_in_left.xml

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="-100%p" android:toXDelta="0"
    android:duration="@android:integer/config_mediumAnimTime"/>

slide_out_left.xml

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0" android:toXDelta="-100%p"
    android:duration="@android:integer/config_mediumAnimTime"/>

none.xml

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="1.0" android:toAlpha="1.0"
    android:duration="@android:integer/config_mediumAnimTime" />

This example's layout is a standard DrawerLayout with a DoubleDrawerView for its drawer, and two simple NavigationViews therein. Do note that the main drawer View must be listed first inside the DoubleDrawerView, with the second, inner drawer View after.

activity_main.xml

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/main_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.example.doubledrawer.DoubleDrawerView
        android:id="@+id/double_drawer_view"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="left">

        <android.support.design.widget.NavigationView
            android:id="@+id/main_navigation_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:menu="@menu/navigation_main" />

        <android.support.design.widget.NavigationView
            android:id="@+id/settings_navigation_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:menu="@menu/navigation_settings" />

    </com.example.doubledrawer.DoubleDrawerView>

</android.support.v4.widget.DrawerLayout>

For the sake of a complete cut and paste example, some simple res/menu/ files for the NavigationViews above.

navigation_main.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <group
        android:id="@+id/group_screens"
        android:checkableBehavior="single">
        <item
            android:id="@+id/menu_screen_1"
            android:title="Screen 1" />
        <item
            android:id="@+id/menu_screen_2"
            android:title="Screen 2"/>
    </group>

    <item
        android:id="@+id/menu_open_settings"
        android:title="Open Settings" />

</menu>

navigation_settings.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/menu_close_settings"
        android:title="Back to Main" />

    <group
        android:id="@+id/group_settings">
        <item
            android:id="@+id/menu_setting_1"
            android:title="Setting 1" />
        <item
            android:id="@+id/menu_setting_2"
            android:title="Setting 2" />
    </group>

</menu>

In the example Activity, we just get references to the DoubleDrawerView and NavigationViews, and implement an OnNavigationItemSelectedListener to open and close the inner drawer accordingly.

public class MainActivity extends AppCompatActivity
    implements NavigationView.OnNavigationItemSelectedListener {

    private DrawerLayout drawerLayout;
    private DoubleDrawerView doubleDrawerView;
    private NavigationView mainNavigationView, settingsNavigationView;

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

        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        doubleDrawerView = (DoubleDrawerView) findViewById(R.id.double_drawer_view);
        mainNavigationView = (NavigationView) findViewById(R.id.main_navigation_view);
        settingsNavigationView = (NavigationView) findViewById(R.id.settings_navigation_view);

        mainNavigationView.setNavigationItemSelectedListener(this);
        settingsNavigationView.setNavigationItemSelectedListener(this);

        drawerLayout.openDrawer(Gravity.LEFT);
    }

    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_open_settings:
                doubleDrawerView.openInnerDrawer();
                break;

            case R.id.menu_close_settings:
                doubleDrawerView.closeInnerDrawer();
                break;

                // Additional cases as needed
                // This example simply Toasts the title for the extra sample items

            default:
                Toast.makeText(this, item.getTitle(), Toast.LENGTH_SHORT).show();
        }
        return true;
    }
}
like image 171
Mike M. Avatar answered Sep 30 '22 13:09

Mike M.