ViewPager 詳解(四)—-自主實現滑動指示條
前言:前面我們用了三篇的時間講述了有關ViewPager的基礎知識,到這篇就要進入點實際的了。在第三篇《ViewPager 詳解(三)—PagerTabStrip與PagerTitleStrip新增標題欄的異同》中,我們說了,PagerTabStrip和PagerTitleStrip都不適合用在實際用途中,當要在實際運用中,我們就要自己去實現相關的功能。這篇文章中單純講述划動指示條的實現方法,而對於互動Tab的實現,就不再講解,最後給出網上的一段原始碼,大家可以去研究一下,有關互動Tab的實現原理是一樣的,難度不大。
相關文章:
先上本篇效果圖:
一、XML佈局
佈局程式碼如下:
[html] view plain- <LinearLayoutxmlns: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
- android:layout_height=“wrap_content”
- android:layout_gravity=“center”/>
- </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?- publicclass MainActivity extends Activity {
- private View view1, view2, view3;
- private List<View> viewList;// view陣列
- private ViewPager viewPager; // 對應的viewPager
- private ImageView cursor;
- privateint bmpw = 0; // 遊標寬度
- privateint offset = 0;// // 動畫圖片偏移量
- privateint currIndex = 0;// 當前頁卡編號
- @Override
- protectedvoid 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());
- }
- //初始化指示器位置
- publicvoid 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);// 設定動畫初始位置
- }
- //頁面改變監聽器
- publicclass MyPageChangeListener implements OnPageChangeListener {
- int one = offset * 2 + bmpw;// 頁卡1 -> 頁卡2 偏移量
- int two = one * 2;// 頁卡1 -> 頁卡3 偏移量
- @Override
- publicvoid onPageSelected(int arg0) {
- Animation animation = null;
- switch (arg0) {
- case0:
- if (currIndex == 1) {
- animation = new TranslateAnimation(one, 0, 0, 0);
- } elseif (currIndex == 2) {
- animation = new TranslateAnimation(two, 0, 0, 0);
- }
- break;
- case1:
- if (currIndex == 0) {
- animation = new TranslateAnimation(offset, one, 0, 0);
- } elseif (currIndex == 2) {
- animation = new TranslateAnimation(two, one, 0, 0);
- }
- break;
- case2:
- if (currIndex == 0) {
- animation = new TranslateAnimation(offset, two, 0, 0);
- } elseif (currIndex == 1) {
- animation = new TranslateAnimation(one, two, 0, 0);
- }
- break;
- }
- currIndex = arg0;
- animation.setFillAfter(true);// True:圖片停在動畫結束位置
- animation.setDuration(300);
- cursor.startAnimation(animation);
- }
- @Override
- publicvoid onPageScrolled(int arg0, float arg1, int arg2) {
- }
- @Override
- publicvoid onPageScrollStateChanged(int arg0) {
- }
- }
- /**
- * ViewPager介面卡
- */
- publicclass MyPagerAdapter extends PagerAdapter {
- public List<View> mListViews;
- public MyPagerAdapter(List<View> mListViews) {
- this.mListViews = mListViews;
- }
- @Override
- publicboolean isViewFromObject(View arg0, Object arg1) {
- // TODO Auto-generated method stub
- return arg0 == arg1;
- }
- @Override
- publicint getCount() {
- // TODO Auto-generated method stub
- return mListViews.size();
- }
- @Override
- publicvoid 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);
- }
- }
- }
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?- //初始化指示器位置
- publicvoid 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 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?- publicclass MyPageChangeListener implements OnPageChangeListener {
- int one = offset * 2 + bmpw;// 頁卡1 -> 頁卡2 偏移量
- int two = one * 2;// 頁卡1 -> 頁卡3 偏移量
- @Override
- publicvoid onPageSelected(int arg0) {
- Animation animation = null;
- switch (arg0) {
- case0:
- if (currIndex == 1) {
- animation = new TranslateAnimation(one, 0, 0, 0);
- } elseif (currIndex == 2) {
- animation = new TranslateAnimation(two, 0, 0, 0);
- }
- break;
- case1:
- if (currIndex == 0) {
- animation = new TranslateAnimation(offset, one, 0, 0);
- } elseif (currIndex == 2) {
- animation = new TranslateAnimation(two, one, 0, 0);
- }
- break;
- case2:
- if (currIndex == 0) {
- animation = new TranslateAnimation(offset, two, 0, 0);
- } elseif (currIndex == 1) {
- animation = new TranslateAnimation(one, two, 0, 0);
- }
- break;
- }
- currIndex = arg0;
- animation.setFillAfter(true);// True:圖片停在動畫結束位置
- animation.setDuration(300);
- cursor.startAnimation(animation);
- }
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