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

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

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

相關文章:

先上本篇效果圖:

  

一、XML佈局

佈局程式碼如下:

<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程式碼

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

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()---初始化指示器位置

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

	//初始化指示器位置
	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()---頁面改變監聽器

程式碼如下 :

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

相關推薦

ViewPager ----自主實現滑動指示

前言:前面我們用了三篇的時間講述了有關ViewPager的基礎知識,到這篇就要進入點實際的了。在第三篇《ViewPager 詳解(三)---PagerTabStrip與PagerTitleStrip新增標題欄的異同》中,我們說了,PagerTabStrip和PagerTitl

ViewPager —-自主實現滑動指示

前言:前面我們用了三篇的時間講述了有關ViewPager的基礎知識,到這篇就要進入點實際的了。在第三篇《ViewPager 詳解(三)—PagerTabStrip與PagerTitleStrip新增標題欄的異同》中,我們說了,PagerTabStrip和Page

郵件實現------JavaMail 發送帶圖片和附件和接收郵件

發送 網絡圖 發送對象 true n) com 訪問權限 sub map   好了,進入這個系列教程最主要的步驟了,前面郵件的理論知識我們都了解了,那麽這篇博客我們將用代碼完成郵件的發送。這在實際項目中應用的非常廣泛,比如註冊需要發送郵件進行賬號激活,再比如OA項目中利用郵

實現螢幕切換、滑動-ViewPager之--------PagerTitleStrip與PagerTabStrip新增標題欄

PagerTabStrip 1.PagerTabStrip概述:(API解釋) PagerTabStrip是ViewPager的一個關於當前頁面、上一個頁面和下一個頁面的一個非互動的指示器。它經常作為ViewPager控制元件的一個子控制元件被被新增

HTTP:JAVA實現HTTP請求

通過上幾篇的文章,我們對HTTP已經已經有了一個初步的認識,對於"為什麼要用HTTP","怎麼用HTTP","HTTP是什麼"相信大家都有了一個了一個屬於自己的看法,今天這篇文章主要是程式碼的角度上去實現HTTP的請求。

PullScrollView——完全使用listview實現下拉回彈方法一

在前面三篇中,我為大家展示了使用ScrollView實現下拉回彈的效果。但如果ScrollView裡如果巢狀使用ListView就可能會出現問題,因為兩者都會有滑動監聽。操作起來可能會起衝突,然後解決了衝突問題,到後面頁面效能也會很差強人意。即然如此,那我們就直接使用

elastic-job:失效轉移

shard out utm monit 設置 borde 點滴 title 等於 elastic-job中最關鍵的特性之一就是失效轉移。配置了失效轉移之後,如果在任務執行過程中有一個執行實例掛了,那麽之前被分配到這個實例的任務(或者分片)會在下次任務執行之前被重新分配到其他

Quartz學習——SSMM(Spring+SpringMVC+Mybatis+Mysql)和Quartz集成

webapp cron表達式 msi 接口 cli post 定時 報錯 gets Quartz學習——SSMM(Spring+SpringMVC+Mybatis+Mysql)和Quartz集成詳解(四) 當任何時候覺你得難受了,其實你的大腦是在進化,當任何時候你覺得

07-Linux中DNS

用戶 mail all 驗證 src 更改 條目 http nslookup 接“06-Linux中DNS詳解(三)” 九、配置主從DNS服務器實現域名解析容錯 1、實驗環境zhangyujia.com(192.168.80.100)為主區域,com(192.168.8

編碼原理---之字形掃描

便是 集中 img 詳解 工作 -- 漢字 如何 編碼原理 上一篇我們講到,經過量化後得到了諸多零值和整數值,本篇接下來講講編碼過程中過對這些值如何組織和處理,那就是ZigZag掃描嘍。 一、簡介 ZigZag掃描也稱作之字形掃描,何以得此稱謂,是因為其掃描的路徑特

Nginx模塊

nginx https fastcgi 一、Nginx之目錄瀏覽二、Nginx之log模塊三、Ning之gzip模塊四、Nginx之https服務五、Nginx之fastCGI模塊 一、配置Nginx提供目錄瀏覽功能 1.修改nginx配置文件 server { listen

Zookeeper:Zookeeper中的zkCli.sh客戶端使用

zkCli.sh zookeeper客戶端 最好配置上環境變量連接操作:zkCli.sh -timeout 1000 -r -server 127.0.0.1 # -timeout 設置客戶端和服務器之間的超時時長,單位毫秒 # -r 只讀模式,不加就是讀寫模式 # -server IP:PORT 要

Keepalived

mysql pan 節點 ios all -s 關閉 定義 interval 一.通過vrrp_script實現對集群資源的監控: Keepalived基礎HA功能時用到了vrrp_script這個模塊,此模塊專門用於對集群中服務資源進行監控。與此模塊一起使用

PE文件格式

ebs 位置 數位 地址 inf font pe文件 。。 地址轉換 PE文件格式詳解(四) 0x00 前言 上一篇介紹了區塊表的信息,以及如何在hexwrokshop找到區塊表。接下來,我們繼續深入了解區塊,並且學會文件偏移和虛擬地址轉換的知識。 0x01 區塊對齊值

PE檔案格式

PE檔案格式詳解(四) 0x00 前言   上一篇介紹了區塊表的資訊,以及如何在hexwrokshop找到區塊表。接下來,我們繼續深入瞭解區塊,並且學會檔案偏移和虛擬地址轉換的知識。 0x01 區塊對齊值   首先我們要知道啥事區塊對齊?為啥要區塊對齊?這個問題

安卓專案實戰之強大的網路請求框架okGo使用:Cookie的管理

Cookie概念相關 具體來說cookie機制採用的是在客戶端保持狀態的方案,而session機制採用的是在伺服器端保持狀態的方案。同時我們也看到,由於採用伺服器端保持狀態的方案在客戶端也需要儲存一個標識,所以session機制是需要藉助於cookie機制來達到儲存標識的目的,所謂ses

安卓專案實戰之強大的網路請求框架okGo使用實現get,post基本網路請求,下載上傳進度監聽以及對Callback自定義的深入理解

1.新增依賴 //必須使用 compile 'com.lzy.net:okgo:3.0.4' //以下三個選擇新增,okrx和okrx2不能同時使用,一般選擇新增最新的rx2支援即可 compile 'com.lzy.net:okrx:1.0.2' compile 'com.lzy

【SpringBoot學習之路】08.Springboot配置檔案

轉載宣告:商業轉載請聯絡作者獲得授權,非商業轉載請註明出處.原文來自 © 呆萌鍾【SpringBoot學習之路】08.Springboot配置檔案詳解(四)  自動配置原理 配置檔案到底能寫什麼?怎麼寫?自動配置原理; 配置檔案能配置的屬性參照

Java 反射機制

Java 反射機制詳解(四) 4. 反射與泛型  定義一個泛型類: public class DAO<T> { //根據id獲取一個物件 T get(Integer id){ return null; }