一、需求

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

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

另一个问题,是近期发现的。就是从一个activity界面跳到当中的一个fragment,这个在实际的应用中。也会涉及到,由于我们的项目就涉及到这里了,知道最后还是想办法把这个问题攻克了,以下来看看具体的介绍吧。

二、实际效果图

  

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3NyX3lhbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""> 
 

三、实现过程

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这个错误。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3NyX3lhbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

导入了对应的库文件后。将主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出现了重叠的情况,看图:

    

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3NyX3lhbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

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

我之前就犯了这个大错误,每次在后面的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状态的保存)的更多相关文章

  1. 【FastDev4Android框架开发】打造QQ6.X最新版本号側滑界面效果(三十八)

    转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/50253925 本文出自:[江清清的博客] (一).前言: [好消息] ...

  2. 自己实现android側滑菜单

    当今的android应用设计中.一种主流的设计方式就是会拥有一个側滑菜单,以图为证:     实现这种側滑效果,在5.0曾经我们用的最多的就是SlidingMenu这个开源框架,而5.0之后.goog ...

  3. Android 实现形态各异的双向側滑菜单 自己定义控件来袭

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39670935.本文出自:[张鸿洋的博客] 1.概述 关于自己定义控件側滑已经写了 ...

  4. Android学习之仿QQ側滑功能的实现

    如今项目越来越多的应用了滑动删除的功能,Android本来遵循的是长按删除,IOS定制的是滑动删除,不可否认滑动删除确实在客户体验上要好一点,所以看了非常多关于仿QQ滑动删除的样例,还是感觉代码家的A ...

  5. android:QQ多种側滑菜单的实现

    在这篇文章中写了 自己定义HorizontalScrollView实现qq側滑菜单 然而这个菜单效果仅仅是普通的側拉效果 我们还能够实现抽屉式側滑菜单 就像这样 第一种效果 另外一种效果 第三种效果 ...

  6. Android 高仿QQ5.2双向側滑菜单DrawerLayout实现源代码

    Android 高仿QQ5.2双向側滑菜单DrawerLayout实现源代码 左右側滑效果图 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a ...

  7. 側滑回退的layout(相似IOS側滑回退到上一个activity)

    用过apple的同学应该都知道,大多数IOS应用都支持側滑回退,就不具体说明了,直接上图: 作为使用ios的android开发人员来说,我是特别喜欢这个功能的.既然这样,那就在android上也实现这 ...

  8. 高仿QQ6.0側滑菜单之滑动优化(二)

    好了,昨天已经实现了高仿QQ6.0的側滑大致框架.如有兴趣.能够去看下仿QQ6.0側滑之ViewDragHelper的使用(一) 可是之前的实现.仅仅是简单的能够显示和隐藏左側的菜单,可是特别生硬,并 ...

  9. 高仿QQ6.0之側滑删除

    前两天已经完毕了高仿QQ6.0側滑和优化,今天来看下側滑删除的实现吧,假设有兴趣,能够去看下之前的两篇,仿QQ6.0側滑之ViewDragHelper的使用(一)和高仿QQ6.0側滑菜单之滑动优化(二 ...

随机推荐

  1. SGU 158.Commuter Train

    一道简单题. 火车停的位置不是在整点就是在二分之一点,坐标*2,然后枚举火车停的位置,计算总距离即可. code: #include <iostream> #include <cma ...

  2. SGU 226.Colored graph(最短路)

    时间限制:0.25s 空间限制:4M 题意: 给出一个n个节点,m条边的图,每条边都有标记了编号为1,2,3三种颜色之一,现在求从1号节点到n号节点的一条最短路径的长度,要求该路径中相邻的边没有相同的 ...

  3. 怎么去掉iframe的滚动条?

    <iframe name="123" src="YNJD/ynjd.htm" frameborder="0" width=" ...

  4. 关于unitils联合dbunit的测试

    unitils据说测试的能力很强大,可测试dao,service,web层,其实对数据库的测试我更关心,看到有人展示了测试的方法,数据直接写在xls表中,很直观,然后就依照他们的方法进行试验,花费的时 ...

  5. 关于this

    一:全局环境中的this指的是window对象 二:作为对象的方法调用 当函数作为对象的方法被调用时,this指向该对象 例子: 三:作为普通方法调用 当函数不作为对象的属性被调用,而是作为普通函数函 ...

  6. [翻译]jQuery十周年-John Resig

    10th Anniversary of jQuery Today marks the 10th anniversary of the release of jQuery...[原文] 今天是jQuer ...

  7. C#☞软件设计模型_基础

    建模图有助于理解.阐明和传达代码的构思和软件系统必须支持的用户需求. 若要描述和传达用户需求,您可以使用统一建模语言 (UML) 用例图.活动图.类图和序列图. 若要描述和传达系统的功能,您可以使用 ...

  8. [r]Setting up Django and your web server with uWSGI and nginx

    Setting up Django and your web server with uWSGI and nginx This tutorial is aimed at the Django user ...

  9. Vue 2.0基础

    我们将会选择使用一些vue周边的库vue-cli, vue-router,vue-resource,vuex 1.使用vue-cli创建项目2.使用vue-router实现单页路由3.用vuex管理我 ...

  10. JS拖动div的原理

    要实现移动窗体,首先要捕获三个参数:1.a = 鼠标点击时的坐标.2.b = 被移动窗体的左顶点坐标.3.c = 鼠标移动时的坐标.然后还要算出你鼠标无论点击窗体哪个位置,移动改变的都是 (d = 窗 ...