在实际项目开发中,定制一个菜单,能让用户得到更好的用户体验,诚然菜单的样式各种各样,但是有一种菜单——滑动菜单,是被众多应用广泛使用的。关于这种滑动菜单的实现,我在前面的博文中也介绍了如何自定义去实现,请参考Android自定义控件——侧滑菜单,这篇博文描述的是如何从无到有创建一个侧滑菜单的控件,里面的代码不多,但是处理的逻辑和各种效果比较复杂,如果稍有不慎,这种自定义控件就要BUG不断,难以在项目中使用,而且实现的效果比较单一。
好在有开源力量的存在,在开源世界里,一切常用的实用的东西,都会有大牛帮我们做好了。所以,这种侧滑菜单不难被找到,下面就来介绍一下这个开源的侧滑菜单SlidingMenu。
一、SlidingMenu相关介绍
1,获取SlidingMenu
SlidingMenu在GitHub中可以被找到,下面是GitHub源码的地址,大家可以点进去,下载这个源码。另外,SlidingMenu这个开源组件也是基于另外一个开源组件之上的,这个开源组件是ActionBarSherlock,也需要下载下来。
SlidingMenu项目:https://github.com/jfeinstein10/SlidingMenu
ActionBarSherlock项目:https://github.com/JakeWharton/ActionBarSherlock
PS:关于SlidingMenu的作者Jeremy Feinstein和ActionBarSherlock的作者JakeWharton,都是大牛,前者还是JazzyViewPager的作者,后者更是Android-ViewPagerIndicator、NineOldAndroids、DiskLruCache等等的作者,大家可以注册一下GitHub的账号,选择Follow一下这些大牛,站在巨人的肩膀上进步。
2,导入到项目中
首先解压这个ActionBarSherlock的压缩包,找到actionbarsherlock这个包,这个工程是类库,下面打开eclipse,Import->Android->Android Project from Existing Code,导入这个actionbarsherlock。
然后解压这个SlidingMenu的压缩包,找到library,同样的方法Import->Android->Android Project from Existing Code,导入SlidingMenu的library,然后右键这个library,Properties->Android->add,选择上面导入的actionbarsherlock。
接着新建一个Android项目,在这个项目里引用SlidingMenu,同样,右键工程目录->Properties->Android->add,添加上面导入的SlidingMenu的类库library,这样,这个SlidingMenu就算是导入到了工程中了。注意,当导入这个包的时候有可能会报下面的错误:
引起这个错误的原因是ActionBarSherlock和SlidingMenu以及我们的工程里面的android-support-v4.jar这个包版本不一致,解决的办法是,将我们自己工程libs目录下的android-support-v4.jar复制黏贴到ActionBarSherlock和SlidingMenu的类库的libs目录下,选择同意覆盖,这样这个报错就消除了。
3,引用SlidingMenu
1.你可以通过new SlidingMenu(Context context)的方式把你的activity包含在一个slidingmenu里,然后调用SlidingMenu.attachToActivity(Activity activity, SlidingMenu.SLIDING_WINDOW | SlidingMenu.SLIDING_CONTENT)方法。SLIDING_WINDOW会在SlidingMenu的内容部分包含ActionBar,而SLIDING_CONTENT不会。你可以参加示例项目里的AttachExample。
2.你可以让你的activity继承SlidingActivity来在activity级别上嵌入SlidingMenu。
2.1 在你Activity的onCreate()方法里,像平常一样调用setContentView()方法,也要调用setBehindContentView()方法,它和setContentView()方法有同样的语法结构。setBehindContentView()方法会把view放置在SlidingMenu的后面。你也可以使用getSlidingMenu()方法,这样你就可以自定义你链接的slidingMenu了。
2.2 如果你想使用其它的库,例如ActionBarSherlock,你只需要改变SlidingActivity的继承关系,让它继承SherlockActivity就可以了,原来继承的是Activity。这一点尤为重要,若是在Activity中需要引用ActionBar时,必须修改当前Activity继承于SherlockActivity,不然会产生意想不到的错误。
3.你可以在Java代码里用编程来使用SlidingMenu,也可以在xml布局文件里使用。你可以把SlidingMenu当成一种其它的视图类型,并可以把它放在一些非常棒的地方,例如ListView的行里。
4,相关API介绍
1,下面是SlidingMenu在GitHub主页中的介绍,翻译过来大致的意思如下:
Simple Example - 简单示例
01.
public
class
SlidingExample
extends
Activity {
02.
03.
@Override
04.
public
void
onCreate(Bundle savedInstanceState) {
05.
super
.onCreate(savedInstanceState);
06.
setTitle(R.string.attach);
07.
// set the content view
08.
setContentView(R.layout.content);
09.
// configure the SlidingMenu
10.
SlidingMenu menu =
new
SlidingMenu(
this
);
11.
menu.setMode(SlidingMenu.LEFT);
12.
menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
13.
menu.setShadowWidthRes(R.dimen.shadow_width);
14.
menu.setShadowDrawable(R.drawable.shadow);
15.
menu.setBehindOffsetRes(R.dimen.slidingmenu_offset);
16.
menu.setFadeDegree(
0
.35f);
17.
menu.attachToActivity(
this
, SlidingMenu.SLIDING_CONTENT);
18.
menu.setMenu(R.layout.menu);
19.
}
20.
21.
}
XML Usage - xml用法
如果你决定要把SlidingMenu当作一个view,那你可以在xml文件里定义它:
01.
<com.jeremyfeinstein.slidingmenu.lib.SlidingMenu
02.
xmlns:sliding=
"http://schemas.android.com/apk/res-auto"
03.
android:id=
"@+id/slidingmenulayout"
04.
android:layout_width=
"fill_parent"
05.
android:layout_height=
"fill_parent"
06.
sliding:viewAbove=
"@layout/YOUR_ABOVE_VIEW"
07.
sliding:viewBehind=
"@layout/YOUR_BEHIND_BEHIND"
08.
sliding:touchModeAbove=
"margin|fullscreen"
09.
sliding:behindOffset=
"@dimen/YOUR_OFFSET"
10.
sliding:behindWidth=
"@dimen/YOUR_WIDTH"
11.
sliding:behindScrollScale=
"@dimen/YOUR_SCALE"
12.
sliding:shadowDrawable=
"@drawable/YOUR_SHADOW"
13.
sliding:shadowWidth=
"@dimen/YOUR_SHADOW_WIDTH"
14.
sliding:fadeEnabled=
"true|false"
15.
sliding:fadeDegree=
"float"
16.
sliding:selectorEnabled=
"true|false"
17.
sliding:selectorDrawable=
"@drawable/YOUR_SELECTOR"
/>
注意:你不能既使用behindOffset,又使用behindWidth。如果你这样做,程序会抛出异常。
viewAbove : 你想在SlidingMenu上面使用的布局的引用
viewBehind :你想在SlidingMenu下面使用的布局的引用
touchModeAbove :一个enum,当上面的视图显示时,它指定了屏幕的哪部分是可触摸的。margin意味着只有左边缘。fullscreen意味着整个屏幕。默认是margin。
behindOffset :当后面的视图显示时,你想让它上面的view显示的像素尺寸。默认是0。
behindWidth : 后面视图宽度的尺寸。默认是屏幕的宽度(相当于behindOffset=0)。
behindScrollScale :一个浮点值,代表了上面view滚动与下面view滚动的关系。如果被设置为0.5f,上面的view每滚动2px,后面的view滚动1px。如果被设置为1.0f,上面的view每滚动1px,后面的view也滚动1px。如果被设置为0.0f,后面的view不会滚动,也就是说它是静态的。这是一个有趣的东东。默认是0.25f。
shadowDrable :指向上面视图和后面视图落差阴影的drawable的引用。默认没有阴影。
shadowWidth :代表着阴影drawable宽度的尺寸。默认为0。
shadowEnable :当SlidingMenu以非fade模式打开,在关闭时是否以fade模式关闭。
fadeDegree :一个浮点值,代表着fade的“数量”。1.0f意味着当SlidingMenu关闭时,fade会一直存在。0.0f意味着不会有fade。
selectorEnable :一个布尔值,标识了在上面view的左边是否绘制一个选择项,用于展示后面view被选择的元素。
selectorDrawable : 用于选择项drawable的引用。注意:为了使得选择项被画出来,在被选择的view上,你必须调用SlidingMenu.setSelectView(View v)方法。在ListView上,列表项极有可能不工作,因为Android会回收它们。
Caveats - 附加说明
你的布局必须基于viewgroup,不幸的是,这种做法违背了<merge>的最优化。
2,SlidingMenu类的相关方法:
menu.setMode(SlidingMenu.LEFT); //设置左滑菜单
menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN); //设置滑动的屏幕范围,该设置为全屏区域都可以滑动
menu.setShadowDrawable(R.drawable.shadow); //设置阴影图片
menu.setShadowWidthRes(R.dimen.shadow_width); //设置阴影图片的宽度
menu.setBehindOffsetRes(R.dimen.slidingmenu_offset); //SlidingMenu划出时主页面显示的剩余宽度
menu.setBehindWidth(400); //设置SlidingMenu菜单的宽度
menu.setFadeDegree(0.35f); //SlidingMenu滑动时的渐变程度
menu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT); //使SlidingMenu附加在Activity上
menu.setMenu(R.layout.menu_layout); //设置menu的布局文件
menu.toggle(); //动态判断自动关闭或开启SlidingMenu
menu.showMenu(); //显示SlidingMenu
menu.showContent(); //显示内容
menu.setOnOpenListener(onOpenListener); //监听slidingmenu打开
关于关闭menu有两个监听,简单的来说,对于menu close事件,一个是when,一个是after
menu.OnClosedListener(OnClosedListener); //监听slidingmenu关闭时事件
menu.OnClosedListener(OnClosedListener); //监听slidingmenu关闭后事件
左右都可以划出SlidingMenu菜单只需要设置
menu.setMode(SlidingMenu.LEFT_RIGHT); //属性,然后设置右侧菜单的布局文件
menu.setSecondaryShadowDrawable(R.drawable.shadowright); //右侧菜单的阴影图片
================================================华丽丽的分割线========================================================
二、在项目中引用SlidingMenu
1,创建项目,导入library
首先来看看效果图吧,上图:
可以看到效果了,没错,这个Demo用的是SIidingMenu的左右都可以滑出的效果,是不是觉得还可以啊?下面,我们一步步的来,去完成这个简单的SlidingMemuDemo的工程,这个工程非常简单,但是只要实现了这个Demo之后,以后做项目的时候,可以在这个Demo上面扩展,添加不同的界面UI罢了。
首先,按照上面介绍的步骤,先将下载好的SlidingMenu包解压,找到library,在Eclipse上Import这个library。然后新建这个SlidingMenuDemo,右键选择Properties->Android->Add,添加这个library到工程下。注意:我们在这个工程里面将不会涉及使用ActionBar,所以不需要导入ActionBarSherlock的类库了。
2,菜单的布局XML
接下来,我们先定义好左右菜单的UI,由于这是一个Demo,所以我这个UI做的比较简单,就是写死的一个线性布局,而且左右菜单的布局都是一样的,就偷懒不想写过多的代码,既然只是一个Demo,那大家就不要把美观放在第一位了,着重关注这个功能实现就好了。因为左右菜单的布局都是一样的,所以在这里只贴出左边菜单的布局的XML,以供参考。在实际开发中,菜单可以多种多样的,可以放ListView、GridView等等,根据具体需要来定夺。
01.
<?xml version=
"1.0"
encoding=
"utf-8"
?>
02.
<FrameLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
03.
android:id=
"@+id/menu_left_frag"
04.
android:layout_width=
"match_parent"
05.
android:layout_height=
"match_parent"
>
06.
07.
<ScrollView
08.
android:layout_width=
"match_parent"
09.
android:layout_height=
"match_parent"
>
10.
11.
<LinearLayout
12.
android:layout_width=
"match_parent"
13.
android:layout_height=
"match_parent"
14.
android:background=
"@drawable/menu_bg"
15.
android:orientation=
"vertical"
>
16.
17.
<TextView
18.
android:id=
"@+id/tab_news"
19.
style=
"@style/tab_style"
20.
android:drawableLeft=
"@drawable/tab_news"
21.
android:text=
"新闻"
/>
22.
23.
<TextView
24.
android:id=
"@+id/tab_read"
25.
style=
"@style/tab_style"
26.
android:drawableLeft=
"@drawable/tab_read"
27.
android:text=
"订阅"
/>
28.
29.
<TextView
30.
android:id=
"@+id/tab_local"
31.
style=
"@style/tab_style"
32.
android:drawableLeft=
"@drawable/tab_local"
33.
android:text=
"本地"
/>
34.
35.
<TextView
36.
android:id=
"@+id/tab_ties"
37.
style=
"@style/tab_style"
38.
android:drawableLeft=
"@drawable/tab_ties"
39.
android:text=
"跟帖"
/>
40.
41.
<TextView
42.
android:id=
"@+id/tab_pics"
43.
style=
"@style/tab_style"
44.
android:drawableLeft=
"@drawable/tab_pics"
45.
android:text=
"图片"
/>
46.
47.
<TextView
48.
android:id=
"@+id/tab_focus"
49.
style=
"@style/tab_style"
50.
android:drawableLeft=
"@drawable/tab_focus"
51.
android:text=
"话题"
/>
52.
53.
<TextView
54.
android:id=
"@+id/tab_vote"
55.
style=
"@style/tab_style"
56.
android:drawableLeft=
"@drawable/tab_vote"
57.
android:text=
"投票"
/>
58.
59.
<TextView
60.
android:id=
"@+id/tab_ugc"
61.
style=
"@style/tab_style"
62.
android:drawableLeft=
"@drawable/tab_ugc"
63.
android:text=
"聚合阅读"
/>
64.
</LinearLayout>
65.
</ScrollView>
66.
67.
</FrameLayout>
01.
<style name=
"tab_style"
>
02.
<item name=
"android:layout_width"
>fill_parent</item>
03.
<item name=
"android:layout_height"
>wrap_content</item>
04.
<item name=
"android:background"
>
@drawable
/tab_background</item>
05.
<item name=
"android:drawablePadding"
>20dip</item>
06.
<item name=
"android:gravity"
>center_vertical</item>
07.
<item name=
"android:padding"
>10dip</item>
08.
<item name=
"android:textColor"
>
@android
:color/white</item>
09.
<item name=
"android:textSize"
>18dp</item>
10.
<item name=
"android:clickable"
>
true
</item>
11.
</style>
1.
public
class
SlidingFragmentActivity
extends
FragmentActivity
implements
SlidingActivityBase
会发现SlidingFragmentActivity是继承了FragmentActivity,那么就决定着,接下来的UI界面都是使用Fragment来实现的,包括左右菜单,主页UI都是Fragment。先来看看这个左右菜单的实现,比较简单,直接上主要代码:
01.
package
com.example.slidingmenudemo;
02.
03.
import
com.example.slidingmenudemo.fragment.BaseFragment;
04.
import
com.example.slidingmenudemo.fragment.FocusFragment;
05.
import
com.example.slidingmenudemo.fragment.LocalFragment;
06.
import
com.example.slidingmenudemo.fragment.PicsFragment;
07.
import
com.example.slidingmenudemo.fragment.ReadFragment;
08.
import
com.example.slidingmenudemo.fragment.TiesFragment;
09.
import
com.example.slidingmenudemo.fragment.UgcFragment;
10.
import
com.example.slidingmenudemo.fragment.VoteFragment;
11.
12.
import
android.os.Bundle;
13.
import
android.support.v4.app.Fragment;
14.
import
android.view.LayoutInflater;
15.
import
android.view.View;
16.
import
android.view.View.OnClickListener;
17.
import
android.view.ViewGroup;
18.
19.
public
class
LeftMenuFragment
extends
Fragment
implements
OnClickListener {
20.
21.
private
MainActivity mAct;
22.
private
View view;
23.
24.
@Override
25.
public
View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
26.
view = inflater.inflate(R.layout.menu_left_frag,
null
);
27.
mAct = (MainActivity) getActivity();
28.
view.findViewById(R.id.tab_news).setOnClickListener(
this
);
29.
view.findViewById(R.id.tab_read).setOnClickListener(
this
);
30.
view.findViewById(R.id.tab_local).setOnClickListener(
this
);
31.
view.findViewById(R.id.tab_ties).setOnClickListener(
this
);
32.
view.findViewById(R.id.tab_pics).setOnClickListener(
this
);
33.
view.findViewById(R.id.tab_focus).setOnClickListener(
this
);
34.
view.findViewById(R.id.tab_vote).setOnClickListener(
this
);
35.
view.findViewById(R.id.tab_ugc).setOnClickListener(
this
);
36.
return
view;
37.
}
38.
39.
@Override
40.
public
void
onClick(View v) {
41.
BaseFragment fragment =
null
;
42.
switch
(v.getId()) {
43.
case
R.id.tab_news:
44.
fragment =
new
HomeFragment();
45.
break
;
46.
case
R.id.tab_read:
47.
fragment =
new
ReadFragment();
48.
break
;
49.
case
R.id.tab_local:
50.
fragment =
new
LocalFragment();
51.
break
;
52.
case
R.id.tab_ties:
53.
fragment =
new
TiesFragment();
54.
break
;
55.
case
R.id.tab_pics:
56.
fragment =
new
PicsFragment();
57.
break
;
58.
case
R.id.tab_focus:
59.
fragment =
new
FocusFragment();
60.
break
;
61.
case
R.id.tab_vote:
62.
fragment =
new
VoteFragment();
63.
break
;
64.
case
R.id.tab_ugc:
65.
fragment =
new
UgcFragment();
66.
break
;
67.
default
:
68.
break
;
69.
}
70.
mAct.switchContent(fragment);
71.
fragment =
null
;
72.
}
73.
74.
}
3,内容Fragment的创建
由于右边菜单的主要代码跟左边菜单的代码很相似,限于篇幅,这里就不贴了,有兴趣的请点击下面的源码链接,下载源码。看源码里面可以发现,当点击菜单上某一个标签时,要将标签代表的内容放到主页上去显示,可以看出这个所谓的“内容”都是一个个的Fragment实现的,要让这些Fragment在FragmentActivity上不停的切换来达到主页内容变化的效果,下面是内容的代码段,很简单,只贴出一段了,不同的内容页不同的布局,在项目按照需求定夺,我这里是简单的处理。
1,Fragment布局XML
01.
<?xml version=
"1.0"
encoding=
"utf-8"
?>
02.
<RelativeLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
03.
android:layout_width=
"match_parent"
04.
android:layout_height=
"match_parent"
>
05.
06.
<include layout=
"@layout/frag_title"
/>
07.
08.
<TextView
09.
android:layout_width=
"wrap_content"
10.
android:layout_height=
"wrap_content"
11.
android:layout_centerInParent=
"true"
12.
android:text=
"这是网易话题频道"
13.
android:textColor=
"#FFFF0000"
14.
android:textSize=
"22dp"
/>
15.
16.
</RelativeLayout>
01.
<?xml version=
"1.0"
encoding=
"utf-8"
?>
02.
<RelativeLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
03.
android:id=
"@+id/rl_maincenter_title"
04.
android:layout_width=
"match_parent"
05.
android:layout_height=
"50dp"
06.
android:background=
"@drawable/top_bar_bg"
>
07.
08.
<ImageButton
09.
android:id=
"@+id/ib_menu_left"
10.
android:layout_width=
"wrap_content"
11.
android:layout_height=
"wrap_content"
12.
android:layout_centerVertical=
"true"
13.
android:layout_marginLeft=
"15dp"
14.
android:background=
"@drawable/left_menu_button"
/>
15.
16.
<TextView
17.
android:id=
"@+id/tv_load_course"
18.
android:layout_width=
"wrap_content"
19.
android:layout_height=
"wrap_content"
20.
android:layout_centerInParent=
"true"
21.
android:gravity=
"center"
22.
android:text=
"网易新闻"
23.
android:textColor=
"@android:color/white"
24.
android:textSize=
"18dp"
/>
25.
26.
<ImageButton
27.
android:id=
"@+id/ib_menu_right"
28.
android:layout_width=
"wrap_content"
29.
android:layout_height=
"wrap_content"
30.
android:layout_alignParentRight=
"true"
31.
android:layout_centerVertical=
"true"
32.
android:layout_marginRight=
"15dp"
33.
android:background=
"@drawable/right_menu_button"
/>
34.
35.
</RelativeLayout>
01.
package
com.example.slidingmenudemo.fragment;
02.
03.
import
com.example.slidingmenudemo.MainActivity;
04.
import
com.example.slidingmenudemo.R;
05.
import
com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;
06.
07.
import
android.app.Activity;
08.
import
android.content.Context;
09.
import
android.os.Bundle;
10.
import
android.support.v4.app.Fragment;
11.
import
android.view.LayoutInflater;
12.
import
android.view.View;
13.
import
android.view.ViewGroup;
14.
import
android.view.View.OnClickListener;
15.
import
android.widget.ImageButton;
16.
17.
public
abstract
class
BaseFragment
extends
Fragment
implements
OnClickListener {
18.
protected
Context ct;
19.
/** SlidingMenu对象 */
20.
protected
SlidingMenu sm;
21.
public
View rootView;
22.
protected
Activity MenuChangeHome;
23.
/** 左菜单按钮 */
24.
private
ImageButton leftMenuBtn;
25.
/** 右菜单按钮 */
26.
private
ImageButton rightMenuBtn;
27.
28.
@Override
29.
public
void
onActivityCreated(Bundle savedInstanceState) {
30.
31.
super
.onActivityCreated(savedInstanceState);
32.
sm = ((MainActivity) getActivity()).getSlidingMenu();
33.
initData(savedInstanceState);
34.
}
35.
36.
@Override
37.
public
void
onCreate(Bundle savedInstanceState) {
38.
super
.onCreate(savedInstanceState);
39.
ct = getActivity();
40.
}
41.
42.
@Override
43.
public
View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
44.
rootView = initView(inflater);
45.
leftMenuBtn = (ImageButton) rootView.findViewById(R.id.ib_menu_left);
46.
rightMenuBtn = (ImageButton) rootView.findViewById(R.id.ib_menu_right);
47.
leftMenuBtn.setOnClickListener(
this
);
48.
rightMenuBtn.setOnClickListener(
this
);
49.
setListener();
50.
return
rootView;
51.
}
52.
53.
public
View getRootView() {
54.
return
rootView;
55.
}
56.
57.
@Override
58.
public
void
onClick(View v) {
59.
// TODO Auto-generated method stub
60.
switch
(v.getId()) {
61.
case
R.id.ib_menu_left:
// 点击左边的按钮,左菜单收放
62.
sm.toggle();
63.
break
;
64.
case
R.id.ib_menu_right:
// 点击右边按钮,右菜单缩放
65.
sm.showSecondaryMenu();
66.
break
;
67.
default
:
68.
break
;
69.
}
70.
}
71.
72.
/**
73.
* 初始化UI
74.
*
75.
* @param inflater
76.
* @return
77.
*/
78.
protected
abstract
View initView(LayoutInflater inflater);
79.
80.
/**
81.
* 初始化数据
82.
*
83.
* @param savedInstanceState
84.
*/
85.
protected
abstract
void
initData(Bundle savedInstanceState);
86.
87.
/**
88.
* 设置监听
89.
*/
90.
protected
abstract
void
setListener();
91.
92.
}
01.
public
class
FocusFragment
extends
BaseFragment {
02.
03.
@Override
04.
protected
View initView(LayoutInflater inflater) {
05.
// TODO Auto-generated method stub
06.
return
inflater.inflate(R.layout.frag_focus,
null
);
07.
}
08.
09.
@Override
10.
protected
void
initData(Bundle savedInstanceState) {
11.
// TODO Auto-generated method stub
12.
}
13.
14.
@Override
15.
protected
void
setListener() {
16.
// TODO Auto-generated method stub
17.
}
18.
}
4,主要代码,MainActivity
最后,来重点看一下这个MainActivity里面的代码,在这里才是构建一个侧滑菜单效果的主要代码,源代码如下,可以参考注释来看:
001.
package
com.example.slidingmenudemo;
002.
003.
import
com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;
004.
import
com.jeremyfeinstein.slidingmenu.lib.SlidingMenu.CanvasTransformer;
005.
import
com.jeremyfeinstein.slidingmenu.lib.app.SlidingFragmentActivity;
006.
007.
import
android.graphics.Canvas;
008.
import
android.os.Bundle;
009.
import
android.support.v4.app.Fragment;
010.
import
android.view.animation.Interpolator;
011.
012.
public
class
MainActivity
extends
SlidingFragmentActivity {
013.
014.
/** 侧滑菜单 */
015.
private
SlidingMenu sm;
016.
/** 左边菜单 */
017.
private
LeftMenuFragment mLeftMenu;
018.
/** 右边菜单 */
019.
private
RightMenuFragment mRightMenu;
020.
/** 主界面 */
021.
private
HomeFragment mHomeFragment;
022.
/** 动画类 */
023.
private
CanvasTransformer mTransformer;
024.
/** 保存Fragment的状态 */
025.
private
Fragment mContent;
026.
027.
@Override
028.
public
void
onCreate(Bundle savedInstanceState) {
029.
// TODO Auto-generated method stub
030.
super
.onCreate(savedInstanceState);
031.
initAnimation();
032.
sm = getSlidingMenu();
033.
setContentView(R.layout.content_frame);
034.
setBehindContentView(R.layout.menu_left_frag);
035.
sm.setSecondaryMenu(R.layout.menu_right_frag);
036.
if
(savedInstanceState ==
null
) {
037.
mLeftMenu =
new
LeftMenuFragment();
038.
mRightMenu =
new
RightMenuFragment();
039.
mHomeFragment =
new
HomeFragment();
040.
getSupportFragmentManager().beginTransaction().replace(R.id.menu_left_frag, mLeftMenu,
"Left"
).commit();
041.
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, mHomeFragment,
"Home"
).commit();
042.
getSupportFragmentManager().beginTransaction().replace(R.id.menu_right_frag, mRightMenu,
"Right"
).commit();
043.
}
044.
sm.setSecondaryShadowDrawable(R.drawable.rightshadow);
// 设置右边菜单的阴影
045.
sm.setShadowDrawable(R.drawable.shadow);
// 设置阴影图片
046.
sm.setShadowWidthRes(R.dimen.shadow_width);
// 设置阴影图片的宽度
047.
sm.setBehindOffsetRes(R.dimen.slidingmenu_offset);
// 显示主界面的宽度
048.
sm.setFadeDegree(0f);
// SlidingMenu滑动时的渐变程度
049.
sm.setBehindScrollScale(0f);
050.
sm.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
// 设置滑动的屏幕范围,该设置为全屏区域都可以滑动
051.
sm.setMode(SlidingMenu.LEFT_RIGHT);
// 设置菜单同时兼具左右滑动
052.
sm.setBehindCanvasTransformer(mTransformer);
// 设置动画
053.
}
054.
055.
/**
056.
* 初始化菜单滑动的效果动画
057.
*/
058.
private
void
initAnimation() {
059.
mTransformer =
new
CanvasTransformer() {
060.
@Override
061.
public
void
transformCanvas(Canvas canvas,
float
percentOpen) {
062.
canvas.scale(interp.getInterpolation(percentOpen), interp.getInterpolation(percentOpen), canvas.getWidth() /
2
, canvas.getHeight() /
2
);
063.
// canvas.translate(0, canvas.getHeight() * (1 -
064.
// interp.getInterpolation(percentOpen)));
065.
}
066.
067.
};
068.
}
069.
070.
private
static
Interpolator interp =
new
Interpolator() {
071.
@Override
072.
public
float
getInterpolation(
float
t) {
073.
t -=
1
.0f;
074.
return
t * t * t +
1
.0f;
075.
}
076.
};
077.
078.
/**
079.
* 切换到主界面
080.
*
081.
* @param fragment
082.
*/
083.
public
void
switchContent(Fragment fragment) {
084.
mContent = fragment;
085.
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).commit();
086.
getSlidingMenu().showContent();
087.
}
088.
089.
/**
090.
* 保存Fragment的状态
091.
*/
092.
@Override
093.
protected
void
onSaveInstanceState(Bundle outState) {
094.
// TODO Auto-generated method stub
095.
super
.onSaveInstanceState(outState);
096.
getSupportFragmentManager().putFragment(outState,
"Home"
, mContent);
097.
}
098.
099.
}
上面的代码里关于Fragment使用以及Fragment的API不是这篇博文的重点,如果看不明白就先学习一下Fragment。我们关注这个菜单的实现即可,我使用的方式是Activity继承SlidingFragmentActivity,这种方式是很常见的,也很好维护,只要理解Fragment使用即可。诚然,我的这个Demo里没有使用SlidingMenu的依赖库ActionBarSherlock,是因为这个Demo已经自己定义了左右菜单导航按钮,无需使用ActionBar。
5,SlidingMenu的动画
关于代码中的初始化动画,有必要解释一下。这个初始化动画可以不设置,默认就是左右水平方向的平移,这样比较死板,但是SlidingMenu的作者考虑到了我们的担忧,很“t贴心”的为我们写好了实现菜单滑动效果动画的接口,不得不说这外国大牛想的还真细腻。
sm.setBehindCanvasTransformer(mTransformer); // 设置动画
其中mTransformer是SlidingMenu类下的内部接口CanvasTransformer对象,源码如下:
01.
/**
02.
* The Interface CanvasTransformer.
03.
*/
04.
public
interface
CanvasTransformer {
05.
06.
/**
07.
* Transform canvas.
08.
*
09.
* @param canvas the canvas
10.
* @param percentOpen the percent open
11.
*/
12.
public
void
transformCanvas(Canvas canvas,
float
percentOpen);
13.
}
SlidingMemu的缩放动画:
01.
/**
02.
* 初始化菜单滑动的效果动画
03.
*/
04.
private
void
initAnimation() {
05.
mTransformer =
new
CanvasTransformer() {
06.
@Override
07.
public
void
transformCanvas(Canvas canvas,
float
percentOpen) {
08.
canvas.scale(interp.getInterpolation(percentOpen), interp.getInterpolation(percentOpen), canvas.getWidth() /
2
, canvas.getHeight() /
2
);
09.
}
10.
11.
};
12.
}
13.
14.
private
static
Interpolator interp =
new
Interpolator() {
15.
@Override
16.
public
float
getInterpolation(
float
t) {
17.
t -=
1
.0f;
18.
return
t * t * t +
1
.0f;
19.
}
20.
};
SlidingMenu的平移动画:
01.
/**
02.
* 初始化菜单滑动的效果动画
03.
*/
04.
private
void
initAnimation() {
05.
mTransformer =
new
CanvasTransformer() {
06.
@Override
07.
public
void
transformCanvas(Canvas canvas,
float
percentOpen) {
08.
canvas.translate(
0
, canvas.getHeight() * (
1
- interp.getInterpolation(percentOpen)));
09.
}
10.
11.
};
12.
}
13.
14.
private
static
Interpolator interp =
new
Interpolator() {
15.
@Override
16.
public
float
getInterpolation(
float
t) {
17.
t -=
1
.0f;
18.
return
t * t * t +
1
.0f;
19.
}
20.
};
01.
private
void
initAnimation() {
02.
mTransformer =
new
CanvasTransformer() {
03.
@Override
04.
public
void
transformCanvas(Canvas canvas,
float
percentOpen) {
05.
canvas.scale(percentOpen,
1
,
0
,
0
);
06.
}
07.
08.
};
09.
}
6,SlidingMenu的背景
最后一点,需要注意的是,在给SlidingMenu添加了动画效果后,运行时会看见菜单的背景处是一片“白色”或者“透明色”的,这样的用户体验非常的不好,那么怎么解决呢?这个很简单的,第一个考虑到是SlidingMenu本身没有设置背景,所以我们要手动的给SlidingMenu控件设置一下背景,打开SlidingMenu的类库library,在res/layout目录下找到slidingmenumain.xml的文件,打开看见这里就简单的定义了一个SlidingMenu,其它什么都没有,此时我们就可以在这个slidingmenumain.xml的节点下设置一下drawable属性即可。
library/res/layout/slidingmenumain.xml:
1.
<?xml version=
"1.0"
encoding=
"utf-8"
?>
2.
<com.jeremyfeinstein.slidingmenu.lib.SlidingMenu
3.
xmlns:android=
"http://schemas.android.com/apk/res/android"
4.
android:id=
"@+id/slidingmenumain"
5.
android:layout_width=
"fill_parent"
6.
android:layout_height=
"fill_parent"
/>