Android中的ViewPager視圖滑動(dòng)切換類的入門實(shí)例教程
ViewPager引入示例
首先讓大家有個(gè)全局的認(rèn)識(shí),直接上個(gè)項(xiàng)目,看看僅僅通過這幾行代碼,竟然就能完成如此強(qiáng)悍的功能。
效果圖:
實(shí)現(xiàn)了三個(gè)view間的相互滑動(dòng)。
第一個(gè)VIEW向第二個(gè)VIEW滑動(dòng)、第二個(gè)VIEW向第三個(gè)VIEW滑動(dòng)
一、新建項(xiàng)目,引入ViewPager控件
ViewPager。它是google SDk中自帶的一個(gè)附加包的一個(gè)類,可以用來實(shí)現(xiàn)屏幕間的切換。
1.在主布局文件里加入
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" tools:context="com.example.testviewpage_1.MainActivity" > <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </RelativeLayout>
其中 <Android.support.v4.view.ViewPager /> 是ViewPager對(duì)應(yīng)的組件,要將其放到想要滑動(dòng)的位置
2、新建三個(gè)layout,用于滑動(dòng)切換的視圖
從效果圖中也可以看到,我們的三個(gè)視圖都非常簡單,里面沒有任何的控件,大家當(dāng)然可以往里添加各種控件,但這里是個(gè)DEMO,只詳解原理即可,所以我這里僅僅用背景來區(qū)別不用layout布局。
布局代碼分別如下:
layout1.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff" android:orientation="vertical" > </LinearLayout>
layout2.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffff00" android:orientation="vertical" > </LinearLayout>
layout3.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ff00ff" android:orientation="vertical" > </LinearLayout><span style="color:#660000;"> </span>
二、代碼實(shí)戰(zhàn)
先上整體代碼,然后逐步講解。
package com.example.testviewpage_1; import java.util.ArrayList; import java.util.List; import java.util.zip.Inflater; import android.app.Activity; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class MainActivity extends Activity { private View view1, view2, view3; private ViewPager viewPager; //對(duì)應(yīng)的viewPager private List<View> viewList;//view數(shù)組 @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裝入數(shù)組中 viewList.add(view1); viewList.add(view2); viewList.add(view3); PagerAdapter pagerAdapter = new PagerAdapter() { @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 viewList.size(); } @Override public void destroyItem(ViewGroup container, int position, Object object) { // TODO Auto-generated method stub container.removeView(viewList.get(position)); } @Override public Object instantiateItem(ViewGroup container, int position) { // TODO Auto-generated method stub container.addView(viewList.get(position)); return viewList.get(position); } }; viewPager.setAdapter(pagerAdapter); } }
代碼量很小,全部放在了OnCreate()函數(shù)中。
1、先看聲明的變量的意義:
private View view1, view2, view3; private List<View> viewList;//view數(shù)組 private ViewPager viewPager; //對(duì)應(yīng)的viewPager
首先viewPager對(duì)應(yīng) <android.support.v4.view.ViewPager/>控件。
view1,view2 ,view3對(duì)應(yīng)我們的三個(gè)layout,即layout1.xml,layout2.xml,layout3.xml
viewList是一個(gè)View數(shù)組,盛裝上面的三個(gè)VIEW
2、接下來是他們的初始化過程:
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裝入數(shù)組中 viewList.add(view1); viewList.add(view2); viewList.add(view3);
初始化過程難度不大,就是將資源與變量聯(lián)系起來布局,最后將實(shí)例化的view1,view2,view3添加到viewList中
3、PageAdapter——PageView的適配器
適配器這個(gè)東東想必大家都不莫生,在ListView中也有適配器,listView通過重寫GetView()函數(shù)來獲取當(dāng)前要加載的Item。而PageAdapter不太相同,畢竟PageAdapter是單個(gè)VIew的合集。
PageAdapter 必須重寫的四個(gè)函數(shù):
(1)boolean isViewFromObject(View arg0, Object arg1)
(2)int getCount()
(3)void destroyItem(ViewGroup container, int position,Object object)
(4)Object instantiateItem(ViewGroup container, int position)
先看看各個(gè)函數(shù),我們上面都做了什么吧:
@Override public int getCount() { // TODO Auto-generated method stub return viewList.size(); }
getCount():返回要滑動(dòng)的VIew的個(gè)數(shù)
@Override public void destroyItem(ViewGroup container, int position, Object object) { // TODO Auto-generated method stub container.removeView(viewList.get(position)); }
destroyItem():從當(dāng)前container中刪除指定位置(position)的View;
@Override public Object instantiateItem(ViewGroup container, int position) { // TODO Auto-generated method stub container.addView(viewList.get(position)); return viewList.get(position); } };
instantiateItem():做了兩件事,第一:將當(dāng)前視圖添加到container中,第二:返回當(dāng)前View
@Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub return arg0 == arg1; }
isViewFromObject():對(duì)于這個(gè)函數(shù)就先不做講解,大家目前先知道它要這樣重寫就行了,后面我們會(huì)對(duì)它進(jìn)行改寫。
下面將仔細(xì)講解這幾個(gè)函數(shù)的意義,與有關(guān)Key的知識(shí)。
ViewPager的四大函數(shù)
一、官方說明
PagerAdapter比AdapterView的使用更加普通.ViewPager使用回調(diào)函數(shù)來表示一個(gè)更新的步驟,而不是使用一個(gè)視圖回收機(jī)制。在需要的時(shí)候pageradapter也可以實(shí)現(xiàn)視圖的回收或者使用一種更為巧妙的方法來管理視圖,比如采用可以管理自身視圖的fragment。
viewpager不直接處理每一個(gè)視圖而是將各個(gè)視圖與一個(gè)鍵聯(lián)系起來。這個(gè)鍵用來跟蹤且唯一代表一個(gè)頁面,不僅如此,該鍵還獨(dú)立于這個(gè)頁面所在adapter的位置。當(dāng)pageradapter將要改變的時(shí)候他會(huì)調(diào)用startUpdate函數(shù),接下來會(huì)調(diào)用一次或多次的instantiateItem或者destroyItem。最后在更新的后期會(huì)調(diào)用finishUpdate。當(dāng)finishUpdate返回時(shí) instantiateItem返回的對(duì)象應(yīng)該添加到父ViewGroup destroyItem返回的對(duì)象應(yīng)該被ViewGroup刪除。methodisViewFromObject(View, Object)代表了當(dāng)前的頁面是否與給定的鍵相關(guān)聯(lián)。
對(duì)于非常簡單的pageradapter或許你可以選擇用page本身作為鍵,在創(chuàng)建并且添加到viewgroup后instantiateItem方法里返回該page本身即可
destroyItem將會(huì)將該page從viewgroup里面移除。isViewFromObject方法里面直接可以返回view == object。
pageradapter支持?jǐn)?shù)據(jù)集合的改變,數(shù)據(jù)集合的改變必須要在主線程里面執(zhí)行,然后還要調(diào)用notifyDataSetChanged方法。和baseadapter非常相似。數(shù)據(jù)集合的改變包括頁面的添加刪除和修改位置。viewpager要維持當(dāng)前頁面是活動(dòng)的,所以你必須提供getItemPosition方法。
二、解析
viewpager不直接處理每一個(gè)視圖而是將各個(gè)視圖與一個(gè)鍵聯(lián)系起來。這個(gè)鍵用來跟蹤且唯一代表一個(gè)頁面,不僅如此,該鍵還獨(dú)立于這個(gè)頁面所在adapter的位置。當(dāng)pageradapter將要改變的時(shí)候他會(huì)調(diào)用startUpdate函數(shù),接下來會(huì)調(diào)用一次或多次的instantiateItem或者destroyItem。最后在更新的后期會(huì)調(diào)用finishUpdate。當(dāng)finishUpdate返回時(shí) instantiateItem返回的對(duì)象應(yīng)該添加到父ViewGroup destroyItem返回的對(duì)象應(yīng)該被ViewGroup刪除。methodisViewFromObject(View, Object)代表了當(dāng)前的頁面是否與給定的鍵相關(guān)聯(lián)。
對(duì)于非常簡單的pageradapter或許你可以選擇用page本身作為鍵,在創(chuàng)建并且添加到viewgroup后instantiateItem方法里返回該page本身即可destroyItem將會(huì)將該page從viewgroup里面移除。isViewFromObject方法里面直接可以返回view == object。
對(duì)于上面兩段話,我這里有兩點(diǎn)要著重講一下:
1、第一段說明了,鍵(Key)的概念,首先這里要清楚的一點(diǎn)是,每個(gè)滑動(dòng)頁面都對(duì)應(yīng)一個(gè)Key,而且這個(gè)Key值是用來唯一追蹤這個(gè)頁面的,也就是說每個(gè)滑動(dòng)頁面都與一個(gè)唯一的Key一一對(duì)應(yīng)。大家先有這個(gè)概念就好,關(guān)于這個(gè)Key是怎么來的,下面再講。
2、第二段簡單講了一個(gè)應(yīng)用,即將當(dāng)前頁面本身的View作為Key。其實(shí)這個(gè)應(yīng)用就是我們前一章講的例子應(yīng)用。不太理解?沒關(guān)系,下面細(xì)講。下面我們講講Key的問題。
三、關(guān)于Key
現(xiàn)在我?guī)е蠹铱纯磶讉€(gè)方法的官方文檔:
1.首先,destroyItem():
該方法實(shí)現(xiàn)的功能是移除一個(gè)給定位置的頁面。適配器有責(zé)任從容器中刪除這個(gè)視圖。這是為了確保在finishUpdate(viewGroup)返回時(shí)視圖能夠被移除。
在引入部分的例子中我們是這樣做的:
@Override public void destroyItem(ViewGroup container, int position, Object object) { // TODO Auto-generated method stub container.removeView(viewList.get(position)); }
果不其然,我們將給定位置的視圖從container中移除了……
2.然后看getCount ():
public abstract int getCount ()
Return the number of views available.
返回當(dāng)前有效視圖的個(gè)數(shù)。然后我們還:
@Override public int getCount() { // TODO Auto-generated method stub return viewList.size(); }
返回了當(dāng)前要滑動(dòng)視圖的個(gè)數(shù),與官方說明一致。
四、最難的兩個(gè)來了
1.instantiateItem (ViewGroup container, int position)
這個(gè)函數(shù)的實(shí)現(xiàn)的功能是創(chuàng)建指定位置的頁面視圖。適配器有責(zé)任增加即將創(chuàng)建的View視圖到這里給定的container中,這是為了確保在finishUpdate(viewGroup)返回時(shí)this is be done!
返回值:返回一個(gè)代表新增視圖頁面的Object(Key),這里沒必要非要返回視圖本身,也可以這個(gè)頁面的其它容器。其實(shí)我的理解是可以代表當(dāng)前頁面的任意值,只要你可以與你增加的View一一對(duì)應(yīng)即可,比如position變量也可以做為Key(最后我們舉個(gè)例子試試可不可行)
心得 :
(1)從說明中可以看到,在代碼中,我們的責(zé)任是將指定position的視圖添加到conatiner中
(2)Key的問題:從這個(gè)函數(shù)就可以看出,該函數(shù)返回值就是我們根據(jù)參數(shù)position增加到conatiner里的View的所對(duì)應(yīng)的Key?。。。。。?!
(3)“it only must ensure this is done by the time it returns fromfinishUpdate(ViewGroup).”這句話在destroyItem()的函數(shù)說明中同樣出現(xiàn)過,這說明在 finishUpdate(viewGroup)執(zhí)行完后,有兩個(gè)操作,一個(gè)是原視圖的移除(不再顯示的視圖),另一個(gè)是新增顯示視圖(即將顯示的視圖)
還是一開始引入的例子中,我們是這樣做的:
@Override public Object instantiateItem(ViewGroup container, int position) { // TODO Auto-generated method stub container.addView(viewList.get(position)); return viewList.get(position); } };
在這里,我們做了兩件事
第一:將參數(shù)里給定的position的視圖,增加到conatiner中,供其創(chuàng)建并顯示、。
第二:返回當(dāng)前position的View做為此視圖的Key。還記得API官方文檔中下面這段話么?
對(duì)于非常簡單的pageradapter或許你可以選擇用page本身作為鍵,在創(chuàng)建并且添加到viewgroup后instantiateItem方法里返回該page本身即可destroyItem將會(huì)將該page從viewgroup里面移除。isViewFromObject方法里面直接可以返回view == object。
這里就把當(dāng)前的View當(dāng)作Key傳過出去?。。?!
2.isViewFromObject (View view, Object object)
功能:該函數(shù)用來判斷instantiateItem(ViewGroup, int)函數(shù)所返回來的Key與一個(gè)頁面視圖是否是代表的同一個(gè)視圖(即它倆是否是對(duì)應(yīng)的,對(duì)應(yīng)的表示同一個(gè)View)
返回值:如果對(duì)應(yīng)的是同一個(gè)View,返回True,否則返回False。
在上面的例子中,我們這樣做的:
@Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub return arg0 == arg1; }
由于在instantiateItem()中,我們作為Key返回來的是當(dāng)前的View,所以在這里判斷時(shí),我們直接將Key與View看是否相等來判斷是否是同一個(gè)View。
五、自定義Key實(shí)例
經(jīng)過上面的講解,想必大家給Key的概念應(yīng)該有個(gè)清楚的理解,下面舉個(gè)例子來說明Key與View的關(guān)系,由于Key與View要一一對(duì)應(yīng),所以我把每個(gè)視圖所處的位置Position作為Key,在上章例子的基礎(chǔ)上更改的,下面先看全部代碼,然后看部分講解:
package com.example.testviewpage_2; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class MainActivity extends Activity { private View view1, view2, view3; private List<View> viewList;// view數(shù)組 private ViewPager viewPager; // 對(duì)應(yīng)的viewPager @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裝入數(shù)組中 viewList.add(view1); viewList.add(view2); viewList.add(view3); PagerAdapter pagerAdapter = new PagerAdapter() { @Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub //根據(jù)傳來的key,找到view,判斷與傳來的參數(shù)View arg0是不是同一個(gè)視圖 return arg0 == viewList.get((int)Integer.parseInt(arg1.toString())); } @Override public int getCount() { // TODO Auto-generated method stub return viewList.size(); } @Override public void destroyItem(ViewGroup container, int position, Object object) { // TODO Auto-generated method stub container.removeView(viewList.get(position)); } @Override public Object instantiateItem(ViewGroup container, int position) { // TODO Auto-generated method stub container.addView(viewList.get(position)); //把當(dāng)前新增視圖的位置(position)作為Key傳過去 return position; } }; viewPager.setAdapter(pagerAdapter); } }
在這里更改了兩個(gè)地方:
1、先看Key的產(chǎn)生的位置instantiateItem()
@Override public Object instantiateItem(ViewGroup container, int position) { // TODO Auto-generated method stub container.addView(viewList.get(position)); //把當(dāng)前新增視圖的位置(position)作為Key傳過去 return position; }
我們?cè)谏现v也講了在這個(gè)函數(shù)中Key是作為返回值與當(dāng)前裝入Container中的視圖對(duì)應(yīng)起來的。所以在這里我們返回postion與container.addView(viewList.get(position));里的viewList.get(position)這個(gè)視圖對(duì)應(yīng)起來。
2、isViewFromObject ()
@Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub //根據(jù)傳來的key,找到view,判斷與傳來的參數(shù)View arg0是不是同一個(gè)視圖 return arg0 == viewList.get((int)Integer.parseInt(arg1.toString())); }
判斷從instantiateItem()返回來的Key與當(dāng)前的View是否能對(duì)應(yīng)起來,我們知道從instantiateItem傳過來的其實(shí)是position,所以我們要根據(jù)position找到View,然后跟參數(shù)中的View arg0判斷。
但在真正操作時(shí)出現(xiàn)了問題,我們要先將obect對(duì)應(yīng)轉(zhuǎn)換為int類型:(int)Integer.parseInt(arg1.toString());然后再根據(jù)position找到對(duì)應(yīng)的View;
效果圖:三個(gè)View之間的滑動(dòng)切換
這里只所以與上章不一樣,僅僅只有上部分一部分的地方才有滑動(dòng)切換,是因?yàn)槲腋牧瞬季治募?/p>
<RelativeLayout 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" tools:context="com.example.testviewpage_2.MainActivity" > <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="wrap_content" android:layout_height="200dip" android:layout_gravity="center" /> </RelativeLayout>
這里將layout_height更改為200dip,只所以這么做,是為了告訴大家,只要在想要實(shí)現(xiàn)滑動(dòng)切換的地方添加上<android.support.v4.view.ViewPager />就可以實(shí)現(xiàn)切換,無所謂位置和大小,跟普通控件一樣!?。。。?!
- Android如何使用ViewPager2實(shí)現(xiàn)頁面滑動(dòng)切換效果
- Android HorizontalScrollView滑動(dòng)與ViewPager切換案例詳解
- Android使用TabLayou+fragment+viewpager實(shí)現(xiàn)滑動(dòng)切換頁面效果
- Android ViewPager撤消左右滑動(dòng)切換功能實(shí)現(xiàn)代碼
- Android開發(fā)之使用ViewPager實(shí)現(xiàn)圖片左右滑動(dòng)切換效果
- Android App中使用ViewPager+Fragment實(shí)現(xiàn)滑動(dòng)切換效果
- Android應(yīng)用中利用ViewPager實(shí)現(xiàn)多頁面滑動(dòng)切換效果示例
- Android編程實(shí)現(xiàn)ViewPager多頁面滑動(dòng)切換及動(dòng)畫效果的方法
- Android實(shí)現(xiàn)界面左右滑動(dòng)切換功能
- Android開發(fā)之ViewPager實(shí)現(xiàn)滑動(dòng)切換頁面
相關(guān)文章
android中使用SharedPreferences進(jìn)行數(shù)據(jù)存儲(chǔ)的操作方法
本篇文章介紹了,在android中使用SharedPreferences進(jìn)行數(shù)據(jù)存儲(chǔ)的操作方法。需要的朋友參考下2013-04-04android自定義進(jìn)度條漸變色View的實(shí)例代碼
這篇文章主要介紹了android自定義進(jìn)度條漸變色View的實(shí)例代碼,有需要的朋友可以參考一下2014-01-01Android編程實(shí)現(xiàn)啟動(dòng)界面的方法分析
這篇文章主要介紹了Android編程實(shí)現(xiàn)啟動(dòng)界面的方法,結(jié)合實(shí)例形式分析了Android啟動(dòng)界面的實(shí)現(xiàn)方法與相關(guān)操作技巧,需要的朋友可以參考下2017-03-03簡單掌握Android Widget桌面小部件的創(chuàng)建步驟
這篇文章主要介紹了簡單掌握Android Widget桌面小部件的創(chuàng)建步驟,Widget一般采用web前端技術(shù)進(jìn)行開發(fā),需要的朋友可以參考下2016-03-03mac系統(tǒng)下載、安裝、使用AndroidStudio
本文給大家介紹的是在Mac系統(tǒng)中下載安裝以及使用AndroidStudio的詳細(xì)教程,非常的實(shí)用,有需要的小伙伴可以參考下2017-10-10Android?Studio實(shí)現(xiàn)簡單補(bǔ)間動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了Android?Studio實(shí)現(xiàn)簡單補(bǔ)間動(dòng)畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07Android 服務(wù)端將位置信息發(fā)送給客戶端的實(shí)現(xiàn)
這篇文章主要介紹了Android 服務(wù)端將位置信息發(fā)送給客戶端的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01