slidingmenu+fragment實現常用的側滑效果(包括Fragment狀態的儲存)

來源:互聯網
上載者:User

一、需求

關於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;}@Overridepublic 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);}/** * 點擊導覽列切換 同時更改標題 */@Overridepublic 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;@Overridepublic void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);initFragment();}private void initFragment() {SlidingMenu mSlidingMenu = getSlidingMenu();wechatFragment = new WechatFragment();getSupportFragmentManager().beginTransaction().replace(R.id.center_frame, wechatFragment).commit();setBehindContentView(R.layout.frame_navi); // 給滑出的slidingmenu的fragment制定layoutnaviFragment = new NaviFragment();getSupportFragmentManager().beginTransaction().replace(R.id.frame_navi, naviFragment).commit();// 設定slidingmenu的屬性mSlidingMenu.setMode(SlidingMenu.LEFT);// 設定slidingmeni從哪側出現mSlidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN);// 只有在邊上才可以開啟mSlidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);//全屏都可以開啟mSlidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_NONE);//不可以通過滑動開啟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() {@Overridepublic void onOpen() {}});// 導航關閉監聽事件mSlidingMenu.setOnClosedListener(new OnClosedListener() {@Overridepublic void onClosed() {}});}}



4.接下來是幾個Fragment介面的實現,這幾個介面就是實際開發中最主要的幾個介面。

fragment的生命週期不同於activity,但是非常類似,有興趣的同學可以去研究一下,這裡就不列出了。其中的oncreatview是用來載入介面的,返回值view就是要顯示的view。

例如我們的首頁,wechatfragment

public class WechatFragment extends Fragment {@Overridepublic void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// TODO Auto-generated method stubreturn super.onCreateView(inflater, container, savedInstanceState);}}
未完待續。。。。。。














聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.