Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android之ActionBar、Tabs、Fragment、ViewPager實現標簽頁切換並緩存頁面

Android之ActionBar、Tabs、Fragment、ViewPager實現標簽頁切換並緩存頁面

編輯:關於Android編程

感覺 Android 到處都是坑,每個地方都要把人折騰半天。

今天來簡單說說 Android之ActionBar、Tabs、Fragment、ViewPager 實現標簽頁切換並緩存頁面

關於他們的介紹就不多說了,網上到處都是,只說關鍵的部分:

我在開發的時候遇到幾個疑難問題,花費大量時間處理,總結如下:

1. 關於 Fragment 內部邏輯處理該寫在哪個事件回調部分?

2. ViewPager 頁面切換動畫卡頓,讓我頭疼了很久。

3. ViewPager 中如何保存 Fragment 當前視圖的狀態,讓 Tabs 頁面切換後不會重新加載,這地方很坑爹

4. ActionBar 中的 tab 很多時如何滾動顯示


解答:

一、Fragment 的事件回調:

package com.ai9475.meitian.ui.fragment;

import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;

import com.ai9475.meitian.R;
import com.ai9475.meitian.view.DiaryList;
import com.ai9475.util.ZLog;

/**
 *
 * Created by ZHOUZ on 14-1-21.
 */
public class DiaryListFragment extends BaseFragment
{
    private static final String TAG = "DiaryListFragment";

    @Override
    public void onAttach(Activity activity)
    {
        ZLog.i(TAG, "onAttach");
        super.onAttach(activity);
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        ZLog.i(TAG, "onCreate");
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        ZLog.i(TAG, "onCreateView");
        return inflater.inflate(R.layout.fragment_diary_list, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState)
    {
        ZLog.i(TAG, "onActivityCreated");
        super.onActivityCreated(savedInstanceState);
        ZLog.i(TAG, "DiaryList0");
        DiaryList diaryList = new DiaryList(
                getActivity().getApplicationContext(),
                (ListView) getView().findViewById(R.id.diaryListCt)

        );
        ZLog.i(TAG, "DiaryList load0");
        diaryList.load("http://m.ai9475.com/?con=meitian_app");
        this.setRetainInstance(true);
    }

    @Override
    public void onStart()
    {
        ZLog.i(TAG, "onStart");
        super.onStart();
    }

    @Override
    public void onResume()
    {
        ZLog.i(TAG, "onResume");
        super.onResume();
    }

    @Override
    public void onPause()
    {
        ZLog.i(TAG, "onPause");
        super.onPause();
    }

    @Override
    public void onStop()
    {
        ZLog.i(TAG, "onStop");
        super.onStop();
    }

    @Override
    public void onDestroyView()
    {
        ZLog.i(TAG, "onDestroyView");
        super.onDestroyView();
    }

    @Override
    public void onDestroy()
    {
        ZLog.i(TAG, "onDestroy");
        super.onDestroy();
    }

    @Override
    public void onDetach()
    {
        ZLog.i(TAG, "onDetach");
        super.onDetach();
    }
}

上面的類中的 on 事件就是Fragment主要處理的時間回調,注意復寫父類方法時要回調執行父類同名方法,否則會出錯

主要復寫 onCreateView 方法,返回該 Fragment 所對應的視圖對象,這裡可以在返回視圖對象前進行一些簡單的配置,但千萬不要寫太耗時的處理阻塞UI主線程。

另外 onActivityCreated 方法,是當 activity 的 onCreate 事件結束時的回調,此時當前的Fragment對應的view已經並入到整個布局中,此時可以使用 getView() 方法獲取視圖對象。

其他幾個事件沒什麼太多可說,有些我也還不是太清楚,還有些動畫調用的事件。


二、切換頁面卡頓問題

這個問題的產生主要可能是兩方面,

1. 沒有使用 ViewPager 的緩存,每次切換都重新加載。

2. 加載 Fragment 內部有耗時耗資源的邏輯處理。

這裡主要說下第二種情況,我一開始沒處理掉 緩存問題時有一個解決辦法,

    
    

mViewPager = (ViewPager) findViewById(R.id.tabsViewPager);
mViewPager.setOnPageChangeListener(
                new ViewPager.SimpleOnPageChangeListener() {
                    private static final String TAG = "ViewPager.SimpleOnPageChangeListener";
                    private ArrayList hasLoadedPages = new ArrayList();
                    @Override
                    public void onPageSelected(int position) {
                        ZLog.i(TAG, "onPageSelected position:"+ position);
                        getSupportActionBar().setSelectedNavigationItem(position);
                    }

                    @Override
                    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
                    {
                        ZLog.i(TAG, "onPageScrolled position: "+ position +", positionOffset:"+ positionOffset +", positionOffsetPixels:"+ positionOffsetPixels);
                    }

                    @Override
                    public void onPageScrollStateChanged(int state) {
                        ZLog.i(TAG, "onPageScrollStateChanged");
                        int position = mViewPager.getCurrentItem();

                        switch (state) {
                            // 正在拖動
                            case ViewPager.SCROLL_STATE_DRAGGING :
                                ZLog.i(TAG, "ViewPager.SCROLL_STATE_DRAGGING position:"+ position);
                                break;
                            // 拖動釋放後正在沉降的過程
                            case ViewPager.SCROLL_STATE_SETTLING :
                                ZLog.i(TAG, "ViewPager.SCROLL_STATE_SETTLING position:"+ position);
                                break;
                            // 切換動畫全部完成結束
                            case ViewPager.SCROLL_STATE_IDLE :
                                ZLog.i(TAG, "ViewPager.SCROLL_STATE_IDLE position:"+ position);
				// 已加載過則不再加載
                                if (hasLoadedPages.contains(position)) break;
                                Fragment fragment = mPager.getFragments().get(position);
                                runCallback(position, fragment);
                                hasLoadedPages.add(position);
                                break;
                        }
                    }

                    public void runCallback(int position, Fragment fragment) {
                        ZLog.i(TAG, "runCallback");
                        DiaryList diaryList;
                        switch (position) {
                            case 0 :
                                ZLog.i(TAG, "DiaryList0");
                                diaryList = new DiaryList(
                                        getApplicationContext(),
                                        (ListView) fragment.getView().findViewById(R.id.diaryListCt)

                                );
                                ZLog.i(TAG, "DiaryList load0");
                                diaryList.load("http://m.ai9475.com/?con=meitian_app");
                                break;
                            case 1:
                                ZLog.i(TAG, "DiaryList1");
                                diaryList = new DiaryList(
                                        getApplicationContext(),
                                        (ListView) fragment.getView().findViewById(R.id.diaryListCt)

                                );
                                ZLog.i(TAG, "DiaryList load1");
                                diaryList.load("http://m.ai9475.com/?con=meitian_app&act=hot");
                                break;
                            case 2:
                                ZLog.i(TAG, "DiaryList2");
                                diaryList = new DiaryList(
                                        getApplicationContext(),
                                        (ListView) fragment.getView().findViewById(R.id.diaryListCt)

                                );
                                ZLog.i(TAG, "DiaryList load2");
                                diaryList.load("http://m.ai9475.com/?con=meitian_app");
                                break;
                        }
                    }
                }

這裡主要用到 public void onPageScrollStateChanged(int state) 頁面滾動切換狀態變化的事件監聽

當滾動動畫完全結束 case ViewPager.SCROLL_STATE_IDLE 時再執行 Fragment 的邏輯處理,這樣動畫就會流暢了。

但經過後來的測試發現有個很簡單的解決方案,就是下面要說到的 ViewPager 的緩存功能,其實很簡單。


三、緩存 Tabs 頁面切換不重新加載數據

我在這地方折騰的最久,而且很多時候無從下手的感覺,網上搜索了很多文章都有說道保存 Fragment 數據和狀態,但是沒有整整提到如何來保存他的當前view狀態,不知道如何保存,當然實際上我還是沒搞懂如何僅僅緩存 Fragment 的狀態,但對於 ViewPager 緩存 Tab 對應的 Fragment 還是找到了辦法,之前花了很大功夫來自己實現,後來偶然發現他居然有個自帶的方法

        // 設置緩存多少個 Tab對應的 fragment
        mViewPager.setOffscreenPageLimit(6);

我測試時用了 6個 listView 加載圖片列表數據,切換動畫也沒有任何卡頓現象,非常流暢,就這麼簡單一句就搞定了。

配置該項後,ViewPager在切換時將不會清理不可見的 Fragment,不會觸發 Fragment 的任何事件,因此也就不會導致其重新加載。


四、ActionBar 中的 Tabs

這個其實不用操作,在tabs數量超過一屏後,例如我現在設置6個寬度超過了屏幕則會變成可以橫向滾動的狀態,而不需要自己實現,之前不知道在這方面查了很多資料都無果,只知道可以用 tabhost 可以實現,但在ActionBar 裡面卻又用不了,自己試了下方多個tab才發現原來會自動實現,無語。


\


還是貼上 MainActivity.class 完整代碼:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PC9wPgo8cHJlIGNsYXNzPQ=="brush:java;">package com.ai9475.meitian.ui; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBar; import android.view.Menu; import android.widget.ListView; import com.ai9475.meitian.AppManager; import com.ai9475.meitian.R; import com.ai9475.meitian.ui.fragment.DiaryListFragment; import com.ai9475.meitian.ui.fragment.Test2Fragment; import com.ai9475.meitian.ui.fragment.Test3Fragment; import com.ai9475.meitian.view.DiaryList; import com.ai9475.util.ZLog; import java.util.ArrayList; public class MainActivity extends BaseActivity { private static final String TAG = "MainActivity"; private MyTabsPagerAdapter mPager; private ViewPager mViewPager; @Override protected void onCreate(Bundle savedInstanceState) { ZLog.i(TAG, "start"); // 執行父級初始化方法 super.onCreate(savedInstanceState); //requestWindowFeature(Window.FEATURE_NO_TITLE); ZLog.i(TAG, "setContentView"); setContentView(R.layout.activity_main); // 滑動頁面視圖配置 ZLog.i(TAG, "MyTabsPagerAdapter start"); mPager = new MyTabsPagerAdapter(getSupportFragmentManager()); mPager.getFragments().add(new DiaryListFragment()); mPager.getFragments().add(new Test2Fragment()); mPager.getFragments().add(new Test3Fragment()); mPager.getFragments().add(new Test3Fragment()); mPager.getFragments().add(new Test3Fragment()); mPager.getFragments().add(new Test3Fragment()); // 滑動分頁容器 mViewPager = (ViewPager) findViewById(R.id.tabsViewPager); // 設置緩存多少個 fragment mViewPager.setOffscreenPageLimit(6); mViewPager.setAdapter(mPager); // 頁面滑動事件 mViewPager.setOnPageChangeListener( new ViewPager.SimpleOnPageChangeListener() { private static final String TAG = "ViewPager.SimpleOnPageChangeListener"; private ArrayList hasLoadedPages = new ArrayList(); @Override public void onPageSelected(int position) { ZLog.i(TAG, "onPageSelected position:"+ position); getSupportActionBar().setSelectedNavigationItem(position); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { ZLog.i(TAG, "onPageScrolled position: "+ position +", positionOffset:"+ positionOffset +", positionOffsetPixels:"+ positionOffsetPixels); } @Override public void onPageScrollStateChanged(int state) { ZLog.i(TAG, "onPageScrollStateChanged"); int position = mViewPager.getCurrentItem(); switch (state) { // 正在拖動 case ViewPager.SCROLL_STATE_DRAGGING : ZLog.i(TAG, "ViewPager.SCROLL_STATE_DRAGGING position:"+ position); break; // 拖動釋放後正在沉降的過程 case ViewPager.SCROLL_STATE_SETTLING : ZLog.i(TAG, "ViewPager.SCROLL_STATE_SETTLING position:"+ position); break; // 切換動畫全部完成結束 case ViewPager.SCROLL_STATE_IDLE : ZLog.i(TAG, "ViewPager.SCROLL_STATE_IDLE position:"+ position); /*if (hasLoadedPages.contains(position)) break; Fragment fragment = mPager.getFragments().get(position); runCallback(position, fragment); hasLoadedPages.add(position);*/ break; } } public void runCallback(int position, Fragment fragment) { ZLog.i(TAG, "runCallback"); DiaryList diaryList; switch (position) { case 0 : ZLog.i(TAG, "DiaryList0"); diaryList = new DiaryList( getApplicationContext(), (ListView) fragment.getView().findViewById(R.id.diaryListCt) ); ZLog.i(TAG, "DiaryList load0"); diaryList.load("http://m.ai9475.com/?con=meitian_app"); break; case 1: ZLog.i(TAG, "DiaryList1"); diaryList = new DiaryList( getApplicationContext(), (ListView) fragment.getView().findViewById(R.id.diaryListCt) ); ZLog.i(TAG, "DiaryList load1"); diaryList.load("http://m.ai9475.com/?con=meitian_app&act=hot"); break; case 2: ZLog.i(TAG, "DiaryList2"); diaryList = new DiaryList( getApplicationContext(), (ListView) fragment.getView().findViewById(R.id.diaryListCt) ); ZLog.i(TAG, "DiaryList load2"); diaryList.load("http://m.ai9475.com/?con=meitian_app"); break; } } } ); ActionBar actionBar = getSupportActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // Tab 頁面切換 MyTabListener listener = new MyTabListener(); // 默認的首頁 tab ActionBar.Tab indexTab = actionBar.newTab() .setText(getString(R.string.tab_index)) .setTabListener(listener); actionBar.addTab(indexTab); actionBar.addTab(actionBar.newTab() .setText(getString(R.string.tab_hot)) .setTabListener(listener) ); actionBar.addTab(actionBar.newTab() .setText(getString(R.string.tab_tag)) .setTabListener(listener) ); actionBar.addTab(actionBar.newTab() .setText(getString(R.string.tab_tag)) .setTabListener(listener) ); actionBar.addTab(actionBar.newTab() .setText(getString(R.string.tab_tag)) .setTabListener(listener) ); actionBar.addTab(actionBar.newTab() .setText(getString(R.string.tab_tag)) .setTabListener(listener) ); // 顯示首頁 indexTab.select(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } private class MyTabListener implements ActionBar.TabListener { @Override public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { int position = tab.getPosition(); ZLog.i(TAG, "tab selected: "+ position); // 數據通信 /*Bundle bundle = new Bundle(); Fragment fragment = mPager.getItem(tab.getPosition()); Toast.makeText(getApplicationContext(), "position:"+ tab.getPosition(), Toast.LENGTH_SHORT).show(); fragment.setArguments(bundle); FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.add(R.id.fragmentContainer, fragment); fragmentTransaction.commit();*/ mViewPager.setCurrentItem(position); } @Override public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { ZLog.i(TAG, "tab reselected: "+ tab.getPosition()); } @Override public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { ZLog.i(TAG, "tab unselected: "+ tab.getPosition()); } }; public class MyTabsPagerAdapter extends FragmentPagerAdapter { private ArrayList mFragments = new ArrayList(); public MyTabsPagerAdapter(FragmentManager fm) { super(fm); } public ArrayList getFragments() { return this.mFragments; } @Override public Fragment getItem(int i) { return this.mFragments.get(i); } @Override public int getCount() { return this.mFragments.size(); } } }



  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved