Android自定义控件 开源组件SlidingMenu的项目集成
在实际项目开发中,定制一个菜单,能让用户得到更好的用户体验,诚然菜单的样式各种各样,但是有一种菜单——滑动菜单,是被众多应用广泛使用的。关于这种滑动菜单的实现,我在前面的博文中也介绍了如何自定义去实现,请参考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 - 简单示例
public class SlidingExample extends Activity { @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle(R.string.attach);
// set the content view
setContentView(R.layout.content);
// configure the SlidingMenu
SlidingMenu menu = new SlidingMenu(this);
menu.setMode(SlidingMenu.LEFT);
menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
menu.setShadowWidthRes(R.dimen.shadow_width);
menu.setShadowDrawable(R.drawable.shadow);
menu.setBehindOffsetRes(R.dimen.slidingmenu_offset);
menu.setFadeDegree(0.35f);
menu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);
menu.setMenu(R.layout.menu);
} }
XML Usage - xml用法
如果你决定要把SlidingMenu当作一个view,那你可以在xml文件里定义它:
<com.jeremyfeinstein.slidingmenu.lib.SlidingMenu
xmlns:sliding="http://schemas.android.com/apk/res-auto"
android:id="@+id/slidingmenulayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
sliding:viewAbove="@layout/YOUR_ABOVE_VIEW"
sliding:viewBehind="@layout/YOUR_BEHIND_BEHIND"
sliding:touchModeAbove="margin|fullscreen"
sliding:behindOffset="@dimen/YOUR_OFFSET"
sliding:behindWidth="@dimen/YOUR_WIDTH"
sliding:behindScrollScale="@dimen/YOUR_SCALE"
sliding:shadowDrawable="@drawable/YOUR_SHADOW"
sliding:shadowWidth="@dimen/YOUR_SHADOW_WIDTH"
sliding:fadeEnabled="true|false"
sliding:fadeDegree="float"
sliding:selectorEnabled="true|false"
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等等,根据具体需要来定 夺。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/menu_left_frag"
android:layout_width="match_parent"
android:layout_height="match_parent" > <ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent" > <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/menu_bg"
android:orientation="vertical" > <TextView
android:id="@+id/tab_news"
style="@style/tab_style"
android:drawableLeft="@drawable/tab_news"
android:text="新闻" /> <TextView
android:id="@+id/tab_read"
style="@style/tab_style"
android:drawableLeft="@drawable/tab_read"
android:text="订阅" /> <TextView
android:id="@+id/tab_local"
style="@style/tab_style"
android:drawableLeft="@drawable/tab_local"
android:text="本地" /> <TextView
android:id="@+id/tab_ties"
style="@style/tab_style"
android:drawableLeft="@drawable/tab_ties"
android:text="跟帖" /> <TextView
android:id="@+id/tab_pics"
style="@style/tab_style"
android:drawableLeft="@drawable/tab_pics"
android:text="图片" /> <TextView
android:id="@+id/tab_focus"
style="@style/tab_style"
android:drawableLeft="@drawable/tab_focus"
android:text="话题" /> <TextView
android:id="@+id/tab_vote"
style="@style/tab_style"
android:drawableLeft="@drawable/tab_vote"
android:text="投票" /> <TextView
android:id="@+id/tab_ugc"
style="@style/tab_style"
android:drawableLeft="@drawable/tab_ugc"
android:text="聚合阅读" />
</LinearLayout>
</ScrollView> </FrameLayout>
布局中使用的样式:
<style name="tab_style">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:background">@drawable/tab_background</item>
<item name="android:drawablePadding">20dip</item>
<item name="android:gravity">center_vertical</item>
<item name="android:padding">10dip</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:textSize">18dp</item>
<item name="android:clickable">true</item>
</style>
由于在使用SlidingMenu时,要继承SlidingFragmentActivity,查看SlidingFragmentActivity的继承体系
public class SlidingFragmentActivity extends FragmentActivity implements SlidingActivityBase
会发现SlidingFragmentActivity是继承了FragmentActivity,那么就决定着,接下来的UI界面都是使用Fragment来实现的,包括左右菜单,主页UI都是Fragment。先来看看这个左右菜单的实现,比较简单,直接上主要代码:
package com.example.slidingmenudemo; import com.example.slidingmenudemo.fragment.BaseFragment;
import com.example.slidingmenudemo.fragment.FocusFragment;
import com.example.slidingmenudemo.fragment.LocalFragment;
import com.example.slidingmenudemo.fragment.PicsFragment;
import com.example.slidingmenudemo.fragment.ReadFragment;
import com.example.slidingmenudemo.fragment.TiesFragment;
import com.example.slidingmenudemo.fragment.UgcFragment;
import com.example.slidingmenudemo.fragment.VoteFragment; import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup; public class LeftMenuFragment extends Fragment implements OnClickListener { private MainActivity mAct;
private View view; @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.menu_left_frag, null);
mAct = (MainActivity) getActivity();
view.findViewById(R.id.tab_news).setOnClickListener(this);
view.findViewById(R.id.tab_read).setOnClickListener(this);
view.findViewById(R.id.tab_local).setOnClickListener(this);
view.findViewById(R.id.tab_ties).setOnClickListener(this);
view.findViewById(R.id.tab_pics).setOnClickListener(this);
view.findViewById(R.id.tab_focus).setOnClickListener(this);
view.findViewById(R.id.tab_vote).setOnClickListener(this);
view.findViewById(R.id.tab_ugc).setOnClickListener(this);
return view;
} @Override
public void onClick(View v) {
BaseFragment fragment = null;
switch (v.getId()) {
case R.id.tab_news:
fragment = new HomeFragment();
break;
case R.id.tab_read:
fragment = new ReadFragment();
break;
case R.id.tab_local:
fragment = new LocalFragment();
break;
case R.id.tab_ties:
fragment = new TiesFragment();
break;
case R.id.tab_pics:
fragment = new PicsFragment();
break;
case R.id.tab_focus:
fragment = new FocusFragment();
break;
case R.id.tab_vote:
fragment = new VoteFragment();
break;
case R.id.tab_ugc:
fragment = new UgcFragment();
break;
default:
break;
}
mAct.switchContent(fragment);
fragment = null;
} }
3,内容Fragment的创建
由于右边菜单的主要代码跟左边菜单的代码很相似,限于篇幅,这里就不贴了,有兴趣的请点击下面的源码链接,下载源码。看源码里面可以发现,当点击菜 单上某一个标签时,要将标签代表的内容放到主页上去显示,可以看出这个所谓的“内容”都是一个个的Fragment实现的,要让这些Fragment在 FragmentActivity上不停的切换来达到主页内容变化的效果,下面是内容的代码段,很简单,只贴出一段了,不同的内容页不同的布局,在项目按 照需求定夺,我这里是简单的处理。
1,Fragment布局XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" > <include layout="@layout/frag_title" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="这是网易话题频道"
android:textColor="#FFFF0000"
android:textSize="22dp" /> </RelativeLayout>
2,include的标题XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl_maincenter_title"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/top_bar_bg" > <ImageButton
android:id="@+id/ib_menu_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
android:background="@drawable/left_menu_button" /> <TextView
android:id="@+id/tv_load_course"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:text="网易新闻"
android:textColor="@android:color/white"
android:textSize="18dp" /> <ImageButton
android:id="@+id/ib_menu_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:background="@drawable/right_menu_button" /> </RelativeLayout>
3,Fragment的抽象基类——BaseFragment
package com.example.slidingmenudemo.fragment; import com.example.slidingmenudemo.MainActivity;
import com.example.slidingmenudemo.R;
import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu; import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.ImageButton; public abstract class BaseFragment extends Fragment implements OnClickListener {
protected Context ct;
/** SlidingMenu对象 */
protected SlidingMenu sm;
public View rootView;
protected Activity MenuChangeHome;
/** 左菜单按钮 */
private ImageButton leftMenuBtn;
/** 右菜单按钮 */
private ImageButton rightMenuBtn; @Override
public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState);
sm = ((MainActivity) getActivity()).getSlidingMenu();
initData(savedInstanceState);
} @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ct = getActivity();
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = initView(inflater);
leftMenuBtn = (ImageButton) rootView.findViewById(R.id.ib_menu_left);
rightMenuBtn = (ImageButton) rootView.findViewById(R.id.ib_menu_right);
leftMenuBtn.setOnClickListener(this);
rightMenuBtn.setOnClickListener(this);
setListener();
return rootView;
} public View getRootView() {
return rootView;
} @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.ib_menu_left: // 点击左边的按钮,左菜单收放
sm.toggle();
break;
case R.id.ib_menu_right: // 点击右边按钮,右菜单缩放
sm.showSecondaryMenu();
break;
default:
break;
}
} /**
* 初始化UI
*
* @param inflater
* @return
*/
protected abstract View initView(LayoutInflater inflater); /**
* 初始化数据
*
* @param savedInstanceState
*/
protected abstract void initData(Bundle savedInstanceState); /**
* 设置监听
*/
protected abstract void setListener(); }
4,其中的一个Fragment主要代码,其实里面什么也没有
public class FocusFragment extends BaseFragment { @Override
protected View initView(LayoutInflater inflater) {
// TODO Auto-generated method stub
return inflater.inflate(R.layout.frag_focus, null);
} @Override
protected void initData(Bundle savedInstanceState) {
// TODO Auto-generated method stub
} @Override
protected void setListener() {
// TODO Auto-generated method stub
}
}
4,主要代码,MainActivity
最后,来重点看一下这个MainActivity里面的代码,在这里才是构建一个侧滑菜单效果的主要代码,源代码如下,可以参考注释来看:
package com.example.slidingmenudemo; import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;
import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu.CanvasTransformer;
import com.jeremyfeinstein.slidingmenu.lib.app.SlidingFragmentActivity; import android.graphics.Canvas;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.animation.Interpolator; public class MainActivity extends SlidingFragmentActivity { /** 侧滑菜单 */
private SlidingMenu sm;
/** 左边菜单 */
private LeftMenuFragment mLeftMenu;
/** 右边菜单 */
private RightMenuFragment mRightMenu;
/** 主界面 */
private HomeFragment mHomeFragment;
/** 动画类 */
private CanvasTransformer mTransformer;
/** 保存Fragment的状态 */
private Fragment mContent; @Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
initAnimation();
sm = getSlidingMenu();
setContentView(R.layout.content_frame);
setBehindContentView(R.layout.menu_left_frag);
sm.setSecondaryMenu(R.layout.menu_right_frag);
if (savedInstanceState == null) {
mLeftMenu = new LeftMenuFragment();
mRightMenu = new RightMenuFragment();
mHomeFragment = new HomeFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.menu_left_frag, mLeftMenu, "Left").commit();
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, mHomeFragment, "Home").commit();
getSupportFragmentManager().beginTransaction().replace(R.id.menu_right_frag, mRightMenu, "Right").commit();
}
sm.setSecondaryShadowDrawable(R.drawable.rightshadow); // 设置右边菜单的阴影
sm.setShadowDrawable(R.drawable.shadow); // 设置阴影图片
sm.setShadowWidthRes(R.dimen.shadow_width); // 设置阴影图片的宽度
sm.setBehindOffsetRes(R.dimen.slidingmenu_offset); // 显示主界面的宽度
sm.setFadeDegree(0f); // SlidingMenu滑动时的渐变程度
sm.setBehindScrollScale(0f);
sm.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN); // 设置滑动的屏幕范围,该设置为全屏区域都可以滑动
sm.setMode(SlidingMenu.LEFT_RIGHT); // 设置菜单同时兼具左右滑动
sm.setBehindCanvasTransformer(mTransformer); // 设置动画
} /**
* 初始化菜单滑动的效果动画
*/
private void initAnimation() {
mTransformer = new CanvasTransformer() {
@Override
public void transformCanvas(Canvas canvas, float percentOpen) {
canvas.scale(interp.getInterpolation(percentOpen), interp.getInterpolation(percentOpen), canvas.getWidth() / , canvas.getHeight() / );
// canvas.translate(0, canvas.getHeight() * (1 -
// interp.getInterpolation(percentOpen)));
} };
} private static Interpolator interp = new Interpolator() {
@Override
public float getInterpolation(float t) {
t -= 1.0f;
return t * t * t + 1.0f;
}
}; /**
* 切换到主界面
*
* @param fragment
*/
public void switchContent(Fragment fragment) {
mContent = fragment;
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).commit();
getSlidingMenu().showContent();
} /**
* 保存Fragment的状态
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState, "Home", mContent);
} }
上面的代码里关于Fragment使用以及Fragment的API不是这篇博文的重点,如果看不明白就先学习一下Fragment。我们关注这个菜单的 实现即可,我使用的方式是Activity继承SlidingFragmentActivity,这种方式是很常见的,也很好维护,只要理解 Fragment使用即可。诚然,我的这个Demo里没有使用SlidingMenu的依赖库ActionBarSherlock,是因为这个Demo已 经自己定义了左右菜单导航按钮,无需使用ActionBar。
5,SlidingMenu的动画
关于代码中的初始化动画,有必要解释一下。这个初始化动画可以不设置,默认就是左右水平方向的平移,这样比较死板,但是SlidingMenu的作者考虑到了我们的担忧,很“t贴心”的为我们写好了实现菜单滑动效果动画的接口,不得不说这外国大牛想的还真细腻。
sm.setBehindCanvasTransformer(mTransformer); // 设置动画
其中mTransformer是SlidingMenu类下的内部接口CanvasTransformer对象,源码如下:
/**
* The Interface CanvasTransformer.
*/
public interface CanvasTransformer { /**
* Transform canvas.
*
* @param canvas the canvas
* @param percentOpen the percent open
*/
public void transformCanvas(Canvas canvas, float percentOpen);
}
实现这个接口,复写这个transformCanvas方法,使用该方法中提供的Canvas对象来实现相应的动画效果。当SlidingMenu触发了 setBehindCanvasTransformer(mTransformer)时,这个方法会触发SlidingMenu下的自定义View对象的 dispatchDraw(Canvas canvas)方法,即每次菜单界面重绘的时候,这个动画就会被调用。关于动画的写法,我提供两个吧,实际情况得根据项目需求来定夺。
SlidingMemu的缩放动画:
/**
* 初始化菜单滑动的效果动画
*/
private void initAnimation() {
mTransformer = new CanvasTransformer() {
@Override
public void transformCanvas(Canvas canvas, float percentOpen) {
canvas.scale(interp.getInterpolation(percentOpen), interp.getInterpolation(percentOpen), canvas.getWidth() / , canvas.getHeight() / );
} };
} private static Interpolator interp = new Interpolator() {
@Override
public float getInterpolation(float t) {
t -= 1.0f;
return t * t * t + 1.0f;
}
};
SlidingMenu的平移动画:
/**
* 初始化菜单滑动的效果动画
*/
private void initAnimation() {
mTransformer = new CanvasTransformer() {
@Override
public void transformCanvas(Canvas canvas, float percentOpen) {
canvas.translate(, canvas.getHeight() * ( - interp.getInterpolation(percentOpen)));
} };
} private static Interpolator interp = new Interpolator() {
@Override
public float getInterpolation(float t) {
t -= 1.0f;
return t * t * t + 1.0f;
}
};
SlidingMenu的拉伸动画:
private void initAnimation() {
mTransformer = new CanvasTransformer() {
@Override
public void transformCanvas(Canvas canvas, float percentOpen) {
canvas.scale(percentOpen, , , );
} };
}
6,SlidingMenu的背景
最后一点,需要注意的是,在给SlidingMenu添加了动画效果后,运行时会看见菜单的背景处是一片“白色”或者“透明色”的,这样的用户体验 非常的不好,那么怎么解决呢?这个很简单的,第一个考虑到是SlidingMenu本身没有设置背景,所以我们要手动的给SlidingMenu控件设置 一下背景,打开SlidingMenu的类库library,在res/layout目录下找到slidingmenumain.xml的文件,打开看见 这里就简单的定义了一个SlidingMenu,其它什么都没有,此时我们就可以在这个slidingmenumain.xml的节点下设置一下 drawable属性即可。
library/res/layout/slidingmenumain.xml:
<?xml version="1.0" encoding="utf-8"?>
<com.jeremyfeinstein.slidingmenu.lib.SlidingMenu
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/slidingmenumain"
android:layout_width="fill _parent"
android:layout_height="fill_parent" />
Android自定义控件 开源组件SlidingMenu的项目集成的更多相关文章
- [Android Pro] 终极组件化框架项目方案详解
cp from : https://blog.csdn.net/pochenpiji159/article/details/78660844 前言 本文所讲的组件化案例是基于自己开源的组件化框架项目g ...
- 开源一款强大的文件服务组件(QJ_FileCenter)(系列三 访问接口与项目集成)
系列文章 1. 开源一款强大的文件服务组件(QJ_FileCenter)(系列一) 2. 开源一款强大的文件服务组件(QJ_FileCenter)(系列二 安装说明) 3. 开源一款强大的文件服务组件 ...
- 【转】【Android】开源项目汇总-备用
第一部分 个性化控件(View) 主要介绍那些不错个性化的View,包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.Pro ...
- Android常用开源项目
Android开源项目第一篇——个性化控件(View)篇 包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.Progre ...
- 【Android】开源项目汇总-备用
from://http://www.eoeandroid.com/home.php?mod=space&uid=765778&do=blog&id=47674 Android开 ...
- 【Android】开源项目汇总
Android开源项目第一篇——个性化控件(View)篇 包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.Progres ...
- [转] Android优秀开源项目
Android经典的开源项目其实非常多,但是国内的博客总是拿着N年前的一篇复制来复制去,实在是不利于新手学习.今天爬爬把自己熟悉的一些开源项目整理起来,希望能对Android开发同学们有所帮助.另外, ...
- Android优秀开源项目
本文转自:http://blog.tisa7.com/android_open_source_projects Android优秀开源项目 Android经典的开源项目其实非常多,但是国内的博客总是拿 ...
- Android组件化框架项目详解
简介 什么是组件化? 项目发展到一定阶段时,随着需求的增加以及频繁地变更,项目会越来越大,代码变得越来越臃肿,耦合会越来越多,开发效率也会降低,这个时候我们就需要对旧项目进行重构即模块的拆分,官方的说 ...
随机推荐
- C++中一个函数隐藏的有趣例子
函数隐藏是一个函数的定义或声明导致其他一些函数不可见. 函数A隐藏函数B的条件: 1. 两个函数具有相同的函数名称 2. 具有不同的作用域.所谓定义域函数定义或声明的位置,如全局作 ...
- [PWA] 7. First Cache when installed
If you want your application works offline or lie-wifi. You need to use cache. API: Create Caches: c ...
- 根据IP地址获取IP的详细信息
<?php header('Content-Type:text/html; charset=utf-8'); function ip_data() { $ip = GetIP(); $url = ...
- log4j配置文件详解---转
使用步骤注意: 1. 从http://logging.apache.org/log4j/1.2/ 下载文件 2. 在src目录下加入log4j.properties,将jar包放入build -pat ...
- [转] restrict关键字用法
PS: 在函数中,指针参数指定了restrict,表示这个指针指向的这段区域只能通过这个指针修改 c99中新增加了一个类型定义,就是restrict. 看了下网上的相关贴子,但还是问题解决的不够.下面 ...
- Ubuntu设置环境变量的几种方法
1.Linux的变量种类 按变量的生存周期来划分,Linux变量可分为两类: 1.1 永久的:需要修改配置文件,变量永久生效. 1.2 临时的:使用export命令声明即可,变量在关闭shell时失效 ...
- 模拟电路"虚短" & "虚断"
<虚短 & 虚断> 运算放大器组成的电路五花八门,令人眼花瞭乱,是模拟电路中学习的重点.遍观所有模拟电子技朮的书籍和课程,在介绍运算放大器电路的时候,无非是先给电路来个定性,比如这 ...
- HDU 5037 Frog(贪心)
题意比较难懂,一只青蛙过河,它最多一次跳L米,现在河中有石头,距离不等,上帝可以往里加石头,青蛙非常聪明,它一定会选择跳的次数最少的路径.问怎么添加石头能让青蛙最多的次数.输出青蛙跳的最多的次数. 考 ...
- C#基础知识01(continue、break 和 return、ref 和 out)
break[跳出循环或者退出一个switch语句]由于它是用来退出循环或者switch语句的,所以只有当它出现在这些语句中时才是合法的. continue 语句和break语句相似,只是它不是退出一个 ...
- .net中XML的创建02(linqToXml)
linqToXml比较的灵活和方便,它是基于函数式编程具体的使用如下:引用程序集using System.Xml.Linq; 1.创建XDocument并设置文档头 XDocument XDoc = ...