1. 程式人生 > >ViewPager 詳解(四)—-自主實現滑動指示條

ViewPager 詳解(四)—-自主實現滑動指示條

前言:前面我們用了三篇的時間講述了有關ViewPager的基礎知識,到這篇就要進入點實際的了。在第三篇《ViewPager 詳解(三)—PagerTabStrip與PagerTitleStrip新增標題欄的異同》中,我們說了,PagerTabStrip和PagerTitleStrip都不適合用在實際用途中,當要在實際運用中,我們就要自己去實現相關的功能。這篇文章中單純講述划動指示條的實現方法,而對於互動Tab的實現,就不再講解,最後給出網上的一段原始碼,大家可以去研究一下,有關互動Tab的實現原理是一樣的,難度不大。

相關文章:

先上本篇效果圖:

  

一、XML佈局

佈局程式碼如下:

[html] view plain
copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. <LinearLayoutxmlns:android=“http://schemas.android.com/apk/res/android”
  2.     xmlns:tools=“http://schemas.android.com/tools”
  3.     android:layout_width=“match_parent”
  4.     android:layout_height=“match_parent”
  5.     android:orientation=“vertical”
  6.     tools:context=“com.example.testviewpage_2.MainActivity”
    >
  7.      <ImageView
  8.         android:id=“@+id/cursor”
  9.         android:layout_width=“fill_parent”
  10.         android:layout_height=“wrap_content”
  11.         android:scaleType=“matrix”
  12.         android:src=“@drawable/a”/>
  13.     <android.support.v4.view.ViewPager
  14.         android:id=“@+id/viewpager”
  15.         android:layout_width
    =“wrap_content”
  16.         android:layout_height=“wrap_content”
  17.         android:layout_gravity=“center”/>
  18. </LinearLayout>
<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="com.example.testviewpage_2.MainActivity" >

     <ImageView
        android:id="@+id/cursor"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:scaleType="matrix"
        android:src="@drawable/a" />

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>

</LinearLayout>
採用線性垂直佈局,在滑動頁面的上方新增一個小水平條。

二、JAVA程式碼

先給出全部程式碼,然後再逐步講解。

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicclass MainActivity extends Activity {  
  2.     private View view1, view2, view3;  
  3.     private List<View> viewList;// view陣列
  4.     private ViewPager viewPager; // 對應的viewPager
  5.     private ImageView cursor;  
  6.     privateint bmpw = 0// 遊標寬度
  7.     privateint offset = 0;// // 動畫圖片偏移量
  8.     privateint currIndex = 0;// 當前頁卡編號
  9.     @Override
  10.     protectedvoid onCreate(Bundle savedInstanceState) {  
  11.         super.onCreate(savedInstanceState);  
  12.         setContentView(R.layout.activity_main);  
  13.         viewPager = (ViewPager) findViewById(R.id.viewpager);  
  14.         LayoutInflater inflater = getLayoutInflater();  
  15.         view1 = inflater.inflate(R.layout.layout1, null);  
  16.         view2 = inflater.inflate(R.layout.layout2, null);  
  17.         view3 = inflater.inflate(R.layout.layout3, null);  
  18.         viewList = new ArrayList<View>();// 將要分頁顯示的View裝入陣列中
  19.         viewList.add(view1);  
  20.         viewList.add(view2);  
  21.         viewList.add(view3);  
  22.         //初始化指示器位置
  23.         initCursorPos();  
  24.         viewPager.setAdapter(new MyPagerAdapter(viewList));  
  25.         viewPager.setOnPageChangeListener(new MyPageChangeListener());  
  26.     }  
  27.     //初始化指示器位置
  28.     publicvoid initCursorPos() {  
  29.         // 初始化動畫
  30.         cursor = (ImageView) findViewById(R.id.cursor);  
  31.         bmpw = BitmapFactory.decodeResource(getResources(), R.drawable.a)  
  32.                 .getWidth();// 獲取圖片寬度
  33.         DisplayMetrics dm = new DisplayMetrics();  
  34.         getWindowManager().getDefaultDisplay().getMetrics(dm);  
  35.         int screenW = dm.widthPixels;// 獲取解析度寬度
  36.         offset = (screenW / viewList.size() - bmpw) / 2;// 計算偏移量
  37.         Matrix matrix = new Matrix();  
  38.         matrix.postTranslate(offset, 0);  
  39.         cursor.setImageMatrix(matrix);// 設定動畫初始位置
  40.     }  
  41.     //頁面改變監聽器
  42.     publicclass MyPageChangeListener implements OnPageChangeListener {  
  43.         int one = offset * 2 + bmpw;// 頁卡1 -> 頁卡2 偏移量
  44.         int two = one * 2;// 頁卡1 -> 頁卡3 偏移量
  45.         @Override
  46.         publicvoid onPageSelected(int arg0) {  
  47.             Animation animation = null;  
  48.             switch (arg0) {  
  49.             case0:  
  50.                 if (currIndex == 1) {  
  51.                     animation = new TranslateAnimation(one, 000);  
  52.                 } elseif (currIndex == 2) {  
  53.                     animation = new TranslateAnimation(two, 000);  
  54.                 }  
  55.                 break;  
  56.             case1:  
  57.                 if (currIndex == 0) {  
  58.                     animation = new TranslateAnimation(offset, one, 00);  
  59.                 } elseif (currIndex == 2) {  
  60.                     animation = new TranslateAnimation(two, one, 00);  
  61.                 }  
  62.                 break;  
  63.             case2:  
  64.                 if (currIndex == 0) {  
  65.                     animation = new TranslateAnimation(offset, two, 00);  
  66.                 } elseif (currIndex == 1) {  
  67.                     animation = new TranslateAnimation(one, two, 00);  
  68.                 }  
  69.                 break;  
  70.             }  
  71.             currIndex = arg0;  
  72.             animation.setFillAfter(true);// True:圖片停在動畫結束位置
  73.             animation.setDuration(300);  
  74.             cursor.startAnimation(animation);  
  75.         }  
  76.         @Override
  77.         publicvoid onPageScrolled(int arg0, float arg1, int arg2) {  
  78.         }  
  79.         @Override
  80.         publicvoid onPageScrollStateChanged(int arg0) {  
  81.         }  
  82.     }  
  83.     /** 
  84.      * ViewPager介面卡 
  85.      */
  86.     publicclass MyPagerAdapter extends PagerAdapter {  
  87.         public List<View> mListViews;  
  88.         public MyPagerAdapter(List<View> mListViews) {  
  89.             this.mListViews = mListViews;  
  90.         }  
  91.         @Override
  92.         publicboolean isViewFromObject(View arg0, Object arg1) {  
  93.             // TODO Auto-generated method stub
  94.             return arg0 == arg1;  
  95.         }  
  96.         @Override
  97.         publicint getCount() {  
  98.             // TODO Auto-generated method stub
  99.             return mListViews.size();  
  100.         }  
  101.         @Override
  102.         publicvoid destroyItem(ViewGroup container, int position, Object object) {  
  103.             // TODO Auto-generated method stub
  104.             container.removeView(mListViews.get(position));  
  105.         }  
  106.         @Override
  107.         public Object instantiateItem(ViewGroup container, int position) {  
  108.             // TODO Auto-generated method stub
  109.             container.addView(mListViews.get(position));  
  110.             return mListViews.get(position);  
  111.         }  
  112.     }  
  113. }  
public class MainActivity extends Activity {

    private View view1, view2, view3;
    private List<View> viewList;// view陣列
    private ViewPager viewPager; // 對應的viewPager

    private ImageView cursor;
    private int bmpw = 0; // 遊標寬度
    private int offset = 0;// // 動畫圖片偏移量
    private int currIndex = 0;// 當前頁卡編號

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        viewPager = (ViewPager) findViewById(R.id.viewpager);
        LayoutInflater inflater = getLayoutInflater();
        view1 = inflater.inflate(R.layout.layout1, null);
        view2 = inflater.inflate(R.layout.layout2, null);
        view3 = inflater.inflate(R.layout.layout3, null);

        viewList = new ArrayList<View>();// 將要分頁顯示的View裝入陣列中
        viewList.add(view1);
        viewList.add(view2);
        viewList.add(view3);

        //初始化指示器位置
        initCursorPos();

        viewPager.setAdapter(new MyPagerAdapter(viewList));
        viewPager.setOnPageChangeListener(new MyPageChangeListener());

    }

    //初始化指示器位置
    public void initCursorPos() {
        // 初始化動畫
        cursor = (ImageView) findViewById(R.id.cursor);
        bmpw = BitmapFactory.decodeResource(getResources(), R.drawable.a)
                .getWidth();// 獲取圖片寬度

        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int screenW = dm.widthPixels;// 獲取解析度寬度
        offset = (screenW / viewList.size() - bmpw) / 2;// 計算偏移量

        Matrix matrix = new Matrix();
        matrix.postTranslate(offset, 0);
        cursor.setImageMatrix(matrix);// 設定動畫初始位置
    }


    //頁面改變監聽器
    public class MyPageChangeListener implements OnPageChangeListener {

        int one = offset * 2 + bmpw;// 頁卡1 -> 頁卡2 偏移量
        int two = one * 2;// 頁卡1 -> 頁卡3 偏移量

        @Override
        public void onPageSelected(int arg0) {
            Animation animation = null;
            switch (arg0) {
            case 0:
                if (currIndex == 1) {
                    animation = new TranslateAnimation(one, 0, 0, 0);
                } else if (currIndex == 2) {
                    animation = new TranslateAnimation(two, 0, 0, 0);
                }
                break;
            case 1:
                if (currIndex == 0) {
                    animation = new TranslateAnimation(offset, one, 0, 0);
                } else if (currIndex == 2) {
                    animation = new TranslateAnimation(two, one, 0, 0);
                }
                break;
            case 2:
                if (currIndex == 0) {
                    animation = new TranslateAnimation(offset, two, 0, 0);
                } else if (currIndex == 1) {
                    animation = new TranslateAnimation(one, two, 0, 0);
                }
                break;
            }
            currIndex = arg0;
            animation.setFillAfter(true);// True:圖片停在動畫結束位置
            animation.setDuration(300);
            cursor.startAnimation(animation);
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
        }
    }





    /**
     * ViewPager介面卡
     */
    public class MyPagerAdapter extends PagerAdapter {
        public List<View> mListViews;

        public MyPagerAdapter(List<View> mListViews) {
            this.mListViews = mListViews;
        }

        @Override
        public boolean isViewFromObject(View arg0, Object arg1) {
            // TODO Auto-generated method stub
            return arg0 == arg1;
        }

        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return mListViews.size();
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            // TODO Auto-generated method stub
            container.removeView(mListViews.get(position));
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            // TODO Auto-generated method stub
            container.addView(mListViews.get(position));

            return mListViews.get(position);
        }
    }

}
從易到難一步步來講。

1、MyPagerAdapter類


在前幾篇中,我們對於介面卡的實現總是new一個PageAdapter的例項。我們這裡做了一點稍微的更改,將其集合成一個類,內容都沒變,只是多了一個建構函式而已。所以針對這個類的具體程式碼,我就不再細講,如果對其中的複寫的函式為什麼要這麼寫不理解的同學,請看《ViewPager 詳解(二)—詳解四大函式》

2、initCursorPos()—初始化指示器位置

遊標在初始化顯示時,我們要根據螢幕寬度來顯示遊標位置。先看看這部分程式碼:

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. //初始化指示器位置
  2. publicvoid initCursorPos() {  
  3.     // 初始化動畫
  4.     cursor = (ImageView) findViewById(R.id.cursor);  
  5.     bmpw = BitmapFactory.decodeResource(getResources(), R.drawable.a)  
  6.             .getWidth();// 獲取圖片寬度
  7.     DisplayMetrics dm = new DisplayMetrics();  
  8.     getWindowManager().getDefaultDisplay().getMetrics(dm);  
  9.     int screenW = dm.widthPixels;// 獲取解析度寬度
  10.     offset = (screenW / viewList.size() - bmpw) / 2;// 計算偏移量
  11.     Matrix matrix = new Matrix();  
  12.     matrix.postTranslate(offset, 0);  
  13.     cursor.setImageMatrix(matrix);// 設定動畫初始位置
  14. }  
    //初始化指示器位置
    public void initCursorPos() {
        // 初始化動畫
        cursor = (ImageView) findViewById(R.id.cursor);
        bmpw = BitmapFactory.decodeResource(getResources(), R.drawable.a)
                .getWidth();// 獲取圖片寬度

        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int screenW = dm.widthPixels;// 獲取解析度寬度
        offset = (screenW / viewList.size() - bmpw) / 2;// 計算偏移量

        Matrix matrix = new Matrix();
        matrix.postTranslate(offset, 0);
        cursor.setImageMatrix(matrix);// 設定動畫初始位置
    }

可能有些同學不明白的位置在於,初始化位置的偏移量為什麼這麼算,下面,我畫了張圖,看下就應該明白了。


最後對於偏移的方法,可用的很多,這裡仿網上的程式碼用了matrix;當然大家可以用其它的偏移方法,一樣。

3、MyPageChangeListener()—頁面改變監聽器

程式碼如下 :

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicclass MyPageChangeListener implements OnPageChangeListener {  
  2.     int one = offset * 2 + bmpw;// 頁卡1 -> 頁卡2 偏移量
  3.     int two = one * 2;// 頁卡1 -> 頁卡3 偏移量
  4.     @Override
  5.     publicvoid onPageSelected(int arg0) {  
  6.         Animation animation = null;  
  7.         switch (arg0) {  
  8.         case0:  
  9.             if (currIndex == 1) {  
  10.                 animation = new TranslateAnimation(one, 000);  
  11.             } elseif (currIndex == 2) {  
  12.                 animation = new TranslateAnimation(two, 000);  
  13.             }  
  14.             break;  
  15.         case1:  
  16.             if (currIndex == 0) {  
  17.                 animation = new TranslateAnimation(offset, one, 00);  
  18.             } elseif (currIndex == 2) {  
  19.                 animation = new TranslateAnimation(two, one, 00);  
  20.             }  
  21.             break;  
  22.         case2:  
  23.             if (currIndex == 0) {  
  24.                 animation = new TranslateAnimation(offset, two, 00);  
  25.             } elseif (currIndex == 1) {  
  26.                 animation = new TranslateAnimation(one, two, 00);  
  27.             }  
  28.             break;  
  29.         }  
  30.         currIndex = arg0;  
  31.         animation.setFillAfter(true);// True:圖片停在動畫結束位置
  32.         animation.setDuration(300);  
  33.         cursor.startAnimation(animation);  
  34.     }  
public class MyPageChangeListener implements OnPageChangeListener {

    int one = offset * 2 + bmpw;// 頁卡1 -> 頁卡2 偏移量
    int two = one * 2;// 頁卡1 -> 頁卡3 偏移量

    @Override
    public void onPageSelected(int arg0) {
        Animation animation = null;
        switch (arg0) {
        case 0:
            if (currIndex == 1) {
                animation = new TranslateAnimation(one, 0, 0, 0);
            } else if (currIndex == 2) {
                animation = new TranslateAnimation(two, 0, 0, 0);
            }
            break;
        case 1:
            if (currIndex == 0) {
                animation = new TranslateAnimation(offset, one, 0, 0);
            } else if (currIndex == 2) {
                animation = new TranslateAnimation(two, one, 0, 0);
            }
            break;
        case 2:
            if (currIndex == 0) {
                animation = new TranslateAnimation(offset, two, 0, 0);
            } else if (currIndex == 1) {
                animation = new TranslateAnimation(one, two, 0, 0);
            }
            break;
        }
        currIndex = arg0;
        animation.setFillAfter(true);// True:圖片停在動畫結束位置
        animation.setDuration(300);
        cursor.startAnimation(animation);
    }
原理是這樣,根據滑動到的頁面,把遊標滑動找指定位置。
這裡可能有難度的地方在於,數學……

我畫了一張圖,解釋從第一個頁面到第二個頁面時的距離為什麼是“遊標寬度+offset*2”,其它距離類似。


這篇就到這了,時間比較緊,而且這個難度不太大,講的可能不太細。

原始碼中,給大家列出了一個有Tab互動的Demo,圖片如下:

  

相關文章:

原始碼包含:

1、TestViewPage_scroll_cursor:文中示例原始碼

2、DWinterTabDemo:帶Tab互動的Demo