編輯:關於Android編程
關於使用ViewPageIndicator和ViewPager實現Tab導航,在開發社區裡已經有一堆的博客對其進行了介紹,如果我還在這裡寫如何去實現,那簡直就是老生常談,毫無新鮮感,而且,我也不認為自己對ViewPageIndicator的理解會比別人好,畢竟我也是看著大神的帖子,在學習實踐著。
那我還寫這個有啥意義呢?其實麼,就是想在這裡記錄下,在使用ViewPageIndicator和ViewPager實現Tab導航時,大家有可能會遇到的坑。這個坑,需要我們開發時盡量去避免的。
啥?你問我為啥子知道有這些坑?
因為我剛剛遇到過,剛剛解決了,所以覺得分享經驗啦!
在介紹具體實現的代碼之前,我先介紹兩篇博客呗,畢竟我就是根據他們寫的來學習的。第一篇《Android 開源框架ViewPageIndicator 和 ViewPager 仿網易新聞客戶端Tab標簽》這篇博客對如何實現tab已經介紹的非常詳細了,包括如何去自定義tab樣式,請學習膜拜吧。。。如果你學習能力較差,那好吧,在慕課網航有個教學視頻,這可是鴻翔大神錄制的哦,4-1 ViewPagerIndicator與ViewPager實現Tab,如果你看了視頻還不會,那我,呵呵呵。。。
看過之前我推薦博客和視頻的人會問,在Eclipse中,我們直接引入ViewPageIndicator項目,再把就好了android-support-v4.jar 包進行下處理就好了。 那,如何在Android Studio中導入ViewPageIndicator項目呢?
好,我來告訴大家,請看下圖:
看到了吧,我們僅需要在此處搜索com.inkapplications.viewpageindicator,選中,點擊OK,gradle會自動幫我把改工程加載進來的。
讓我們看下子導入後,源碼在哪了:
當你需要修改資源文件的時候,可以直接在res目錄下的資源文件中進行修改,是不是很方便!!!
此刻有一點要記住,因為你改項目中已經引入了android-support-v4,所以你無需再引入其它的v4包,切記切記!!!
import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.lidroid.xutils.ViewUtils; public class FragmentStudy extends Fragment { private View view = null; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if(view==null){ view = inflater.inflate(R.layout.fragment_study, container, false); } ViewUtils.inject(this, view); return view; } }fragment_study.xml文件:
public class ProjectPagerAdapter extends FragmentPagerAdapter { private static String[] titles = {全部, 計劃中, 進行中, 已完成}; public ProjectPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { Fragment fragment = null; Bundle bundle = null; switch (position) { case 0: fragment = new FragmentStudy(); bundle = new Bundle(); bundle.putInt(pos, 0); fragment.setArguments(bundle); break; case 1: fragment = new FragmentStudy(); bundle = new Bundle(); bundle.putInt(pos, 1); fragment.setArguments(bundle); break; case 2: fragment = new FragmentStudy(); bundle = new Bundle(); bundle.putInt(pos, 2); fragment.setArguments(bundle); break; case 3: fragment = new FragmentStudy(); bundle = new Bundle(); bundle.putInt(pos, 3); fragment.setArguments(bundle); break; } return fragment; } @Override public int getCount() { return titles.length; } @Override public CharSequence getPageTitle(int position) { return titles[position]; } }
import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.view.ViewPager; import com.lidroid.xutils.ViewUtils; import com.lidroid.xutils.view.annotation.ViewInject; import com.viewpagerindicator.TabPageIndicator; public class MainActivity extends FragmentActivity { @ViewInject(R.id.tab_page_indicator) private TabPageIndicator tabPageIndicator; @ViewInject(R.id.study_viewpager) private ViewPager studyViewpager; private ProjectPagerAdapter mAdatpter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewUtils.inject(this); mAdatpter = new ProjectPagerAdapter(getSupportFragmentManager());// 此處,如果不是繼承的FragmentActivity,而是繼承的Fragment,則參數應該傳入getChildFragmentManager() studyViewpager.setAdapter(mAdatpter); tabPageIndicator.setViewPager(studyViewpager); } }
這樣,一個基本的頂部導航Tab就出來了,接下來,我們還可以定義tab的樣式,在style.xml文件中,我們添加:
好了,快來看下效果:
請千萬不要滿足,因為這個Tab還不穩定,它還有漏洞,下面我們來看下。
對於之前實現的tab導航,當我們來回切換tab時,會發現,系統會崩潰:
錯誤意思是,當切換tab回到已經加載過的Fragment時,系統不允許之前的Fragment在還未移除的情況下,再次加載該View,一個View只能有一個父控件。請仔細看我們FragmentStudy的代碼:
if(view==null){ view = inflater.inflate(R.layout.fragment_study, container, false); }
那該如何解決呢?
有人說好辦啊,把判斷view==null直接去掉不就好了。。。額,確實好了,但是你有沒有考慮每次都會創建新的view,浪費資源性能呢?
那如何是好呢?別急,有辦法,讓我們修改下代碼:
import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.lidroid.xutils.ViewUtils; public class FragmentStudy extends Fragment { private View view = null; @Override public void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); // pos = getArguments().getInt(pos); // System.out.println(pos); LayoutInflater inflater = getActivity().getLayoutInflater(); view = inflater.inflate(R.layout.fragment_study, (ViewGroup) getActivity().findViewById(R.id.study_viewpager), false); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // if(view==null){ // view = inflater.inflate(R.layout.fragment_study, container, false); // } // 這句話必須加 ViewGroup p = (ViewGroup) view.getParent(); if (p != null) { p.removeAllViewsInLayout(); } ViewUtils.inject(this, view); return view; } }有沒有發現啥? 沒錯,我們把加載布局文件創建View的過程,放在了onCreate()方法中,即只在第一次創建該Fragment時加載布局,之後切換時,都不會再加載布局了。
美哉啊!!!
在運行下該項目,發現是不是不會再崩潰了?!
不知道大家知不知道,ViewPager有個功能,也被成為ViewPager的一個好處,就是它可以預加載Fragment。可是如果我在每個Fragment中都有網絡請求,豈不是加載一個Fragment發送了多個請求?這種體驗可是不好的。有沒有辦法改呢?
有人說,那不簡單啊,設置ViewPager不去預加載不就好了!
對,就這麼簡單,ViewPager確實提供了相應的方法,去設置預加載Fragment的數量:
通過ViewPager的setOffscreenPageLimit(int pagenum)來設置,默認情況下參數是1,比如viewPager.setOffscreenPageLimit(2)會預加載2個頁面,viewPager.setOffscreenPageLimit(0)會不預加載頁面。
可是,尼瑪,操蛋的事來了,我嘗試了,viewPager.setOffscreenPageLimit(0)這個方法根本沒有用啊,真讓我抓狂。
該咋辦?
google了一下,還真讓我找到了方法,重寫Fragment的setUserVisibleHint方法:
// 使用fragment+viewpage時會發現設置setOffscreenPageLimit(0)不預加載頁面不管用, // 可以用下邊的方法代替,下邊的方法是在子頁面(也就是fragment中)復寫下邊的方法,根據fragment是否可見來判斷是否是當前頁面,然後執行網絡加載數據 @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isVisibleToUser) { //fragment可見時執行加載數據或者進度條等 qryDataFromServer(); } else { //不可見時不執行操作 } } private void qryDataFromServer() { System.out.println(第+pos + 個Fragment is qryDataFromServer); }
I/System.out﹕ 第0個Fragment is qryDataFromServer I/System.out﹕ 第1個Fragment is qryDataFromServer I/System.out﹕ 第2個Fragment is qryDataFromServer I/System.out﹕ 第3個Fragment is qryDataFromServer I/System.out﹕ 第2個Fragment is qryDataFromServer I/System.out﹕ 第1個Fragment is qryDataFromServer I/System.out﹕ 第0個Fragment is qryDataFromServer
相信看到這裡,大家已經能夠掌握如何使用TabPageIndicator和ViewPager開發一個比較完美的頂部導航欄了,其實,TabPageIndicator使用並不難,最重要的還是去避免上文中提到的幾個坑,這樣才會有較快的開發效率!
前言上篇文章介紹了單Activity多Fragment模式去構建一個項目的簡單框架,這種模式可以帶給我們諸多好處。本篇我將在上一篇那個模式的基礎上對這個app裡面的一些類
可以達到的效果 第一個圖片的位置放照相機,點擊打開照相機 其余的是顯示全部存儲的圖片,點擊一次是查看大圖,長按則是每張圖片出現一個checkBox,可以進行選擇 下
一、使用PULL解析XML 1.PULL簡介 我曾在《淺談XMl解析的幾種方式》一文中介紹了使用DOM方式,SAX方式,Jdom方式,以及dom4j的方式來
在之前做的聯系人項目中,應用安裝完以後需要顯示數據庫中預存的數據,這時需要導入已有的數據庫contact.db。這也是一個面試題,那麼如何實現呢?首先在res中新建raw