閱讀89 返回首頁    go 阿裏雲 go 技術社區[雲棲]


使用ViewPager+Fragment來實現帶滾動條的多屏滑動-IndicatorFragmentActivity

轉載請注明出處:https://blog.csdn.net/singwhatiwanna/article/details/17201587

介紹

在android應用中,多屏滑動是一種很常見的風格,博主之前也寫過一些多屏滑動的demo,比如滾動banner(https://blog.csdn.net/singwhatiwanna/article/details/8875241)和仿tabhost的控件。這次給大家介紹一種效果更好的風格:帶滾動條的多屏滑動,類似於google play裏麵的風格。如果你看過我之前寫的banner,你就會發現那個banner是原生的,沒有采用viewpager啥的,所以代碼很長,如果采用ViewPager,代碼就會短很多,但是使用ViewPager也有弊端:需要導入android-support-v4.jar、細節無法控製。不過現在情況已經不一樣了,android-support-v4中提供了很多實用的功能,以至於現在新建一個android工程默認都會導入這個jar包。那我們就也采用viewpager來做滑動吧。另外一個概念就是Fragment和FragmentActivity,Fragment是一個特殊的類,有著和activity一致的生命周期和view一致的界麵,也就是Fragment就等於具有生命周期的View,但是,要注意的是:Fragment並不是View,它和View沒有繼承關係。使用Fragment的好處是:Fragment可以重用,而且每個Fragment可以在內部處理自己的業務就像activity一樣,這樣模塊間耦合較低,比把所有的業務都寫在一個activity內部邏輯要清晰很多。還有就是,由於每個模塊的業務都在Fragment內部來實現,這樣activity隻要管理好幾個Fragment就行了,不需要做和業務相關的事情,最後,Fragment可以用來做不同分辨率機型的適配。Fragment在sdk(android 3.0及更高)和android-support-v4裏麵都有,但是由於兼容性的問題,我們隻能使用android-support-v4裏麵的Fragment,除非你想你的apk隻跑在3.0以後的android手機上,FragmentActivity的情況和Fragment類似。關於Fragment和FragmentActivity,其實有一些基本的用法需要了解一下,但是考慮到Fragment不是本文的重點,所以這裏就不介紹了,另外,本文隻用Fragment做了一個簡單的界麵,大家應該一看就懂,好了,言歸正傳。

IndicatorFragmentActivity的實現過程

1 新建一個工程,目錄結構如下:


2 實現ui包下的三個文件

ViewPagerCompat.java:這是一個ViewPager的加強類,主要是為了解決滑動衝突的問題。不然的話,在ViewPager內部加入ListView等可滑動控件,兩者之間會產生幹擾。

在這裏想多說一下,關於此類問題,解決辦法是:重寫父控件的onInterceptTouchEvent函數,在move的時候根據需要返回true,比如左右滑動返回true,其他情況均返回false。這樣,當左右滑動的時候,由於onInterceptTouchEvent返回了true,父控件就能處理,其他情況,事件將傳遞到listview中,listview自身可以處理上下滑動。

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public class ViewPagerCompat extends ViewPager {  
  2.   
  3.     //mViewTouchMode表示ViewPager是否全權控製滑動事件,默認為false,即不控製  
  4.     private boolean mViewTouchMode = false;  
  5.   
  6.     public ViewPagerCompat(Context context, AttributeSet attrs) {  
  7.         super(context, attrs);  
  8.     }  
  9.   
  10.     public void setViewTouchMode(boolean b) {  
  11.         if (b && !isFakeDragging()) {  
  12.             //全權控製滑動事件  
  13.             beginFakeDrag();  
  14.         } else if (!b && isFakeDragging()) {  
  15.             //終止控製滑動事件  
  16.             endFakeDrag();  
  17.         }  
  18.         mViewTouchMode = b;  
  19.     }  
  20.   
  21.     /** 
  22.      * 在mViewTouchMode為true的時候,ViewPager不攔截點擊事件,點擊事件將由子View處理 
  23.      */  
  24.     @Override  
  25.     public boolean onInterceptTouchEvent(MotionEvent event) {  
  26.         if (mViewTouchMode) {  
  27.             return false;  
  28.         }  
  29.         return super.onInterceptTouchEvent(event);  
  30.     }  
  31.   
  32.     @Override  
  33.     public boolean onTouchEvent(MotionEvent ev) {  
  34.         try {  
  35.             return super.onTouchEvent(ev);  
  36.         } catch (Exception e) {  
  37.             return false;  
  38.         }  
  39.     }  
  40.   
  41.     /** 
  42.      * 在mViewTouchMode為true或者滑動方向不是左右的時候,ViewPager將放棄控製點擊事件, 
  43.      * 這樣做有利於在ViewPager中加入ListView等可以滑動的控件,否則兩者之間的滑動將會有衝突 
  44.      */  
  45.     @Override  
  46.     public boolean arrowScroll(int direction) {  
  47.         if (mViewTouchMode) return false;  
  48.         if (direction != FOCUS_LEFT && direction != FOCUS_RIGHT) return false;  
  49.         return super.arrowScroll(direction);  
  50.     }  
  51.   
  52. }  

下麵兩個文件代碼有點多,沒有粘出來,後麵附有下載地址,大家可以下載下來看看,代碼都做了注釋的。有什麼疑問歡迎交流。

TitleIndicator.java:這個一個帶滾動條的選項卡,會隨著viewpager的滑動而滑動,其實現思想是這樣的:每個選項卡是一個view,根據需要可以add多個view也就是多個選項卡進來,選項卡下部還有一個滾動條,滾動條是用canvas畫出來的。所有的invalidate方法均會觸發onDraw,當頁麵滾動的時候,會有一個滾動距離,然後onDraw被觸發後,就會在新位置重新畫上滾動條(其實就是畫線)。

IndicatorFragmentActivity.java:這是IndicatorFragmentActivity的主界麵,用於管理上述兩個view,對子類提供protected abstract int supplyTabs(List<TabInfo> tabs)接口來生成頁麵。

下麵主要介紹下如何使用這個IndicatorFragmentActivity。


如何使用?

請按如下步驟:

1 新建一個類繼承IndicatorFragmentActivity,然後實現supplyTabs抽象方法,提供生成選項卡所需的數據

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public class MainActivity extends IndicatorFragmentActivity {  
  2.   
  3.     public static final int FRAGMENT_ONE = 0;  
  4.     public static final int FRAGMENT_TWO = 1;  
  5.     public static final int FRAGMENT_THREE = 2;  
  6.   
  7.     @Override  
  8.     protected void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.     }  
  11.   
  12.     //在這裏提供數據來進行初始化  
  13.     @Override  
  14.     protected int supplyTabs(List<TabInfo> tabs) {  
  15.         tabs.add(new TabInfo(FRAGMENT_ONE, getString(R.string.fragment_one),  
  16.                 FragmentOne.class));  
  17.         tabs.add(new TabInfo(FRAGMENT_TWO, getString(R.string.fragment_two),  
  18.                 FragmentTwo.class));  
  19.         tabs.add(new TabInfo(FRAGMENT_THREE, getString(R.string.fragment_three),  
  20.                 FragmentThree.class));  
  21.   
  22.         //返回的下標表示界麵初始化的時候所指向的fragment的序號  
  23.         return FRAGMENT_TWO;  
  24.     }  
  25.   
  26. }  

2 為每個選項卡提供fragment類

最簡單的fragment,啥都不做,就加載一個layout然後初始化一個listview。其實我的demo裏有3個界麵一樣的fragment,但是博主為了偷懶,直接寫了一個BaseFragment,讓它們3個都繼承這個BaseFragment,反正界麵都一樣嘛。

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public class BaseFragment extends Fragment {  
  2.     protected View mMainView;  
  3.     protected static ArrayList<Map<String, Object>> mlistItems;  
  4.     protected Context mContext;  
  5.   
  6.     static {  
  7.         mlistItems = new ArrayList<Map<String, Object>>();  
  8.         for (int i = 0; i < 20; i++) {  
  9.             Map<String, Object> map = new HashMap<String, Object>();  
  10.             map.put("name""name#" + i);  
  11.             map.put("sex", i % 2 == 0 ? "male" : "female");  
  12.             mlistItems.add(map);  
  13.         }  
  14.     }  
  15.   
  16.     public BaseFragment() {  
  17.         super();  
  18.     }  
  19.   
  20.     @Override  
  21.     public void onAttach(Activity activity) {  
  22.         super.onAttach(activity);  
  23.         mContext = activity.getApplicationContext();  
  24.     }  
  25.   
  26.     @Override  
  27.     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
  28.         mMainView = inflater.inflate(R.layout.fragment_one, container, false);  
  29.         ListView listView = (ListView) mMainView.findViewById(R.id.list);  
  30.         SimpleAdapter adapter = new SimpleAdapter(mContext, mlistItems,  
  31.                 R.layout.listview_item, new String[] {  
  32.                         "name""sex"  
  33.                 }, new int[] {  
  34.                         R.id.name, R.id.download  
  35.                 });  
  36.         listView.setAdapter(adapter);  
  37.         return mMainView;  
  38.     }  
  39.   
  40. }  

這樣就ok了,是不是挺簡單的,也就是說,如果你想要這種效果的話,隻要導入ui包裏麵的3個類,然後再按上述2個步驟去做就行了,效果也是很好的。另外就是選項卡的顏色以及滾動條的顏色都是可以調的,而且每個選項卡上麵是支持顯示其他標識的,比如一個小紅點啥的,就類似於那種有新消息的狀態。有什麼問題,歡迎大家在下麵留言和我交流。



代碼下載:https://download.csdn.net/detail/singwhatiwanna/6680173

最後更新:2017-04-03 12:55:33

  上一篇:go linux文件係統(四)——軟連接與硬連接
  下一篇:go C# 係統應用之透明罩MyOpaqueLayer實現360界麵陰影效果