ViewPager、Fragment、Matrix綜合使用實現Tab滑頁效果

原文地址:http://www.cnblogs.com/kross/p/3372987.htmlhtml

咱們實現一個上面是一個能夠左右滑動的頁面,下面是三個可點擊切換的tab按鈕,tab按鈕上還有一個激活條。效果以下圖所示:java

----------------我是分割線--------------------android

--------------------------我是分割線,下面的圖片表示往右滑動,白條中的小機器人往右滑動-------------------------數組

--------------------------我是分割線,切換到第二個頁面,tab中的第二個被激活,字呈白色-----------------------框架

------------------我是分割線-------------------dom

OK,效果就是如上所示的效果。如今開始一步一步的介紹如何實現。ide

1.建立好基礎的佈局文件。函數

整個頁面是一個LinearLayout,若是你用其餘的佈局也是能夠的,在下只是圖一個方便了。佈局

根據最終效果,咱們將整個佈局分爲三個部分:post

第一部分是上面那一大塊有顏色的區域,這是一個ViewPager,裏面的內容是經過Fragment加載進來的。

第二部分是那個在白條中間的小機器人這一塊,這個做爲激活條(本身編的名詞,就是表名當前的tab是被激活的),就是一個ImageView

第三部分是最底下的三個tab,是一個水平的LinearLayout,裏面每個tab都是ImageView+TextView構成的。

注意這裏tab這個佈局是被重複使用的,由於有三個嘛,爲了代碼重用,咱們可使用<include>標籤。

因此,咱們先寫好每一個小tab的佈局(/res/layout/tab.xml),代碼以下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical" >
    <ImageView
        android:id="@+id/tab_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@drawable/ic_launcher"/>
    <TextView
        android:id="@+id/tab_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/tab_text"
        android:gravity="center"
        android:textColor="#cccccc"/>
</LinearLayout>

爲了方便,就直接使用啓動圖標的圖片了,啊哈哈……啊哈哈哈……

接下來咱們去寫主體頁面的佈局(/res/layout/activity_main.xml),代碼以下:

注意<include>標籤的使用哦~

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >
    <!-- ViewPager的使用必須是完整的名字哦 -->
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1"/>
    <!-- 這是所謂的激活條,爲了方便,也直接使用啓動圖標的圖片了 -->
    <ImageView
        android:id="@+id/active_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="matrix"
        android:src="@drawable/ic_launcher"
        android:background="#ffffff"/>
    <!-- 下面的線性佈局是三個tab放置的區域 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <!-- 使用include標籤,能夠直接重用xml,這是我在《Android UI 基礎教程》中發現的~\(^o^)/~ -->
        <include
            android:id="@+id/tab1"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            layout="@layout/tab"/>
        <include
            android:id="@+id/tab2"
            android:layout_weight="1"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            layout="@layout/tab"/>
        <include
            android:id="@+id/tab3"
            android:layout_weight="1"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            layout="@layout/tab"/>
    </LinearLayout>
</LinearLayout>

OK,這樣咱們整個頁面的框架就有了。

 

2.給ViewPager添加頁面

OKOK,在這一步呢,咱們要作的是給ViewPager這個控件添加頁面,咱們從一開始就打算添加三個頁面的,因此上面纔有3個tab,若是你須要更多,都是同樣的道理。

ViewPager這個控件使用起來是很是方便的,在給它添加好頁面後,它自身能夠實現左右滑動切換的效果,很是滴好用啊。

ViewPager最重要的是給它設置適配器(setAdapter),咱們指望的結果是,每一個頁面裏,都有本身的控件,操做這些控件的方法均可以分別寫在各自的Fragment中,而不是所有都寫在MainActivity中。因此,咱們要讓ViewPager裏面裝載的是Fragment,所以,咱們須要去拓展(extends)一個FragmentPagerAdapter

實現FragmentPagerAdapter又須要事先準備好三個Fragment,三個Fragment又須要三個獨立的佈局。

所以咱們須要作的第一件事是準備三個咱們指望的佈局。

爲了簡單起見,咱們準備layout一、layout二、layout3(/res/layout/layout*.xml)這樣三個佈局,這三個佈局的背景顏色都是不同的,裏面都放了一個按鈕,爲了可以在後面實現每一個頁面獨立的功能。

佈局文件的代碼以下:

<?xml version="1.0" encoding="utf-8"?>
<!-- 這是layout1.xml的佈局代碼,另外兩個佈局文件就是背景顏色和按鈕的id,text改變了而已 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:background="#ff0000">
    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="button1"/>
</LinearLayout>

接下來,咱們要拓展(extends)三個Fragment,分別是Fragment1.java、Fragment2.java、Fragment3.java(/src/fragment/Fragment*.java)。代碼以下:

推薦不一樣功能的類,創建不一樣的包來進行分類管理。

public class Fragment1 extends Fragment {
    
    private View layout = null;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        this.layout = inflater.inflate(R.layout.layout1, null);
        
        //從這裏到return之間,你能夠爲這個Fragment添加其功能。
        Button b = (Button)this.layout.findViewById(R.id.button1);
        b.setOnClickListener(new ButtonListener());
        
        return this.layout;
    }
    
    public class ButtonListener implements OnClickListener {

        @Override
        public void onClick(View v) {
            
            Toast.makeText(getActivity(), "button1", Toast.LENGTH_SHORT).show();
        }
    }
}

OKOK,三個Fragment也準備好了,接下來實現一個FragmentPagerAdapter(/src/adapter/FragmentAdapter.java),代碼以下:

public class FragmentAdapter extends FragmentPagerAdapter{
    
    //這個是存放三個Fragment的數組,待會從MainActivity中傳過來就好了
    private ArrayList<Fragment> fragmentArray;
    
    //本身添加一個構造函數從MainActivity中接收這個Fragment數組
    public FragmentAdapter(FragmentManager fm, ArrayList<Fragment> fragmentArray) {
        this(fm);
        this.fragmentArray = fragmentArray;
    }
    
    public FragmentAdapter(FragmentManager fm) {
        super(fm);
    }
    
    //這個函數的做用是當切換到第arg0個頁面的時候調用。
    @Override
    public Fragment getItem(int arg0) {
        return this.fragmentArray.get(arg0);
    }

    @Override
    public int getCount() {
        return this.fragmentArray.size();
    }
}

實現好Adapter後,咱們就去MainActivity(src/com.kross.test/MainActivity.java)中配置一下。

在MainActivity中,咱們須要作以下幾件事情:

1.準備好Fragment,把它們添加進數組。

2.獲取到ViewPager的實例,爲其設置適配器。

3.設置ViewPager當前顯示第一頁。

由於在FragmentAdapter的構造函數中須要一個FragmentManager,因此,MainActivity應該繼承FragmentActivity

代碼以下:

public class MainActivity extends FragmentActivity {
    
    private ViewPager viewPager = null;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);this.initViewPager();
    
    }

private void initViewPager() { //獲取到ViewPager的實例 this.viewPager = (ViewPager)findViewById(R.id.viewpager); //構造好存放Fragment的數組 ArrayList<Fragment> fragmentArray = new ArrayList<Fragment>(); fragmentArray.add(new Fragment1()); fragmentArray.add(new Fragment2()); fragmentArray.add(new Fragment3()); //爲ViewPager設置適配器 this.viewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(), fragmentArray)); //設置當前顯示的頁面 this.viewPager.setCurrentItem(0); } }

 

3.爲下面的三個tab添加點擊事件,並設置好相應的激活效果。

完成上面兩步,應該能夠實現三個頁面滑動的效果。但下面的三個Tab是沒有被用上的。咱們這步要作到的事情是:點擊下面的tab,切換到相應的頁面,並激活tab,滑動上面的頁面,並激活tab。

這裏須要使用到一個接口OnPageChangeListener。這個接口中有三個方法,都是在頁面滑動的時候會被調用。咱們須要使用這個接口,讓頁面滑動的時候激活相應的tab。

如今來實現該接口PagerListener(/src/listener/PagerListener.java),代碼以下:

public class PagerListener implements OnPageChangeListener {
    
    private ArrayList<View> tabArray = null;private final static String TAG = "PagerListener";
    
    public PagerListener(ArrayList<View> tabArray) {
        this.tabArray = tabArray;
    }
    
    @Override
    //這個……
    public void onPageScrollStateChanged(int arg0) {
        Log.i(TAG, "onPageScrollStateChanged:" + Integer.toString(arg0));
    }

    @Override
    //這個方法是頁面滾動的時候被調用,咱們將在這個方法裏完成對激活條的操做
    public void onPageScrolled(int arg0, float arg1, int arg2) {
        Log.i(TAG, "onPageScrolled");
    }

    @Override
    //這個方法是當頁面切換完畢後被調用,
    public void onPageSelected(int arg0) {
        Log.i(TAG, "onPageSelected");
        
        //先將全部的tab設置成灰色的
        for (View item : this.tabArray) {
            ((TextView)item.findViewById(R.id.tab_text)).setTextColor(Color.rgb(20, 20, 20));
        }
        
        //再將當前的tab設置成白色的,表示激活狀態
        ((TextView)this.tabArray.get(arg0).findViewById(R.id.tab_text)).setTextColor(Color.WHITE);
    }
}

接下來,咱們須要實現一個OnClickListener

TabListener(src/listener/TabListener.java),代碼以下:

public class TabListener implements OnClickListener {
    
    private ViewPager viewPager = null;
    
    public TabListener(ViewPager v) {
        this.viewPager = v;
    }
    
    @Override
    public void onClick(View arg0) {
        switch (arg0.getId()) {
        case R.id.tab1:
            this.viewPager.setCurrentItem(0);
            break;
        case R.id.tab2:
            this.viewPager.setCurrentItem(1);
            break;
        case R.id.tab3:
            this.viewPager.setCurrentItem(2);
            break;
        }
    }
}

OKOK,接下來,咱們只須要在MainActivity中獲取tab的實例,給tab設置監聽器,給ViewPager設置監聽器就OK了。

MainActivity的代碼變成以下這樣:

public class MainActivity extends FragmentActivity {
    
    private ViewPager viewPager = null;
    
    //三個tab
    private View tab1 = null;
    private View tab2 = null;
    private View tab3 = null;//存放tab的數組
    private ArrayList<View> tabArray = null;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);this.initViewPager();
        this.initTab();
        this.setListener();
    
    }private void initTab() {
        this.tab1 = findViewById(R.id.tab1);
        this.tab2 = findViewById(R.id.tab2);
        this.tab3 = findViewById(R.id.tab3);
        
        this.tabArray = new ArrayList<View>();
        this.tabArray.add(tab1);
        this.tabArray.add(tab2);
        this.tabArray.add(tab3);
    }
    
    private void initViewPager() {
        //獲取到ViewPager的實例
        this.viewPager = (ViewPager)findViewById(R.id.viewpager);
        
        //構造好存放Fragment的數組
        ArrayList<Fragment> fragmentArray = new ArrayList<Fragment>();
        fragmentArray.add(new Fragment1());
        fragmentArray.add(new Fragment2());
        fragmentArray.add(new Fragment3());
        
        //爲ViewPager設置適配器
        this.viewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(), fragmentArray));
        
        //設置當前顯示的頁面
        this.viewPager.setCurrentItem(0);
    }
    
    private void setListener() {
        TabListener tl = new TabListener(this.viewPager);
        
        this.tab1.setOnClickListener(tl);
        this.tab2.setOnClickListener(tl);
        this.tab3.setOnClickListener(tl);

        this.viewPager.setOnPageChangeListener(new PagerListener(this.tabArray);
    }
}

完成上面的三步,就基本上實現了大部分的功能了。頁面能夠切換,tab也能夠點,有激活效果。

 

4.使用Matrix讓激活條隨頁面的滑動而滑動。

激活條的滑動,須要使用到OnPageChangeListener接口中的onPageScrolled方法,

該方法有會在頁面被滑動的時候調用,將會獲取到三個參數,第一個參數爲當前頁面的下標,第二個參數爲滑動距離佔屏幕寬度的百分比,第三個參數爲實際滑動的像素。

假設咱們當前處在0下標的頁面,咱們從右往左滑動,滑向1下標的頁面,在滑動的時候,該方法會一直被調用。

在沒有完全切換到1下標的頁面時,第一個參數一直是0,直到完全切換到1下標的頁面。

第二個參數是個[0,1)的浮點數,一滑動,該參數就開始變大 0.12313---->0.23321---->0.31233,當頁面快完成完全切換的時候,也就是該參數將無限逼近1,但不會是1,而後忽然變成了0,完成的頁面的切換。

第三個參數就很好理解了,個人屏幕寬度是720px,我滑到通常,它的值就是360。

知道了這些,咱們須要獲取激活條須要移動的長度,以及屏幕的寬度。

tab有三個,因此咱們用屏幕寬度/3,這是每一個tab的寬度,tab的寬度 - 圖片的寬度,這是剩餘的空間,剩餘的空間 / 2,就是小圖片的偏移量(offset)。

激活條圖片默認會出如今所在控件位置的最左邊,初始的時候,咱們就須要將它的位置設置在一個offset以後。

所以MainActivity的代碼變成以下這樣:

public class MainActivity extends FragmentActivity {
    
    private ViewPager viewPager = null;
    
    //三個tab
    private View tab1 = null;
    private View tab2 = null;
    private View tab3 = null;
    
    //偏移量
    private int offset;
    
    //圖片寬度
    private int imageWidth;
    
    //存放tab的數組
    private ArrayList<View> tabArray = null;
    
    private ImageView activeBar = null;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //獲取激活條控件
        this.activeBar = (ImageView)findViewById(R.id.active_bar);
        
        //獲取該激活條的寬度
        this.imageWidth = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher).getWidth();
        
        //獲取屏幕的寬度
        DisplayMetrics dm = new DisplayMetrics();   
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int screenWidth = dm.widthPixels;
        
        //計算出偏移量
        this.offset = (screenWidth / 3 - imageWidth) / 2;
        
        this.initViewPager();
        this.initTab();
        this.setListener();
    
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    private void initTab() {
        this.tab1 = findViewById(R.id.tab1);
        this.tab2 = findViewById(R.id.tab2);
        this.tab3 = findViewById(R.id.tab3);
        
        this.tabArray = new ArrayList<View>();
        this.tabArray.add(tab1);
        this.tabArray.add(tab2);
        this.tabArray.add(tab3);
    }
    
    private void initViewPager() {
        //獲取到ViewPager的實例
        this.viewPager = (ViewPager)findViewById(R.id.viewpager);
        
        //構造好存放Fragment的數組
        ArrayList<Fragment> fragmentArray = new ArrayList<Fragment>();
        fragmentArray.add(new Fragment1());
        fragmentArray.add(new Fragment2());
        fragmentArray.add(new Fragment3());
        
        //爲ViewPager設置適配器
        this.viewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(), fragmentArray));
        
        //設置當前顯示的頁面
        this.viewPager.setCurrentItem(0);
    }
    
    private void setListener() {
        TabListener tl = new TabListener(this.viewPager);
        
        this.tab1.setOnClickListener(tl);
        this.tab2.setOnClickListener(tl);
        this.tab3.setOnClickListener(tl);
        
        //注意這裏的構造函數
        this.viewPager.setOnPageChangeListener(new PagerListener(this.tabArray, this.activeBar, this.offset, this.imageWidth));
    }
}

須要注意給ViewPager設置監聽器的時候,傳入了激活條的句柄,偏移量以及圖片的寬度。

接下來咱們須要修改下PagerListener的代碼:

public class PagerListener implements OnPageChangeListener {
    
    private ArrayList<View> tabArray = null;
    private ImageView activeBar = null;
    private int offset;
    private int imageWidth;
    
    private final static String TAG = "PagerListener";
    
    public PagerListener(ArrayList<View> tabArray, ImageView activeBar, int offset, int iw) {
        this.tabArray = tabArray;
        this.activeBar = activeBar;
        this.offset = offset;
        this.imageWidth = iw;
    }
    
    @Override
    //這個……
    public void onPageScrollStateChanged(int arg0) {
        Log.i(TAG, "onPageScrollStateChanged:" + Integer.toString(arg0));
    }

    @Override
    //這個方法是頁面滾動的時候被調用,咱們將在這個方法裏完成對激活條的操做
    public void onPageScrolled(int arg0, float arg1, int arg2) {
        Log.i(TAG, "onPageScrolled");
        
        //new一個矩陣
        Matrix matrix = new Matrix();
        
        //設置激活條的最終位置
        switch (arg0) {
        case 0:
            //使用set直接設置到那個位置
            matrix.setTranslate(this.offset, 0);
            break;
        case 1:
            matrix.setTranslate(this.offset * 3 + this.imageWidth, 0);
            break;
        case 2:
            matrix.setTranslate(this.offset * 5 + this.imageWidth * 2, 0);
            break;
        }
        
        //在滑動的過程當中,計算出激活條應該要滑動的距離
        float t = (this.offset * 2 + this.imageWidth) * arg1;
        
        //使用post追加數值
        matrix.postTranslate(t, 0);
        
        this.activeBar.setImageMatrix(matrix);
    }

    @Override
    //這個方法是當頁面切換完畢後被調用,
    public void onPageSelected(int arg0) {
        Log.i(TAG, "onPageSelected");
        
        //先將全部的tab設置成灰色的
        for (View item : this.tabArray) {
            ((TextView)item.findViewById(R.id.tab_text)).setTextColor(Color.rgb(20, 20, 20));
        }
        
        //再將當前的tab設置成白色的,表示激活狀態
        ((TextView)this.tabArray.get(arg0).findViewById(R.id.tab_text)).setTextColor(Color.WHITE);
    }
}

OKOK,完成上面全部的代碼,就OK了。這樣就實現了全部的效果。真是辛苦啊……

若是還有疑惑的話,能夠來微博上問我:http://weibo.com/KrossFord

原文地址:http://www.cnblogs.com/kross/p/3372987.html

相關文章
相關標籤/搜索