在我们开始之前,让我们先做一些资源文件上的准备.
首先添加app的menu中需要用到的所有icon:
每一个都长得像概念视频中的样子,但其实他们都是从谷歌的Material 设计图标 中获取的。
我们的菜单是基于ListView实现的,因此我们需要为list的item准备好布局。下面是三种不同的布局:
带有用户头像与昵称的头部
菜单按钮
分割线(用在菜单按钮之间)
<br /><?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#dddddd" /> </FrameLayout>
这里是
带有所有新源码的一个完整提交现在我们来为全局菜单准备布局。总的来说他就是个简单的ListView,我们本可以把它放在xml中,但是考虑到我们希望将这个view注入(嵌入)到更多的Activity中,还是用纯代码更好些。
这个View的需求很简单 – 只要显示菜单项与用户的简单介绍就可以了。因此实现并不是太复杂:
GlobalMenuView.java
public class GlobalMenuView extends ListView implements View.OnClickListener { private OnHeaderClickListener onHeaderClickListener; private GlobalMenuAdapter globalMenuAdapter; private ImageView ivUserProfilePhoto; private int avatarSize; private String profilePhoto; public GlobalMenuView(Context context) { super(context); init(); } private void init() { setChoiceMode(CHOICE_MODE_SINGLE); setDivider(getResources().getDrawable(android.R.color.transparent)); setDividerHeight(0); setBackgroundColor(Color.WHITE); setupHeader(); setupAdapter(); } private void setupAdapter() { globalMenuAdapter = new GlobalMenuAdapter(getContext()); setAdapter(globalMenuAdapter); } private void setupHeader() { this.avatarSize = getResources().getDimensionPixelSize(R.dimen.global_menu_avatar_size); this.profilePhoto = getResources().getString(R.string.user_profile_photo); setHeaderDividersEnabled(true); View vHeader = LayoutInflater.from(getContext()).inflate(R.layout.view_global_menu_header, null); ivUserProfilePhoto = (ImageView) vHeader.findViewById(R.id.ivUserProfilePhoto); Picasso.with(getContext()) .load(profilePhoto) .placeholder(R.drawable.img_circle_placeholder) .resize(avatarSize, avatarSize) .centerCrop() .transform(new CircleTransformation()) .into(ivUserProfilePhoto); addHeaderView(vHeader); vHeader.setOnClickListener(this); } @Override public void onClick(View v) { if (onHeaderClickListener != null) { onHeaderClickListener.onGlobalMenuHeaderClick(v); } } public interface OnHeaderClickListener { public void onGlobalMenuHeaderClick(View v); } public void setOnHeaderClickListener(OnHeaderClickListener onHeaderClickListener) { this.onHeaderClickListener = onHeaderClickListener; } }
正如你看到的,用户介绍的view作为ListView的头部被使用。这就是为什么需要添加一个自定义的监听者来处理onClick。其余的都很简单。
commit
with GlobalMenuView
implementation
¡£是建立Navigation Drawer的时候了,首先准备DrawerLayout的根View布局:
drawer_root.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/drawerLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/vContentFrame" android:layout_width="match_parent" android:layout_height="match_parent" /> <FrameLayout android:id="@+id/vLeftDrawer" android:layout_width="280dp" android:layout_height="match_parent" android:layout_gravity="start" /> </android.support.v4.widget.DrawerLayout>
这个基本的布局包含了自定义的根view(在vContentFrame 元素中)以及左边的drawer(vLeftDrawer 元素)。
现在该来准备将DrawerLayout注入到Activit布局树中的工具了。未来很可能要对DrawerLayoutInstaller做一些改进,但是目前的需求很简单:
1.在不接触xml文件的情况下将DrawerLayout注入到已有的Activity中。
2.可以自定义DrawerLayout的xml根view以及左item的view。
3.一些自定义(左item的宽度,自定义打开/关闭drawer的toggle)
The first point is done with three simple steps:
第一点通过三个简单的步骤完成:
得到Activity的根View(使用activity.findViewById(android.R.id.content)获得)同时将它的唯一子view拿掉
将抽屉布局作为孩子放入到根View中
将从根View中拿掉的子View放到抽屉的content view中
实现:
DrawerLayoutInstaller_drawerinject.javaprivate void addDrawerToActivity(DrawerLayout drawerLayout) { ViewGroup rootView = (ViewGroup) activity.findViewById(android.R.id.content); ViewGroup drawerContentRoot = (ViewGroup) drawerLayout.getChildAt(0); View contentView = rootView.getChildAt(0); rootView.removeView(contentView); drawerContentRoot.addView(contentView, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT )); rootView.addView(drawerLayout, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT )); }
DrawerLayoutInstaller
µÄʵÏÖ
¡£我们终于可以将所有这些东西放在一起了,首先在BaseActivity中我们需要构建我们的GlobalMenuView ,然后将它放在DrawerLayout中。然后将所有东西注入到Activity布局中:
BaseActivity_setupDrawer.java
private void setupDrawer() { GlobalMenuView menuView = new GlobalMenuView(this); menuView.setOnHeaderClickListener(this); drawerLayout = DrawerLayoutInstaller.from(this) .drawerRoot(R.layout.drawer_root) .drawerLeftView(menuView) .drawerLeftWidth(Utils.dpToPx(300)) .withNavigationIconToggler(getToolbar()) .build(); }
最后一件事 – 实现打开ProfileAcitivty的onGlobalMenuHeaderClick()方法:
BaseActivity_globalMenuHeaderClick.java
@Override public void onGlobalMenuHeaderClick(final View v) { drawerLayout.closeDrawer(Gravity.START); new Handler().postDelayed(new Runnable() { @Override public void run() { int[] startingLocation = new int[2]; v.getLocationOnScreen(startingLocation); startingLocation[0] += v.getWidth() / 2; UserProfileActivity.startUserProfileFromLocation(startingLocation, BaseActivity.this); overridePendingTransition(0, 0); } }, 200); }
这里handler将打开动作延迟到DrawerLayout关闭之后。下面是最终的效果
项目的完整代码 : repository
作者: Miroslaw Stanek
译文链接