Android侧滑菜单实现方案详解
一、SlidingPaneLayout组件
SlidingPaneLayout是Android v4支持库提供的滑动面板控件,配置简单且功能专一。根据官方文档说明,该控件仅支持从左侧滑出菜单。
基本使用方式如下:
<android.support.v4.widget.SlidingPaneLayout
android:id="@+id/slidePanel"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="180dp"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 菜单区域内容 -->
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<!-- 主内容区域 -->
</FrameLayout>
</android.support.v4.widget.SlidingPaneLayout>
SlidingPaneLayout组件要求包含两个直接子视图:首个子视图作为菜单面板,第二个子视图作为内容展示区域。
在Activity中进行事件监听配置:
SlidingPaneLayout slidePanel = (SlidingPaneLayout) findViewById(R.id.slidePanel);
if (slidePanel != null) {
slidePanel.setPanelSlideListener(new SlidingPaneLayout.PanelSlideListener() {
@Override
public void onPanelSlide(View panel, float slideOffset) {
// 滑动过程中的回调处理
}
@Override
public void onPanelOpened(View panel) {
// 面板完全展开时的回调
}
@Override
public void onPanelClosed(View panel) {
// 面板关闭时的回调
}
});
}
二、DrawerLayout抽屉组件
DrawerLayout同样来自v4支持库,能够实现更为灵活的抽屉式侧滑菜单效果。
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#cccccc">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="主内容区域"/>
</LinearLayout>
<LinearLayout
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#aaaaaa"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="侧边菜单内容"/>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
重要约束:DrawerLayout支持三个子节点布局,依次为左侧菜单、主内容区域、右侧菜单。其中主内容布局必须位于第一位,且不能包含layout_gravity属性。侧边菜单需要通过android:layout_gravity属性指定对齐方式,"start"表示左侧菜单,"end"表示右侧菜单。
完整集成示例代码:
private DrawerLayout drawerLayout;
private Toolbar toolbar;
private ActionBarDrawerToggle toggle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
// 创建标题栏与抽屉的联动开关
toggle = new ActionBarDrawerToggle(this, drawerLayout,
toolbar, R.string.open, R.string.close);
toggle.syncState();
// 添加系统内置监听器
drawerLayout.addDrawerListener(toggle);
// 添加自定义监听器处理业务逻辑
drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
Log.d("Drawer", "滑动中: " + slideOffset);
}
@Override
public void onDrawerOpened(View drawerView) {
Log.d("Drawer", "已打开");
}
@Override
public void onDrawerClosed(View drawerView) {
Log.d("Drawer", "已关闭");
}
@Override
public void onDrawerStateChanged(int newState) {
Log.d("Drawer", "状态改变: " + newState);
}
});
}
三、NavigationView导航视图
NavigationView是Material Design设计规范中的组件,专门用于简化DrawerLayout中菜单项的配置工作。当前主流应用普遍采用此方案实现侧滑菜单。
早期DrawerLayout的标准用法需要手动创建ListView并编写适配器,代码较为繁琐:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/frame_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="@+id/drawer_list"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#9999cc"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp" />
</android.support.v4.widget.DrawerLayout>
使用NavigationView后的布局结构:
<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">
<include layout="@layout/layout_content" />
<android.support.design.widget.NavigationView
android:id="@+id/navigationView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="left"
android:fitsSystemWindows="true"
app:headerLayout="@layout/layout_header"
app:menu="@layout/layout_menu" />
</android.support.v4.widget.DrawerLayout>
NavigationView通过android:layout_gravity属性控制抽屉菜单的滑出方向,"left"或"start"从左侧滑出,"right"或"end"从右侧滑出。该组件有两个核心配置属性:
- app:headerLayout: 指定顶部头部布局文件
- app:menu: 指定菜单资源文件
代码中的交互处理:
private void setupNavigationView() {
NavigationView navigationView = (NavigationView) findViewById(R.id.navigationView);
final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem item) {
item.setChecked(true);
drawer.closeDrawers();
return true;
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (item.getItemId() == android.R.id.home) {
drawer.openDrawer(GravityCompat.START);
return true;
}
return super.onOptionsItemSelected(item);
}
关于菜单项的视觉样式定制,NavigationView支持以下几种配置方式:
- 背景设置: setItemBackgroundResource(int) 或 app:itemBackground属性
- 图标着色: setItemIconTintList(ColorStateList) 或 app:itemIconTint属性
- 文字颜色: setItemTextColor(ColorStateList) 或 app:itemTextColor属性
主题颜色继承机制:正常状态下的文字和图标颜色继承自android:textColorPrimary属性,选中状态则使用colorPrimary属性定义的颜色。