Two Realizations of Side Slide Menu
- Drawer Layout is more flexible.
- Using Drawer Layout + Navigation View, this is Google's standardization of Material Design.
Using Drawer Layout to realize sideslip
First, we need a layout:
<?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="match_parent" android:orientation="vertical"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#D197F2" app:title="Title" app:titleTextColor="#fff"/> <android.support.v4.widget.DrawerLayout android:id="@+id/drawer" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="content"/> </LinearLayout> <LinearLayout android:layout_width="200dp" android:layout_height="match_parent" android:layout_gravity="start" android:background="@android:color/holo_blue_light" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Side Slide Menu 1"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Side Slide Menu 2"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Side Slide Menu 3"/> </LinearLayout> </android.support.v4.widget.DrawerLayout> </LinearLayout>
The layout side-slip menu includes the menu section and the content section, wrapped in Drawer Layout. Among them, the root layout of the menu section needs to add android:layout_gravity="start", if it is right-sliding, it can be changed to end. In this way, a basic side slip effect can be achieved.
DrawerLayout is actually implemented through ViewDragHelper. The relevant code of DrawerLayout constructor is as follows:
public DrawerLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mLeftCallback = new ViewDragCallback(Gravity.LEFT); mRightCallback = new ViewDragCallback(Gravity.RIGHT); mLeftDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mLeftCallback); mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT); mLeftDragger.setMinVelocity(minVel); mLeftCallback.setDragger(mLeftDragger); }
Using Drawer Layout's monitoring to achieve some results
For example, when we can slide sideways, the button in the upper left corner of the Toolbar changes in real time. We can add a monitor to ActionBarDrawer Toggle:
toolbar = (Toolbar) findViewById(R.id.toolbar); drawer = (DrawerLayout) findViewById(R.id.drawer); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.drawer_open, R.string.drawer_close); toggle.syncState(); drawer.addDrawerListener(toggle);
Now let's analyze the implementation principle:
Among them, ActionBarDrawerToggle implements DrawerLayout.DrawerListener. And constantly refresh the top left corner of the Drawerable during the sliding process:
The implementation of setPosition is as follows:@Override public void onDrawerSlide(View drawerView, float slideOffset) { setPosition(Math.min(1f, Math.max(0, slideOffset))); }
private void setPosition(float position) { if (position == 1f) { mSlider.setVerticalMirror(true); } else if (position == 0f) { mSlider.setVerticalMirror(false); } mSlider.setProgress(position); }
In fact, the process of sliding is constantly changing the rogress of mSlider (a custom Drawerable object), thus constantly refreshing the state.
Therefore, we can do some custom effects, such as zooming and panning when sliding:
drawer.addDrawerListener(new DrawerLayout.DrawerListener() { @Override public void onDrawerStateChanged(int newState) { // Change of state } @Override public void onDrawerSlide(View drawerView, float slideOffset) { // Continuously callback slideOffset: 0~1 during the sliding process View content = drawer.getChildAt(0); float scale = 1 - slideOffset;//1~0 float leftScale = (float) (1 - 0.3 * scale); float rightScale = (float) (0.7f + 0.3 * scale);//0.7~1 drawerView.setScaleX(leftScale);//1~0.7 drawerView.setScaleY(leftScale);//1~0.7 content.setScaleX(rightScale); content.setScaleY(rightScale); content.setTranslationX(drawerView.getMeasuredWidth() * (1 - scale));//0~width } @Override public void onDrawerOpened(View drawerView) { // open } @Override public void onDrawerClosed(View drawerView) { // Close } });
Using Drawer Layout+Navigation View to Realize Side Slip
Similarly, we need a layout. Similarly, we need to use Drawer Layout to wrap content and menus, where the menu is a Navigation View, which can specify the header and the menu section, and provide some settings for the properties. (As you can see, the flexibility of using Navigation View is poor. If the project uses this template directly, it can be used directly. Otherwise, we still use the general way to achieve it.)
<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" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Content section --> <FrameLayout android:id="@+id/fl" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <!-- Menu section --> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/navigation_headerlayout" app:menu="@menu/navigation_menu"/> </android.support.v4.widget.DrawerLayout>
Here we designate the head as follows:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical"> <ImageView android:id="@+id/iv_icon" android:layout_width="70dp" android:layout_height="70dp" android:layout_marginTop="20dp" android:src="@drawable/icon_people"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="test" android:textSize="20sp"/> </LinearLayout>
The menu section is as follows (created under the menu folder), where menus can be nested:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/action_gallery" android:icon="@android:drawable/ic_menu_gallery" android:orderInCategory="100" android:title="Album" /> <item android:id="@+id/action_details" android:icon="@android:drawable/ic_menu_info_details" android:orderInCategory="100" android:title="details" /> <item android:id="@+id/action_about" android:icon="@android:drawable/ic_menu_help" android:orderInCategory="100" android:title="about" /> <item android:id="@+id/action_music" android:icon="@android:drawable/ic_menu_more" android:orderInCategory="100" android:title="Music" > <menu> <item android:id="@+id/action_play" android:icon="@android:drawable/ic_media_play" android:title="play"/> <item android:id="@+id/action_pause" android:icon="@android:drawable/ic_media_pause" android:title="Pause"/> </menu> </item> </menu>
So far, you can achieve the sideslip, and finally we add the corresponding click event, and then close the menu:
nav_view = (NavigationView) findViewById(R.id.nav_view); drawer = (DrawerLayout) findViewById(R.id.drawer); nav_view.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { Toast.makeText(NavigationViewActivity.this, item.getTitle(), Toast.LENGTH_SHORT).show(); drawer.closeDrawer(nav_view); return false; } }); nav_view.getHeaderView(0).findViewById(R.id.iv_icon).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(NavigationViewActivity.this, "Click on the head Icon", Toast.LENGTH_SHORT).show(); drawer.closeDrawer(nav_view); } });