滑动菜单

介绍滑动菜单的用法

预备:

  • support v4包,继承自ViewGroup

示例:

样式一:

  • 示例布局
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SlidingPaneLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/SlidingPane"
android:layout_width="match_parent"
android:layout_height="match"
android:background="#D32F2F">

<LinearLayout
android:id="@+id/ll_menu"
android:gravity="center"
android:layout_width="200dp"
android:background="#d32f2f"
android:layout_height="match_parent">

<TextView
android:text="Menu"
android:textSize="25sp"
android:textColor="#ffffff"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

<LinearLayout
android:id="@+id/ll_main"
android:background="#ffffff"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
</LinearLayout>

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

SlidingPaneLayout 一些主要的方法:

  • setParallaxDistance(int parallaxBy)设置滑动视差
  • setCoveredFadeColor(int color)导航菜单视图的滑动颜色渐变
  • setSliderFadeColor(int color)主视图的滑动颜色渐变
  • setPanelSlideListener(SlidingPanelLayou.PanelSlideListener listener)滑动监听
  • openPanel()打开导航菜单
  • closePanel()关闭导航菜单
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class SlidingPanelLayoutActivity extends AppCompatActivity {

private SlidingPaneLayout mSlidingPane;
private LinearLayout ll_menu,ll_main;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
mSlidingPane=(SlidingPaneLayout)findViewById(R.id.SlidingPane);
ll_main=(LinearLayout) findViewById(R.id.ll_main);
ll_menu=(LinearLayout) findViewById(R.id.ll_menu);
setSupportActionBar((Toolbar)findViewById(R.id.toolbar));

//设置滑动视差 可选
mSlidingPane.setParallaxDistance(200);
//菜单滑动的颜色渐变设置 可选
// mSlidingPane.setCoveredFadeColor(getResources().getColor(R.color.colorAccent));
//主视图滑动的颜色渐变设置 可选
mSlidingPane.setSliderFadeColor(0);
//滑动监听 可选
mSlidingPane.setPanelSlideListener(new SlidingPaneLayout.PanelSlideListener(){
/**
* Called when a sliding pane's position changes.
*
* @param panel The child view that was moved
* @param slideOffset The new offset of this sliding pane within its range, from 0-1
*/
@Override
public void onPanelSlide(View panel, float slideOffset) {
Log.d("mylog", "slide---"+slideOffset);
//slideOffset这个参数是跟随滑动0-1变化的
//通过这个竖直变化我们可以做出一些不一样的滑动效果
// ll_menu.setScaleY(slideOffset/2+0.5F);
// ll_menu.setScaleX(slideOffset/2+0.5F);
// ll_main.setScaleY(1-slideOffset/5);
}

/**
* Called when a sliding pane becomes slid completely open. The pane may or may not
* be interactive at this point depending on how much of the pane is visible.
*
* @param panel The child view that was slid to an open position, revealing other panes
*/
@Override
public void onPanelOpened(View panel) {
Log.d("mylog","slide---open");

}

/**
* Called when a sliding pane becomes slid completely closed. The pane is now guaranteed
* to be interactive. It may now obscure other views in the layout.
*
* @param panel The child view that was slid to a closed position
*/
@Override
public void onPanelClosed(View panel) {
Log.d("mylog","slide---close");
}
});
}
}
  • 这样就做出了互动导航的效果
  • 注意:在滑动监听中的这个方法里,根据slideOffset参数0~1的变化可以去改变视图大小就会做出更多种类的效果,这里我们设置滑动过程中改变主视图的大小,代码如下:
1
2
3
4
5
6
7
public void onPanelSlide(View panel, float slideOffset){
//slideOffset这个参数是跟随滑动0~1变化的
//通过这个数值变化我们可以做出一些不一样的滑动效果
ll_menu.setScaleY(slideOffset/2+0.5F);
ll_menu.setScaleX(slideOffset.2+0.5F);
ll_main.setScaleY(1-slideOffset/5);
}

样式二:

  • 快速实现这个效果需要利用V4包的DrawerLayout这个布局容器,可见V4包下面有多少好东西,另外其实SlidingPaneLayoutDrawerLayout都是利用V4的ViewDragHelper去实现的,这是一个帮助类,这里就不多介绍了,对它感兴趣的可以深入了解下。
  • 示例布局:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar2"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>

<android.support.v4.widget.DrawerLayout
android:id="@+id/dl_left"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:background="#ffffff"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>

<!--drawer layout-->
<LinearLayout
android:layout_width="200dp"
android:layout_height="match_parent"
android:background="#d32f2f"
android:layout_gravity="start">

<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Menu"
android:textSize="25sp"
android:gravity="center"
android:textColor="#ffffff"/>

</LinearLayout>

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

</LinearLayout>
  • 需要注意的是主视图的布局代码要放在侧滑菜单布局的前面,侧滑菜单布局的代码中android:layout_gravity="start"从左侧滑动,反之end右侧滑动

DrawerLayout的一些主要方法:

  • addDrawerListener(DrawerLayout.DrawerListener listener)添加滑动监听
  • openDrawer(int gravity)开启导航菜单参数:GravityCompat.START GravityCompat.END要跟XML设置相同
  • closeDrawer(int gravity)关闭导航菜单
  • isDrawerOpen(int drawerGravity)菜单是否开启
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class DrawerLayoutActivity extends AppCompatActivity {

private DrawerLayout drawerLayout;
private Toolbar toolbar;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
setSupportActionBar(toolbar = (Toolbar) findViewById(R.id.toolbar2));
drawerLayout = (DrawerLayout)findViewById(R.id.dl_left);
//ActionBarDrawerToggle是DrawerLayout.DrawerListener的实现
//可以方便的将drawlayout和actionbar结合起来
ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this,drawerLayout, toolbar, R.string.open, R.string.close){
/**
* {@link DrawerLayout.DrawerListener} callback method. If you do not use your
* ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call
* through to this method from your own listener object.
*
* @param drawerView Drawer view that is now open
*/
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}

/**
* {@link DrawerLayout.DrawerListener} callback method. If you do not use your
* ActionBarDrawerToggle instance directly as your DrawerLayout's listener, you should call
* through to this method from your own listener object.
*
* @param drawerView Drawer view that is now closed
*/
@Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
}
};
actionBarDrawerToggle.syncState();
drawerLayout.addDrawerListener(actionBarDrawerToggle);
}
}
  • DrawerLayoutActionBarDrawerToggle配合快速就可以快速构建出具有动画交互的滑动导航菜单效果,是不是很简单。

当下的设计标准

  • 接下来总结“当下”如何按照Android的设计标准去滑动导航菜单,我为什么说的“当下”呢?因为这个设计标准是会变的。
    • 滑动导航菜单需要在Actionbar(Toolbar)下面,这在Android 4.X时代是比较常见的设计,也是当时Android Design标准设计。
      ###实现步骤:
  • 因为NavigationView在Design库中,需要添加依赖:compile 'com.android.support:design:24.0.0'
  • 在DrawLayout 中添加 NavigationView:
  • 布局:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<android.support.v4.widget.DrawerLayout
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:id="@+id/drawerlayout"
android:fitsSystemWindows="true">
<LinearLayout
android:id="@+id/ll_main"
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="?attr/actionBarSize"
android:background="@color/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>

</LinearLayout>

<android.support.design.widget.NavigationView
android:id="@+id/navigationView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/nv_header"
app:menu="@menu/main_drawer"/>

</android.support.v4.widget.DrawerLayout>
  • 因为属于DrawLayout的导航菜单布局,所以NavigationView要加上android:layout_gravity="start"代表从左面滑动,反之是"end"。
  • 其中app:headerLayout="@layout/nv_header"需要传入一个导航菜单的头部布局,它的作用如图绿框部分。。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//头部布局代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="180dp"
android:background="@drawable/background_material"
android:gravity="bottom"
android:padding="16dp">

<LinearLayout
android:layout_marginTop="8dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_vertical">

<ImageView
android:id="@+id/profile_image"
android:layout_width="76dp"
android:layout_height="76dp"
android:background="@drawable/z"/>

</LinearLayout>

<TextView
android:text="xlucifer"
android:textSize="14sp"
android:textColor="#fff"
android:textStyle="bold"
android:paddingBottom="4dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1234567890"
android:textSize="14sp"
android:textColor="#fff"/>

</LinearLayout>
  • app:menu="@menu/main_drawer"用于设置导航菜单中的菜单部分。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group>
<item android:id="@+id/navigation_item1"
android:checkable="true"
android:title="First"
android:icon="@mipmap/ic_launcher"/>
<item android:id="@+id/navigation_item2"
android:checkable="true"
android:title="Second"
android:icon="@mipmap/ic_launcher"/>
<item android:id="@+id/navigation_item3"
android:checkable="true"
android:title="Third"
android:icon="@mipmap/ic_launcher"/>
<item android:id="@+id/navigation_item4"
android:checkable="true"
android:title="Fourth"
android:icon="@mipmap/ic_launcher"/>

<item android:id="@+id/navigation_sub"
android:title="其他">
<menu>
<item android:id="@+id/navigation_sub_item1"
android:checkable="true"
android:title="Fifth"
android:icon="@mipmap/ic_launcher"/>
<item android:id="@+id/navigation_sub_item2"
android:checkable="true"
android:title="Sixth"
android:icon="@mipmap/ic_launcher"/>
<item android:id="@+id/navigation_sub_item3"
android:checkable="true"
android:title="Seventh"
android:icon="@mipmap/ic_launcher"/>
</menu>
</item>
</group>
</menu>
  • 最后是java中代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class NavigationViewActivity extends AppCompatActivity {
private DrawerLayout drawerLayout;
private Toolbar toolbar;
private NavigationView navigationView;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drawlayout_activity);
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT){
//透明状态栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
setSupportActionBar(toolbar=(Toolbar)findViewById(R.id.toolbar));
drawerLayout=(DrawerLayout)findViewById(R.id.drawerlayout);
navigationView=(NavigationView)findViewById(R.id.navigationView);

ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open, R.string.close);
actionBarDrawerToggle.syncState();
drawerLayout.addDrawerListener(actionBarDrawerToggle);

//navigationView menu点击监听
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener(){

@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
selectDrawerItem(menuItem);
return true;
}
});
}

private void selectDrawerItem(MenuItem menuItem) {
switch (menuItem.getItemId()){
//...
default:
Toast.makeText(NavigationViewActivity.this, "menu click", Toast.LENGTH_SHORT).show();
break;
}
menuItem.setChecked(true);
drawerLayout.closeDrawers();
}
}
  • 其中下面代码和布局代码中的android:fitsSystemWindows="true"起到一个半透明状态栏的作用,半透明状态栏效果有各种实现方式,google也没能给一个好的实现方式,后续可能会考虑写一个全面的了解透明状态效果的文章
1
2
3
4
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT){
//透明状态栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}