一、需求

关于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. 使用require.js时,解决AMD封装jquery1.4.1的问题。

    require.config({ baseUrl: "js/", paths: { "jquery": "jquery-1.4.1.min" ...

  2. Mysql 目录恢复注意事项

    SET @mycnt=0; SELECT @mycnt := @mycnt +1 as mycnt, a.*, b.* FROM a, b; 表中第一列即为mycnt,从1开始计数. set @num ...

  3. call 方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法.

    call 方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法. 注意:该函数的语法与 apply() 方法的语法几乎完全相同,唯一的区别在于,apply()方法接受的是一个参 ...

  4. 用jQuery实现瀑布流效果学习笔记

    jQuery一直没系统的学,只知道是js库,封装了好多js函数,方便了开发.以前做过一个原生的图片网站瀑布流效果,超级麻烦,这次用了jQuery方法,瞬间代码浓缩了,只有56行js代码.神奇的让我来把 ...

  5. 学习WindowsPhone 2013/12/22

    菜鸟一枚,只能边看别人的博客变学习来提升自己,参考博客内容:http://blog.csdn.net/column/details/wp-comming.html?page=3 ,稍微看了一下,写的还 ...

  6. nginx 要改进的地方基础

  7. 删除svn文件

    删除svn文件 sudo find . -name ".DS_Store" -exec rm -r {} \; sudo find . -name ".git" ...

  8. +=与join的性能测试

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  9. hdu 5139 Formula

    http://acm.hdu.edu.cn/showproblem.php?pid=5139 思路:这道题要先找规律,f(n)=n!*(n-1)!*(n-2)!.....1!;  不能直接打表,而是离 ...

  10. Delphi控件的透明与不透明(要挨个解释一下原因),对InvalidateControl的关键理解

    procedure TForm1.Button3Click(Sender: TObject);begin if (csOpaque in ControlStyle) then ShowMessage( ...