編輯:關於Android編程
ViewPager引入示例
首先讓大家有個全局的認識,直接上個項目,看看僅僅通過這幾行代碼,竟然就能完成如此強悍的功能。
效果圖:
實現了三個view間的相互滑動。
第一個VIEW向第二個VIEW滑動、第二個VIEW向第三個VIEW滑動
一、新建項目,引入ViewPager控件
ViewPager。它是google SDk中自帶的一個附加包的一個類,可以用來實現屏幕間的切換。
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對應的組件,要將其放到想要滑動的位置
2、新建三個layout,用於滑動切換的視圖
從效果圖中也可以看到,我們的三個視圖都非常簡單,裡面沒有任何的控件,大家當然可以往裡添加各種控件,但這裡是個DEMO,只詳解原理即可,所以我這裡僅僅用背景來區別不用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 > </span>
二、代碼實戰
先上整體代碼,然後逐步講解。
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; //對應的viewPager private List<View> viewList;//view數組 @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); 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()函數中。
1、先看聲明的變量的意義:
private View view1, view2, view3; private List<View> viewList;//view數組 private ViewPager viewPager; //對應的viewPager
首先viewPager對應 <android.support.v4.view.ViewPager/>控件。
view1,view2 ,view3對應我們的三個layout,即layout1.xml,layout2.xml,layout3.xml
viewList是一個View數組,盛裝上面的三個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裝入數組中 viewList.add(view1); viewList.add(view2); viewList.add(view3);
初始化過程難度不大,就是將資源與變量聯系起來布局,最後將實例化的view1,view2,view3添加到viewList中
3、PageAdapter——PageView的適配器
適配器這個東東想必大家都不莫生,在ListView中也有適配器,listView通過重寫GetView()函數來獲取當前要加載的Item。而PageAdapter不太相同,畢竟PageAdapter是單個VIew的合集。
PageAdapter 必須重寫的四個函數:
(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)
先看看各個函數,我們上面都做了什麼吧:
@Override public int getCount() { // TODO Auto-generated method stub return viewList.size(); }
getCount():返回要滑動的VIew的個數
@Override public void destroyItem(ViewGroup container, int position, Object object) { // TODO Auto-generated method stub container.removeView(viewList.get(position)); }
destroyItem():從當前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():做了兩件事,第一:將當前視圖添加到container中,第二:返回當前View
@Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub return arg0 == arg1; }
isViewFromObject():對於這個函數就先不做講解,大家目前先知道它要這樣重寫就行了,後面我們會對它進行改寫。
下面將仔細講解這幾個函數的意義,與有關Key的知識。
ViewPager的四大函數
一、官方說明
PagerAdapter比AdapterView的使用更加普通.ViewPager使用回調函數來表示一個更新的步驟,而不是使用一個視圖回收機制。在需要的時候pageradapter也可以實現視圖的回收或者使用一種更為巧妙的方法來管理視圖,比如采用可以管理自身視圖的fragment。
viewpager不直接處理每一個視圖而是將各個視圖與一個鍵聯系起來。這個鍵用來跟蹤且唯一代表一個頁面,不僅如此,該鍵還獨立於這個頁面所在adapter的位置。當pageradapter將要改變的時候他會調用startUpdate函數,接下來會調用一次或多次的instantiateItem或者destroyItem。最後在更新的後期會調用finishUpdate。當finishUpdate返回時 instantiateItem返回的對象應該添加到父ViewGroup destroyItem返回的對象應該被ViewGroup刪除。methodisViewFromObject(View, Object)代表了當前的頁面是否與給定的鍵相關聯。
對於非常簡單的pageradapter或許你可以選擇用page本身作為鍵,在創建並且添加到viewgroup後instantiateItem方法裡返回該page本身即可
destroyItem將會將該page從viewgroup裡面移除。isViewFromObject方法裡面直接可以返回view == object。
pageradapter支持數據集合的改變,數據集合的改變必須要在主線程裡面執行,然後還要調用notifyDataSetChanged方法。和baseadapter非常相似。數據集合的改變包括頁面的添加刪除和修改位置。viewpager要維持當前頁面是活動的,所以你必須提供getItemPosition方法。
二、解析
viewpager不直接處理每一個視圖而是將各個視圖與一個鍵聯系起來。這個鍵用來跟蹤且唯一代表一個頁面,不僅如此,該鍵還獨立於這個頁面所在adapter的位置。當pageradapter將要改變的時候他會調用startUpdate函數,接下來會調用一次或多次的instantiateItem或者destroyItem。最後在更新的後期會調用finishUpdate。當finishUpdate返回時 instantiateItem返回的對象應該添加到父ViewGroup destroyItem返回的對象應該被ViewGroup刪除。methodisViewFromObject(View, Object)代表了當前的頁面是否與給定的鍵相關聯。
對於非常簡單的pageradapter或許你可以選擇用page本身作為鍵,在創建並且添加到viewgroup後instantiateItem方法裡返回該page本身即可destroyItem將會將該page從viewgroup裡面移除。isViewFromObject方法裡面直接可以返回view == object。
對於上面兩段話,我這裡有兩點要著重講一下:
1、第一段說明了,鍵(Key)的概念,首先這裡要清楚的一點是,每個滑動頁面都對應一個Key,而且這個Key值是用來唯一追蹤這個頁面的,也就是說每個滑動頁面都與一個唯一的Key一一對應。大家先有這個概念就好,關於這個Key是怎麼來的,下面再講。
2、第二段簡單講了一個應用,即將當前頁面本身的View作為Key。其實這個應用就是我們前一章講的例子應用。不太理解?沒關系,下面細講。下面我們講講Key的問題。
三、關於Key
現在我帶著大家看看幾個方法的官方文檔:
1.首先,destroyItem():
該方法實現的功能是移除一個給定位置的頁面。適配器有責任從容器中刪除這個視圖。這是為了確保在finishUpdate(viewGroup)返回時視圖能夠被移除。
在引入部分的例子中我們是這樣做的:
@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.
返回當前有效視圖的個數。然後我們還:
@Override public int getCount() { // TODO Auto-generated method stub return viewList.size(); }
返回了當前要滑動視圖的個數,與官方說明一致。
四、最難的兩個來了
1.instantiateItem (ViewGroup container, int position)
這個函數的實現的功能是創建指定位置的頁面視圖。適配器有責任增加即將創建的View視圖到這裡給定的container中,這是為了確保在finishUpdate(viewGroup)返回時this is be done!
返回值:返回一個代表新增視圖頁面的Object(Key),這裡沒必要非要返回視圖本身,也可以這個頁面的其它容器。其實我的理解是可以代表當前頁面的任意值,只要你可以與你增加的View一一對應即可,比如position變量也可以做為Key(最後我們舉個例子試試可不可行)
心得 :
(1)從說明中可以看到,在代碼中,我們的責任是將指定position的視圖添加到conatiner中
(2)Key的問題:從這個函數就可以看出,該函數返回值就是我們根據參數position增加到conatiner裡的View的所對應的Key!!!!!!!
(3)“it only must ensure this is done by the time it returns fromfinishUpdate(ViewGroup).”這句話在destroyItem()的函數說明中同樣出現過,這說明在 finishUpdate(viewGroup)執行完後,有兩個操作,一個是原視圖的移除(不再顯示的視圖),另一個是新增顯示視圖(即將顯示的視圖)
還是一開始引入的例子中,我們是這樣做的:
@Override public Object instantiateItem(ViewGroup container, int position) { // TODO Auto-generated method stub container.addView(viewList.get(position)); return viewList.get(position); } };
在這裡,我們做了兩件事
第一:將參數裡給定的position的視圖,增加到conatiner中,供其創建並顯示、。
第二:返回當前position的View做為此視圖的Key。還記得API官方文檔中下面這段話麼?
對於非常簡單的pageradapter或許你可以選擇用page本身作為鍵,在創建並且添加到viewgroup後instantiateItem方法裡返回該page本身即可destroyItem將會將該page從viewgroup裡面移除。isViewFromObject方法裡面直接可以返回view == object。
這裡就把當前的View當作Key傳過出去!!!!
2.isViewFromObject (View view, Object object)
功能:該函數用來判斷instantiateItem(ViewGroup, int)函數所返回來的Key與一個頁面視圖是否是代表的同一個視圖(即它倆是否是對應的,對應的表示同一個View)
返回值:如果對應的是同一個View,返回True,否則返回False。
在上面的例子中,我們這樣做的:
@Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub return arg0 == arg1; }
由於在instantiateItem()中,我們作為Key返回來的是當前的View,所以在這裡判斷時,我們直接將Key與View看是否相等來判斷是否是同一個View。
五、自定義Key實例
經過上面的講解,想必大家給Key的概念應該有個清楚的理解,下面舉個例子來說明Key與View的關系,由於Key與View要一一對應,所以我把每個視圖所處的位置Position作為Key,在上章例子的基礎上更改的,下面先看全部代碼,然後看部分講解:
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數組 private ViewPager viewPager; // 對應的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裝入數組中 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 //根據傳來的key,找到view,判斷與傳來的參數View arg0是不是同一個視圖 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)); //把當前新增視圖的位置(position)作為Key傳過去 return position; } }; viewPager.setAdapter(pagerAdapter); } }
在這裡更改了兩個地方:
1、先看Key的產生的位置instantiateItem()
@Override public Object instantiateItem(ViewGroup container, int position) { // TODO Auto-generated method stub container.addView(viewList.get(position)); //把當前新增視圖的位置(position)作為Key傳過去 return position; }
我們在上講也講了在這個函數中Key是作為返回值與當前裝入Container中的視圖對應起來的。所以在這裡我們返回postion與container.addView(viewList.get(position));裡的viewList.get(position)這個視圖對應起來。
2、isViewFromObject ()
@Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub //根據傳來的key,找到view,判斷與傳來的參數View arg0是不是同一個視圖 return arg0 == viewList.get((int)Integer.parseInt(arg1.toString())); }
判斷從instantiateItem()返回來的Key與當前的View是否能對應起來,我們知道從instantiateItem傳過來的其實是position,所以我們要根據position找到View,然後跟參數中的View arg0判斷。
但在真正操作時出現了問題,我們要先將obect對應轉換為int類型:(int)Integer.parseInt(arg1.toString());然後再根據position找到對應的View;
效果圖:三個View之間的滑動切換
這裡只所以與上章不一樣,僅僅只有上部分一部分的地方才有滑動切換,是因為我更改了布局文件:
<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,只所以這麼做,是為了告訴大家,只要在想要實現滑動切換的地方添加上<android.support.v4.view.ViewPager />就可以實現切換,無所謂位置和大小,跟普通控件一樣!!!!!!
效果:點擊字體,字體變大 主要利用的getView()方法和setOnItemClickListener()方法 ListText.java 復制代碼 代碼如下: pac
Spinner控件是一個下拉列表 1.實現Spinner的系統默認設置 2.實現自定義設置: 3.使用的監聽器接口是:OnItemSelectedListener系統默認
上面一篇博客,介紹了Studio的優點與1.0 RC的安裝與上手體驗,沒想到google的更新速度這麼快,已經出了RC 2版本,主要是修復一些bug。那麼今天就帶大家預覽
一、ActionBar概述ActionBar是androiD3.0以後新增的組件,主要用於標示應用程序以及用戶所處的位置並提供相關操作以及全局的導航功能。下