SlidingMenu+ViewPager实现侧滑菜单效果
先简单介绍下SlidingMenu和ViewPager.
ViewPager就是一个官方提供的多页面滑动组件,需要一个适配器来构建多个页面.
先来看看ViewPager对应的基本适配器PageAdapter,需要实现以下方法
getCount()
这个方法,是获取当前窗体界面数
isViewFromObject()
判断是否由对象生成 的view ,一般写法都比较固定
如:return object == view;
instantiateItem(ViewGroup, int)
这个方法,return一个对象,这个对象表明了PagerAdapter适配器选择哪个对象放在当前的ViewPager中
destroyItem(ViewGroup, int, Object)
这个方法,是从ViewGroup中移出当前View
finishUpdate(ViewGroup container)
在UI更新后完成的动作
ViewPager对应的监听器是PageChangeListner 当页面改变时触发
一般使用一个简单的子类监听器是SimpleOnPageChangeListener
onPageSelected(int position)
页卡选中的方法
平常使用FragmentPagerAdapter和FragmentStatePagerAdapter来构建ViewPager
FragmentPagerAdapter更多的用于少量界面的ViewPager,比如Tab划过的fragment会保存在内存中,尽管已经划过。
而FragmentStatePagerAdapter和ListView有点类似,会保存当前界面,以及下一个界面和上一个界面(如果有),最多保存3个,其他会被销毁掉。
注意的是FragmentStatePagerAdapter可能不经意间会造成内存未正常回收,严重导致内存溢出,比如图片资源没有释放,资源引用问题
setOffscreenPageLimit(int)
设置预加载TAB页卡数量,默认是1,就是当前页卡显示的时候,预先加载下一个页卡.数量不能太大.设为0即不進行预加载
SlidingMenu
使用方法:
首先,Activity要继承自SlidingFragmentActivity,而SlidingFragmentActivity又继承自SherlockFragmentActivity并实现SlidingActivityBase接口提供相应方法
左侧、右侧和两边
在BaseActivity中将SlidingMenu默认设置左面菜单,全屏可拉动及其他一些属性,下面看代码:
// 设置menu布局,根据模式决定是从左侧还是右侧拉出
setBehindContentView(R.layout.menu_frame);
FragmentTransaction t = this.getSupportFragmentManager().beginTransaction();
mFrag = new SampleListFragment();
t.replace(R.id.menu_frame, mFrag);
t.commit();
//SlidingMenu控件的初始化
SlidingMenu sm = getSlidingMenu();
sm.setShadowWidthRes(R.dimen.shadow_width);//阴影宽度
sm.setShadowDrawable(R.drawable.shadow);//阴影Drawable
sm.setBehindOffsetRes(R.dimen.slidingmenu_offset);//拉开后离边框距离
sm.setFadeDegree(0.35f); //颜色渐变比例
sm.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN); //拉动事件区域 --全屏
getSupportActionBar().setDisplayHomeAsUpEnabled(true); //ActionBar返回启用
设置SlidingMenu的模式:
// 设置左侧menu
sm.setMode(SlidingMenu.LEFT);
// 设置右侧menu
sm.setMode(SlidingMenu.RIGHT);
当设置左右两侧时要注意,因为前面只添加了一个菜单布局,所以这里我们要另外再设置一个:
// 设置左右侧都有
sm.setMode(SlidingMenu.LEFT_RIGHT);
// 此时要再次添加布局菜单,上一个为左侧,这个为右侧
sm.setSecondaryMenu(R.layout.menu_frame_two);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.menu_frame_two,
new SampleListFragment()).commit();
sm.setSecondaryShadowDrawable(R.drawable.shadowright);
可拉动触控范围
这个更简单,不多说:
switch (checkedId) {
case R.id.touch_above_full:
// 设置触摸拖动模式--全屏
getSlidingMenu().setTouchModeAbove(
SlidingMenu.TOUCHMODE_FULLSCREEN);
break;
case R.id.touch_above_margin:
// 设置触摸拖动模式--边缘
getSlidingMenu().setTouchModeAbove(
SlidingMenu.TOUCHMODE_MARGIN);
break;
case R.id.touch_above_none:
// 设置触摸拖动模式--关闭
getSlidingMenu().setTouchModeAbove(
SlidingMenu.TOUCHMODE_NONE);
break;
}
放缩比例
// 放缩比例
getSlidingMenu().setBehindScrollScale(
(float) seekBar.getProgress() / seekBar.getMax());
拉出菜单宽度
// 菜单宽度(源码中作者把该操作隐藏)
getSlidingMenu().setBehindWidth(
(int) (percent * getSlidingMenu().getWidth()));
getSlidingMenu().requestLayout();
阴影
有无阴影
if (isChecked)
// 是否有阴影
getSlidingMenu()
.setShadowDrawable(
getSlidingMenu().getMode() == SlidingMenu.LEFT ? R.drawable.shadow: R.drawable.shadowright);
else
getSlidingMenu().setShadowDrawable(null);
阴影宽度
// 设置阴影宽度
getSlidingMenu().setShadowWidth(width);
getSlidingMenu().invalidate();
颜色渐变
有无渐变
getSlidingMenu().setFadeEnabled(isChecked);
渐变比率
// 颜色渐变比例
getSlidingMenu().setFadeDegree(
(float) seekBar.getProgress() / seekBar.getMax());
代码部分
package com.light.android.study; import com.light.android.study.fragment.ContentFragment; import com.light.android.study.fragment.MenuFragment; import com.slidingmenu.lib.SlidingMenu; import com.slidingmenu.lib.app.SlidingActivity; import android.os.Bundle; import android.view.MenuItem; import android.app.ActionBar; import android.app.FragmentTransaction; public class MainActivity extends SlidingActivity{ private FragmentTransaction transaction; private ContentFragment contentFragment; private MenuFragment menuFragment; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.content_page); setBehindContentView(R.layout.menu_page); menuFragment = new MenuFragment(); contentFragment = new ContentFragment("welcome!Kris Light!"); transaction = getFragmentManager().beginTransaction(); transaction.replace(R.id.menu,menuFragment,"menu"); transaction.replace(R.id.content,contentFragment,"content"); transaction.commit(); //設置ActionBar為TAB頁簽模式 getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); //初始化SlidingMenu initSlidingMenu(); } private void initSlidingMenu() { //SlidingMenu控件的初始化 使用默認的Right模式,菜單在右邊 SlidingMenu sm = getSlidingMenu(); //阴影宽度 sm.setShadowWidth(50); //阴影Drawable sm.setShadowDrawable(R.drawable.shadow); //拉开后离边框距离 sm.setBehindOffset(80); //颜色渐变比例 sm.setFadeDegree(0.35f); //设置slding menu的几种手势模式 //TOUCHMODE_FULLSCREEN 全屏模式,在content页面中,滑动,可以打开sliding menu //TOUCHMODE_MARGIN 边缘模式,在content页面中,如果想打开slding ,你需要在屏幕边缘滑动才可以打开slding menu //TOUCHMODE_NONE 自然是不能通过手势打开啦 sm.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN); //使用左上方icon可点,这样在onOptionsItemSelected里面才可以监听到R.id.home getActionBar().setDisplayHomeAsUpEnabled(true); } @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId()== android.R.id.home){ toggle(); } return super.onOptionsItemSelected(item); } }
package com.light.android.study; import android.app.Fragment; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class PageFragment extends Fragment { private String text; public PageFragment(){ } public String getText() { return text; } public void setText(String text) { this.text = text; } public PageFragment(String t){ this.text = t; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.i("Light", "onCreateView "+text); View view = inflater.inflate(R.layout.fragment_page_layout, null); TextView tv = (TextView) view.findViewById(R.id.tv); tv.setText(text); return view; } }
package com.light.android.study.adapter; import java.util.ArrayList; import java.util.List; import com.light.android.study.PageFragment; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.support.v4.view.PagerAdapter; import android.view.View; import android.view.ViewGroup; public class ContentPageAdapter extends PagerAdapter{ private List<PageFragment> pageList = new ArrayList<PageFragment>(); private FragmentManager fragmentManager; private FragmentTransaction transaction; public ContentPageAdapter(List<PageFragment> list,FragmentManager manager){ this.pageList = list; this.fragmentManager = manager; transaction = manager.beginTransaction(); } //获取当前窗体界面数 @Override public int getCount() { return pageList.size(); } //判断是否是由对象生成的View @Override public boolean isViewFromObject(View view, Object object) { return ((Fragment) object).getView() == view; } //这个方法,return一个对象,这个对象表明了PagerAdapter适配器选择哪个对象放在当前的ViewPager中 @Override public Object instantiateItem(ViewGroup container, int position) { if(transaction==null){ transaction = fragmentManager.beginTransaction(); } //先判斷之前是否有attach過這個Fragment,有的話直接重新attach綁定 String tag = pageList.get(position).getText(); PageFragment fragment = (PageFragment) fragmentManager.findFragmentByTag(tag); if(fragment!=null){ transaction.attach(fragment); }else{ //沒有attach過直接add fragment = pageList.get(position); transaction.add(container.getId(),fragment,fragment.getText()); } return fragment; } /** * 此方法是移当前Object */ @Override public void destroyItem(ViewGroup container, int position, Object object) { if (transaction == null) { transaction = fragmentManager.beginTransaction(); } //detach解除綁定 transaction.detach((Fragment) object); } /** * 在UI更新完成后的动作 */ @Override public void finishUpdate(ViewGroup container) { if(transaction!=null){ //提交 transaction.commitAllowingStateLoss(); transaction = null; //立即執行事務 fragmentManager.executePendingTransactions(); } } }
package com.light.android.study.fragment; import com.light.android.study.R; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class ContentFragment extends Fragment { private String title; public ContentFragment(){ } public ContentFragment(String title){ this.title = title; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //設置Fragment不重建 setRetainInstance(true); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View convertView = inflater.inflate(R.layout.fragment_page_layout, null); TextView tv = (TextView) convertView.findViewById(R.id.tv); tv.setText(title); return convertView; } }
package com.light.android.study.fragment; import java.util.ArrayList; import java.util.List; import android.app.ActionBar; import android.app.ActionBar.Tab; import android.app.FragmentTransaction; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceFragment; import android.support.v4.view.ViewPager; import android.view.View; import android.widget.FrameLayout; import com.light.android.study.MainActivity; import com.light.android.study.PageFragment; import com.light.android.study.R; import com.light.android.study.adapter.ContentPageAdapter; import com.slidingmenu.lib.SlidingMenu; public class MenuFragment extends PreferenceFragment { private List<PageFragment> pageList = new ArrayList<PageFragment>(); private MainActivity mActivity; private ViewPager pager; FrameLayout mFrameLayout; private ContentPageAdapter adapter; private int index = -1; public MenuFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); addPreferencesFromResource(R.xml.menu); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mActivity = (MainActivity) getActivity(); pager = (ViewPager) mActivity.findViewById(R.id.viewpager); mFrameLayout = (FrameLayout)mActivity.findViewById(R.id.content); findPreference("chunqiu").setOnPreferenceClickListener(onPreferenceClickListener); findPreference("zhanguo").setOnPreferenceClickListener(onPreferenceClickListener); findPreference("han").setOnPreferenceClickListener(onPreferenceClickListener); findPreference("sanguo").setOnPreferenceClickListener(onPreferenceClickListener); } Preference.OnPreferenceClickListener onPreferenceClickListener = new Preference.OnPreferenceClickListener() { //点击一个选项 @Override public boolean onPreferenceClick(Preference preference) { String key = preference.getKey(); mFrameLayout.setVisibility(View.GONE); //历史 //三国 if("sanguo".equals(key)){ //刚好是三国这一个选项 if(index == 0) { mActivity.getSlidingMenu().toggle(); return true; } index = 0; ActionBar actionBar = mActivity.getActionBar(); actionBar.removeAllTabs(); //清空 pageList.clear(); actionBar.addTab(actionBar.newTab().setText("魏").setTabListener(tablistener)); PageFragment weiFragment = new PageFragment("魏"); pageList.add(weiFragment); actionBar.addTab(actionBar.newTab().setText("蜀").setTabListener(tablistener)); PageFragment shuFragment = new PageFragment("蜀"); pageList.add(shuFragment); actionBar.addTab(actionBar.newTab().setText("吴").setTabListener(tablistener)); PageFragment wuFragment = new PageFragment("吴"); pageList.add(wuFragment); adapter = new ContentPageAdapter(pageList,mActivity.getFragmentManager()); //設置PagerView預加載View數量 pager.setOffscreenPageLimit(2); //为ViewPager设置Adapter pager.setAdapter(adapter); //設置Page改變監聽器 pager.setOnPageChangeListener(onPageChangeListener); }else if("han".equals(key)){ //汉代 //刚好是汉这一个选项 if(index == 1) { mActivity.getSlidingMenu().toggle(); return true; } index = 1; ActionBar actionBar = mActivity.getActionBar(); //清空一次 actionBar.removeAllTabs(); pageList.clear(); actionBar.addTab(actionBar.newTab().setText("汉").setTabListener(tablistener)); PageFragment hanFragment = new PageFragment("汉"); pageList.add(hanFragment); actionBar.addTab(actionBar.newTab().setText("楚").setTabListener(tablistener)); PageFragment chuFragment = new PageFragment("楚"); pageList.add(chuFragment); adapter = new ContentPageAdapter(pageList,mActivity.getFragmentManager()); //設置PagerView預加載View數量 pager.setOffscreenPageLimit(1); //为ViewPager设置Adapter pager.setAdapter(adapter); //設置Page改變監聽器 pager.setOnPageChangeListener(onPageChangeListener); }else if("zhanguo".equals(key)){ //战国 //刚好是战国这一个选项 if(index == 2) { mActivity.getSlidingMenu().toggle(); return true; } index = 2; ActionBar actionBar = mActivity.getActionBar(); //清空一次 actionBar.removeAllTabs(); pageList.clear(); actionBar.addTab(actionBar.newTab().setText("戰國").setTabListener(tablistener)); PageFragment zgFragment = new PageFragment("戰國"); pageList.add(zgFragment); adapter = new ContentPageAdapter(pageList,mActivity.getFragmentManager()); //为ViewPager设置Adapter pager.setAdapter(adapter); //設置Page改變監聽器 pager.setOnPageChangeListener(onPageChangeListener); }else if("chunqiu".equals(key)){ //春秋 //刚好是春秋这一个选项 if(index == 3) { mActivity.getSlidingMenu().toggle(); return true; } index = 3; ActionBar actionBar = mActivity.getActionBar(); //清空一次 actionBar.removeAllTabs(); pageList.clear(); actionBar.addTab(actionBar.newTab().setText("春秋").setTabListener(tablistener)); PageFragment cqFragment = new PageFragment("春秋"); pageList.add(cqFragment); adapter = new ContentPageAdapter(pageList,mActivity.getFragmentManager()); //为ViewPager设置Adapter pager.setAdapter(adapter); //設置Page改變監聽器 pager.setOnPageChangeListener(onPageChangeListener); } //无论如何将菜单开关动作交给SlidingMenu管理 mActivity.getSlidingMenu().toggle(); return false; } }; /** * SimpleOnPageChangeListener.该监听是当我们的viewpager页面切换的时候会触发 * 在里面我们会去改变 tab的聚焦情况 。 * 因为实现上viewpager与actionbar是独立的,需要我们手动同步 。 */ ViewPager.SimpleOnPageChangeListener onPageChangeListener = new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { /** * setSelectedNavigationItem 方法用于设置ActionBar的聚焦tab . * 在接下来我们判断了SLidingMenu的手势力模式, * 如果ViewPager已经滑到了最左边,则我们把手势设置成全屏的, * 这样更往左滑动的时候,就会打开Menu . */ getActivity().getActionBar().setSelectedNavigationItem(position); switch (position) { //滑到最左邊頁卡設置SlidingMenu滑動手勢可全屏即右滑出菜單 case 0: getSlidingMenu().setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN); break; default: getSlidingMenu().setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN); break; } } }; ActionBar.TabListener tablistener = new ActionBar.TabListener() { @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { } @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { if (pager.getCurrentItem() != tab.getPosition()) pager.setCurrentItem(tab.getPosition()); } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { } }; private SlidingMenu getSlidingMenu() { return ((MainActivity)getActivity()).getSlidingMenu(); } }
content_fragment_layout.xml:
<?xml version="1.0" encoding="utf-8"?> <Fragment xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > </Fragment>
content_page.xml:
<?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="match_parent" android:orientation="vertical" > <FrameLayout android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" > </FrameLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>
fragment_page_layout.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".PageActivity" > <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="page" /> </FrameLayout>
menu_page.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/menu" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > </FrameLayout>
更新:
源代码已上传:http://download.csdn.net/detail/u011176244/6227395
需要另外导入SlidingMenu库 网上有很多教程如何使用这个库。