slidingmenu+fragment实现常用的侧滑效果(包括Fragment状态的保存)

一、需求

关于fragment的问题,一直想写一篇博客了,应该当初自己也是对这玩意一点都不熟悉到现在也大概知道个日常的使用的地步。

一个侧滑的导航栏,内有4个条目,每个选项点击进入对应的界面,每一个界面是一个fragment,各界面之间自由切换,且可以保存之前的状态,也就是说,切换的过程并不会产生新的对象,不会重新去new 一个fragment对象,不需要每次点击重新加载数据,这里就涉及了一个很重要的问题,fragment状态的保存,在这篇文章里,我尽量用实例把这个问题说清楚,毕竟当初也是查了不少资料,摸索了不少地方才解决的。

还有一个问题,是最近发现的,就是从一个activity界面跳到其中的一个fragment,这个在实际的应用中,也会涉及到,因为我们的项目就涉及到这里了,知道最后还是想办法把这个问题解决了,下面来看看详细的介绍吧。

二、实际效果图

   
 

三、实现过程

1、准备工作

先导入slidingmenu库文件,这个相信大家都会把.导入slidingmenu的库文件后会报错,因为它是依赖另一个库文件的,这个库文件就是ActionBarSherlock,将它的库文件也导入eclipse,这个时候要注意几点,首先,要将actionbarsherlock作为slidingmenu的库文件,然后将slidingmenu作为程序的库文件。

同时,要将actionbarsherlock中的android-support-v4包分别拷到slidingmenu库的libs中覆盖原来的android-support-v4包,同理也要覆盖程序的support-v4包,否则就会出现The hierarchy of the type MainActivity is inconsistent这个错误。

导入了相应的库文件后,将主Activity继承SlidingFragmentActivity 就可以使用sliding menu了

2.导航栏界面实现,打开slidingmenu后看到的界面

先做一个侧滑导航的fragment,这个fragment就是应用程序的侧边导航栏,侧滑打开后,点击其中的某一项,就会跳到相应的fragment页面。

我们将这个fragment命名为navifragment,先看navifragment的布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/navi_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#cccccc" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="400dip"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/tv_navi_wechat"
            style="@style/navitext"
            android:drawableLeft="@drawable/wechat"
            android:text="微信" />

        <TextView
            android:id="@+id/tv_navi_contacts"
            style="@style/navitext"
            android:drawableLeft="@drawable/contacts"
            android:text="通讯录" />

        <TextView
            android:id="@+id/tv_navi_search"
            style="@style/navitext"
            android:drawableLeft="@drawable/search"
            android:text="发现" />

        <TextView
            android:id="@+id/tv_navi_my"
            style="@style/navitext"
            android:drawableLeft="@drawable/my"
            android:text="我的" />

    </LinearLayout>

</RelativeLayout>

效果如下图:

NaviFragment中的代码如下:

public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {

		if (rootView == null) {
			rootView = inflater.inflate(R.layout.fragment_navi, null);
		}

		fragmentManager = getFragmentManager();

		init();

		return rootView;

	}

	@Override
	public void onAttach(Activity activity) {
		mActivity = (MainActivity) activity;
		super.onAttach(activity);
	}

	/**
	 * 初始化,设置点击事件
	 */
	private void init() {
		navi_wechat = (TextView) rootView.findViewById(R.id.tv_navi_wechat);
		navi_contacts = (TextView) rootView.findViewById(R.id.tv_navi_contacts);
		navi_search = (TextView) rootView.findViewById(R.id.tv_navi_search);
		navi_my = (TextView) rootView.findViewById(R.id.tv_navi_my);

		navi_wechat.setSelected(true);// 默认选中菜单

		navi_wechat.setOnClickListener(this);
		navi_contacts.setOnClickListener(this);
		navi_search.setOnClickListener(this);
		navi_my.setOnClickListener(this);
	}

	/**
	 * 点击导航栏切换 同时更改标题
	 */
	@Override
	public void onClick(View view) {
		switch (view.getId()) {
		case R.id.tv_navi_wechat:// 打开微信界面

			navi_wechat.setSelected(true);// 微信设置为被选中状态,其余设置为非选中状态
			navi_contacts.setSelected(false);
			navi_my.setSelected(false);
			navi_search.setSelected(false);

			OnTabSelected(WECHATFRAGMENT);
			break;
		case R.id.tv_navi_contacts:// 打开通讯录界面

			navi_wechat.setSelected(false);
			navi_contacts.setSelected(true);
			navi_my.setSelected(false);
			navi_search.setSelected(false);

			OnTabSelected(CONTACTSFRAGMENT);
			break;
		case R.id.tv_navi_search:// 打开发现界面

			navi_wechat.setSelected(false);
			navi_contacts.setSelected(false);
			navi_my.setSelected(false);
			navi_search.setSelected(true);

			OnTabSelected(SEARCHFRAGMENT);
			break;
		case R.id.tv_navi_my:// 打开我的界面

			navi_wechat.setSelected(false);
			navi_about.setSelected(false);
			navi_contacts.setSelected(false);
			navi_my.setSelected(true);
			navi_search.setSelected(false);
			navi_yuefan.setSelected(false);

			OnTabSelected(MYFRAGMENT);
			break;
		}
		mActivity.getSlidingMenu().toggle();
	}

	//选中导航中对应的tab选项
	private void OnTabSelected(int index) {
		FragmentTransaction transaction = fragmentManager.beginTransaction();
		hideFragments(transaction);
		switch (index) {
		case WECHATFRAGMENT://微信
			if (null == wechatFragment) {
				wechatFragment = new WechatFragment();
				transaction.add(R.id.center_frame, wechatFragment);
			} else {
				transaction.show(wechatFragment);
			}
			break;
		case CONTACTSFRAGMENT: //通讯录
			if (null == contactsFragment) {
				contactsFragment = new ContactsFragment();
				transaction.add(R.id.center_frame, contactsFragment);
			} else {
				transaction.show(contactsFragment);
//				String phone = SharedPrefsUtil.getString(getActivity(),
//						AppConst.USERPHONE);
//				if (phone != null && !"".equals(phone)) {
//					contactsFragment.et_phone.setText(phone);
//				}
			}
			break;
		case SEARCHFRAGMENT://发现
			if (null == serchFragment) {
				serchFragment = new SerchFragment();
				transaction.add(R.id.center_frame, serchFragment);
			} else {
				transaction.show(serchFragment);
			}
			break;
		case MYFRAGMENT://我的
			if (null == myFragment) {
				myFragment = new MyFragment();
				transaction.add(R.id.center_frame, myFragment);
			} else {
				transaction.show(myFragment);
			}
			break;
		}
		transaction.commit();
	}

	/**
	 * 将所有fragment都置为隐藏状态
	 *
	 * @param transaction
	 *            用于对Fragment执行操作的事务
	 */
	private void hideFragments(FragmentTransaction transaction) {
		if (wechatFragment != null) {
			transaction.hide(wechatFragment);
		}
		if (contactsFragment != null) {
			transaction.hide(contactsFragment);
		}
		if (serchFragment != null) {
			transaction.hide(serchFragment);
		}
		if (myFragment != null) {
			transaction.hide(myFragment);
		}
	}

上面有两个重要的方法,涉及到fragment状态的保存

transcation.hide()  transction.show()

前一个是fragment的隐藏,将fragment隐藏到后面去,当然,这个fragment并没有被destroy,一直保存着隐藏前的状态,当执行show()方法后,该fragment将再次显示,之前的所有状态都继续存在。这样做的好处就是不用每次点击某一个item就new 一个fragment的对象,避免了频繁的创建fragment,也避免了每次加载相同的数据,尤其是在实际应用中,可能加载一个主页的fragment会消耗大量的网络资源,不进行fragment的保存,用户体验也会差很多,同样的内容,尤其是一些不是经常变化的数据,每次加载,很让人难接受。

看上面的代码,当点击一个item条目的时候,首先是将之前所有的fragment都进行隐藏,然后进行判断是否存在该fragment,如果存在,就直接将该fragment显示,如果不存在,则new一个该fragment的对象,并将该fragment对象加入transaction事务控制中去。

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

一般通过以上两句代码获得fragmenttransaction对象,通过该对象对fragment进行管理。

现在,导航栏的界面NaviFragment已经准备好了,接下来是slidingmenu,通过slidingmenu打开导航栏

3.slidingmenu的实现

slidingmenu对象是通过下面的方法获取到的

SlidingMenu mSlidingMenu = getSlidingMenu();

然后,可以设置slidingmenu的一些参数和属性,这里举几个最常用的属性设置

mSlidingMenu.setMode(SlidingMenu.LEFT);// 设置slidingmeni从哪侧出现
		mSlidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN);// 打开模式 有全屏,仅边界
		mSlidingMenu.setBehindOffsetRes(R.dimen.slidingmenu_offset);// 侧滑距离右边界的偏移量
<p style="margin-top: 0px; margin-bottom: 0px; font-size: 11px; font-family: Monaco;">       <span style="white-space:pre">		</span>     //mSlidingMenu.setTouchModeAbove(SlidingMenu.<span style="color: #0326cc">TOUCHMODE_FULLSCREEN</span>);<span style="color: #4e9072">//全屏都可以打开</span></p><p style="margin-top: 0px; margin-bottom: 0px; font-size: 11px; font-family: Monaco;"><span style="white-space:pre">		</span>     //mSlidingMenu.setTouchModeAbove(SlidingMenu.<span style="color: #0326cc">TOUCHMODE_NONE</span>);<span style="color: #4e9072">//不可以通过滑动打开</span></p>
		mSlidingMenu.setFadeEnabled(true);//设置侧滑开关时是否需要淡入淡出的效果
		mSlidingMenu.setFadeDegree(0.5f);//设置淡入淡出的程序
		mSlidingMenu.setMenu(R.layout.frame_navi);
setBehindContentView(R.layout.frame_navi); // 给滑出的slidingmenu的fragment制定layout

MainActivity的代码

public class MainActivity extends SlidingFragmentActivity  {

	private WechatFragment wechatFragment;
	private NaviFragment naviFragment;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);

		initFragment();

	}

	private void initFragment() {

		SlidingMenu mSlidingMenu = getSlidingMenu();

		setBehindContentView(R.layout.frame_navi); // 给滑出的slidingmenu的fragment制定layout
		naviFragment = new NaviFragment();
		getSupportFragmentManager().beginTransaction()
				.replace(R.id.frame_navi, naviFragment).commit();
		// 设置slidingmenu的属性
		mSlidingMenu.setMode(SlidingMenu.LEFT);// 设置slidingmeni从哪侧出现
		mSlidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);//全屏都可以打开
		mSlidingMenu.setBehindOffsetRes(R.dimen.slidingmenu_offset);// 偏移量
		mSlidingMenu.setFadeEnabled(true);
		mSlidingMenu.setFadeDegree(0.5f);
		mSlidingMenu.setMenu(R.layout.frame_navi);

		Bundle mBundle = null;
		// 导航打开监听事件
		mSlidingMenu.setOnOpenListener(new OnOpenListener() {
			@Override
			public void onOpen() {
			}
		});
		// 导航关闭监听事件
		mSlidingMenu.setOnClosedListener(new OnClosedListener() {

			@Override
			public void onClosed() {
			}
		});
	}

}

4.接下来是几个Fragment界面的实现,这几个界面就是实际开发中最主要的几个界面。

fragment的生命周期不同于activity,但是非常类似,有兴趣的同学可以去研究一下,这里就不列出了。其中的oncreatview是用来加载界面的,返回值view就是要显示的view。

例如我们的首页,wechatfragment

public class WechatFragment extends Fragment {
	@Override
	public void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		// TODO Auto-generated method stub

		return inflater.inflat(R.layout.wechat_fargment,null);
	}
}

其他几个fragment的页面跟这个页面类似。

最后,运行程序,就可以得到一个带slidingmenu的fragment应用,点击导航栏中的不同条目,跳转到不同的fragment。

效果图如下所示:

下面,我们来看一种奇怪的现象,fragment出现了重叠的情况,看图:

    

后面的fragment与首页的fragment出现了重叠的现象,这个在开发过程中是个非常大的bug,你点击通讯录界面的按钮,可能就把微信界面的按钮也给点击了,这个在实际开发中是不允许出现的。

我之前就犯了这个大错误,每次在后面的fragment点击的时候,前面fragment界面也对点击事件进行了响应了,头疼了好久,最后终于找到原因,就是在MainAcitity里面加了这么一句代码:

wechatFragment = new WechatFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.center_frame, wechatFragment).commit();

导致了这个问题的产生。

当然,这个问题又可以带来一个应用,比如有好几个fragment标题栏有同一个控件,这个时候,就可以利用这个特性来合理利用了,这个我也用过。不过现在找到这个bug的原因了,就不再这么干了。

fragment还有各种应用,会出现一些意想不到的问题,还有很多值得探索的地方,实际开发中很多问题都涉及到,这里就不细细说明了。

slidingmenu+fragment的简单应用就是这样了。

放上demo的下载地址:http://download.csdn.net/detail/yanglfree/7594673

slidingmenu+fragment实现常用的侧滑效果(包括Fragment状态的保存),布布扣,bubuko.com

时间: 2024-08-01 14:44:09

slidingmenu+fragment实现常用的侧滑效果(包括Fragment状态的保存)的相关文章

fragment做成选项卡,tab效果。 fragment+RadioGroup

fragment做成选项卡,tab效果. fragment+RadioGroup from://http://blog.csdn.net/zimo2013/article/details/12239349 1.Fragment概述 在一个Activity中, Fragment代表UI的一个部分或者一个行为.一个Activity可以结合多个Fragment对象,也可以在多个activity中使用相同Fragment字节码对应的不同对象.一个Fragment对象必须被嵌入在一个主Activity对象

CABasicAnimation学习Demo 包括了一些常用的动画效果

个人写的一些例子: // // ViewController.m // CABasicAnimationDemo // // Created by haotian on 14-6-13. // Copyright (c) 2014年 Baseus. All rights reserved. // #import "ViewController.h" @interface ViewController () @end @implementation ViewController @syn

iOS开发中常用的轮子 第四篇 抽屉和侧滑效果

为避免重复造轮子,很多效果和功能都可以从github上找到.清点以前的项目,整理出了很多用过的开源代码,每天奉送一批. 学习例子的方法: 1,了解:运行一遍例子,弄清这些代码的究竟是什么: 2,使用:在之后开发工程中使用这些例子: 3,研究代码:研究例子的代码的实现,简单修改做出自己的效果. 记得要么是facebook,或是twitter第一个使用了个交互效果:而后风靡全球,是产品必用抽屉:再后来就是延生出了各种变形过的效果: 所以,产品经理要你实现抽屉和侧滑效果时,一定要确定到底是什么样抽屉和

Android使用DrawerLayout仿qq6.6版本侧滑效果

一讲到侧滑菜单,我相信大家都会想到一个开源控件SlidingMenu,在google还没有出来DrawerLayout的时候几乎都是使用Slidingmenu来实现侧滑效果,可以说是效果很不错,自从google出了Drawerlayout以后很多公司就使用了Drawerlayout比如 滴滴打车等等.那么今天我们利用drawerlayout来实现qq6.6最新的侧滑效果.首先来看看Drawerlayout默认的效果: 和目前最新版的qq的侧滑还是不一样的区别就是内容页面没有跟随向右滑动,而是菜单

Menu史上最牛的侧滑效果

GAG-master史上最牛的侧滑效果,其中加载图片展示的时候也是慢慢翻转效果,侧滑Menu更是牛逼.  其中自定义BlurFoldingActionBarToggle 提供了onDrawerOpened()和onDrawerClosed()方法,  然后在这两个方法里面设置打开和关闭等各项操作. 运行效果: 查看完整源码地址:http://www.itlanbao.com/code/20150909/10000/100518.html package me.storm.ninegag; imp

android如何做iphone那种图片抖动动画的效果(包括button和EditText)

给按钮做抖动效果,可以这样做,建立anim文件夹在res下面,创建一个button_shake.xml <?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="120" android:fromDegrees="

使用Fragment来实现Tab的效果

前一篇文章实现了使用ViewPager来实现Tab的效果,这篇来介绍使用Fragment来实现Tab的效果. 下面给出上一篇的地址:http://www.cnblogs.com/mengyan1124/p/4675524.html 实现效果是同前一篇一样的,而布局文件也仅仅只有activity_main.xml发生了一点变化,此文件代码如下: 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&

滑动方向的检测和侧滑效果,自己可以定义,或者上啦刷新的制作基础

滑动方向的检测和侧滑效果,自己可以定义,或者上啦刷新的制作基础 序言: 在iPhone开发里面,经常看到手指在触摸屏上拖动时,可以让画面左右移动,就像侧滑效果一样.今天,我们要做一个效果.. 正文: 第一步: 我们要创建3个枚举量,来表示画面的状态....代码如下: typedef enum { //原状态 KYuanTai, //横向滑动 KHengTai, //纵向滑动 KZongTai, }DirectionForSlide; 枚举类型定义有好几种...这是其中一种... 第二步:我们创建

Android Fragment用法详解(1)--静态使用Fragment

Fragment,也就是碎片,本意是为了适配大屏幕的安卓设备而生的.但是出现后,很多安卓开发者都非常喜欢这个东西.这个东西很好用,但是也不是很容易用.下面我来来细细解说Android中的Fragment. 1.Fragment产生的缘由 运行Android的设备繁多,屏幕大小更是多种多样.针对不同屏幕尺寸,通常情况下,开发者都是先针对手机开发一套源代码,然后拷贝一份,修改布局以适应大屏幕设备,或平板,电视等.为了决解这样的麻烦,Google推出了Fragment.你可以把Fragment当成Ac