編輯:關於Android編程
最近在工作中由於需要客制化系統的關系,接觸到了很多ViewPager相關的UI,發現很多底層原生的界面也還是依然采用ViewPager+Fragment的布局方式,事實上這依然還是主流,微信5.0到6.0等還是采用這種布局方法,所以還是有必要總結下ViewPager的相關知識,增強下記憶和理解,畢竟伴隨著經驗的提升即使再去閱讀同一本書也會有不一樣的體會。
ViewPager繼承自ViewGroup,是左右兩個屏幕平滑地切換的一個容器,容器裡呈現的視圖由對應的Adapter決定,和其他標准的AdapterView類似。簡而言之就是我們通過Adapter把View放到ViewPager裡,動動手指我們就可以實現左右滑動互相切換View了。另外ViewPager的更新不是直接由ViewPager本身去完成的,而是通過觀察者去調用PagerAdapter的notifyDataSetChanged等相關方法去完成界面更新工作。
PagerAdapter其實是一個抽象類封裝了一些接口、回調和功能方法,在實際開發過程中我們往往是使用它及其子類——FragmentPagerAdapter和FragmentStatePagerAdapter的子類來填充到ViewPager中,通俗點來說,ViewPager只是個空皮囊,只有填充了PagerAdapter才能發揮其作用,正所謂巧婦也難為無米之炊,PagerAdapter就是這裡的米,有了米才能各顯神通做出各種各樣的飯。
ViewPager不是直接與View關聯的,而是通過一個key對象,通過這個key對象我們可以追蹤並且唯一識別指定的page在PagerAdapter的位置。
Object instantiateItem(ViewGroup container, int position)——實例化item,PagerAdapter將選擇將這個對象填充到在當前ViewPager裡。
void destroyItem(ViewGroup container, int position, Object object)——將item從指定的位置移出容器
int getCount()——獲取item的總數,一般都是獲取集合的size
isViewFromObject(View,Object)——判斷容器裡的View是否與一個key值相關聯,比如說例如Fragment+ViewPager的處理,每個頁面都由它是對應的Fragment來呈現,但ViewPager並不是直接與View關聯,而是關聯一個key。我們實現這個方法也很簡單谷歌推薦我們只需一句——return view == object;。
public class ViewPagerAdapter extends PagerAdapter { private ListmList; public ViewPagerAdapter(List list) { this.mList = list; } @Override public int getCount() { if (mList != null && mList.size() > 0) { return mList.size(); } else { return 0; } } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(mList.get(position)); return mList.get(position); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } }
PagerAdapter的工作過程其實很簡單,當ViewPager裡的內容要改變的時候,就調用startUpdate方法來完成,隨即也會多次調用instantiateItem或者destroyItem方法,finishUpdate最後被調用來完成更新工作。finishUpdate最終會返回需要添加到容器裡的View和對應的 key對象(通過instantiateItem完成);而一些傳遞到destroyItem的則被移除。
FragmentPagerAdapter繼承自PagerAdapter,主要的成員方法功能都是大同小異的,這個適配器主要就是用於快速實現Fragment在ViewPager裡面進行滑動切換的,所以,如果我們想實現Fragment的左右滑動,優先選擇ViewPager+FragmentPagerAdapter模式,因為FragmentPagerAdapter擁有自己的緩存策略,當配合ViewPager配合使用時,會緩存當前Fragment以及左邊一個、右邊一個(一共三個Fragment對象)假設有三個Fragment,那麼在ViewPager初始化之後,3個fragment都會加載完成,中間的Fragment在整個生命周期裡面只會加載一次,當最左邊的Fragment處於顯示狀態,最右邊的Fragment由於超出緩存范圍,會被銷毀,當再次滑到中間的Fragment的時候,最右邊的Fragment會被再次初始化。所以比較適合用戶制作較少頁面切換的tab界面(最多3個),FragmentPagerAdapter會對我們浏覽過Fragment進行緩存,保存這些界面的臨時狀態,這樣當我們左右滑動的時候,界面切換更加的流暢。但是,這樣也會增加程序占用的內存。那麼3個以上的話,谷歌推薦移步到FragmentStatePagerAdapter。
getCount()——返回的是ViewPager頁面的數量,即Fragement的數量。
getItem(int position)——返回的是要顯示的fragment對象。
//實現一個FragmentPagerAdapter最少只需要實現getCount和getItem方法即可 FragmentPagerAdapter fragmentadapter = new FragmentPagerAdapter( getSupportFragmentManager()) { @Override public int getCount() { return fragments.size(); //getCount()返回的是ViewPager頁面的數量,多少個Fragement對應多少個頁面 } @Override public Fragment getItem(int position) { return fragments.get(position);//返回的是要顯示的fragment對象。 } } };
當然除了FragmentPagerAdapter之外,還有一個類也是專門用於快速實現多個(3個以上)Fragment在ViewPager裡面進行適配並滑動切換的,即FragmentStatePagerAdapter。FragmentStatePagerAdapter也直接繼承自PagerAdapter的,其工作方式和ListView十分相似的。當Fragment對用戶不可見的時候,整個Fragment會被銷毀並且保存Fragment的保存狀態。基於這樣的特性,FragmentStatePagerAdapter比FragmentPagerAdapter更適合用於很多界面之間的轉換,而且消耗更少的內存資源。
getCount()——返回的是ViewPager頁面的數量,即Fragement的數量。
getItem(int position)——返回的是要顯示的fragment對象。
通常情況下調用notifyDataSetChanged方法會讓ViewPager通過Adapter的getItemPosition方法查詢一遍所有child view,如果所有child view位置均為POSITION_NONE,表示所有的child view都不存在,ViewPager會調用destroyItem方法銷毀,並且重新生成,從而加大系統開銷,並在一些復雜情況下導致邏輯問題。特別是對於只是希望更新child view內容的時候,但造成了完全不必要的開銷,
列表內容如果是針對於child view比較簡單的情況(例如僅有TextView、ImageView等,沒有ListView等展示數據的情況),可以重寫PagerAdapter的方法getItemPosition@Override public int getItemPosition(Object object) { return POSITION_NONE; }但復雜的情況則需要根據自己的需求來實現notifyDataSetChanged的功能,比如,在僅需要對某個View內容進行更新時,在instantiateItem()時,用View.setTag方法加入標志,在需要更新信息時,通過findViewWithTag的方法找到對應的View進行局部更新。
FragmentPagerAdapter適合在較少Fragment滑動切換的界面使用的,劃過的fragment會保存在內存中,盡管已經劃過。而FragmentStatePagerAdapter和ListView有點類似,只會保存當前界面,以及下一個界面和上一個界面(如果有),最多保存3個,其他會被銷毀掉。最後要注意的是FragmentStatePagerAdapter可能不經意間會造成內存未正常回收,嚴重導致內存溢出,比如圖片資源沒有釋放,資源引用問題。(之前在網上看到過EditText由於保存焦點導致Fragment未被釋放而導致OOM,設置edtText.saveEanble(false)就可以解決此問題)。最後PagerAdapter都只是數據集,數據集的改變只能發生在主線程裡並且以必須調用notifyDataSetChanged() 來通知完成更新。
這篇主要是簡單描述了下ViewPager的主要功能以及PagerAdapter的角色和一些簡略的原理,由於篇幅問題,下一篇再結合實例來總結下。
首先看效果下拉刷新: 上劃加載 在項目更新的過程中,遇到了一個將XListView換成recyclerView的需求,而且更換完之後大體效果不能變,但是對於下拉刷新這樣的
Android資源文件分類:Android資源文件大致可以分為兩種:第一種是res目錄下存放的可編譯的資源文件:這種資源文件系統會在R.java裡面自動生成該資源文件的I
一、Git 與GitHub這裡首先介紹下Git與GitHub是什麼東西,他們之間有何區別呢?Git :分布式版本控制系統,最初用在Linux上,可以和SVN、CVS等作為
概述整個View樹的繪圖流程是在ViewRoot.java類的performTraversals()函數展開的,該函數做的執行過程可簡單概況為:- 判斷是否需要重新計算視