天天看點

Android Gallery元件實作循環顯示圖像

  Gallery元件主要用于橫向顯示圖像清單,不過按正常做法。Gallery元件隻能有限地顯示指定的圖像。也就是說,如果為Gallery元件指定了10張圖像,那麼當Gallery元件顯示到第10張時,就不會再繼續顯示了。這雖然在大多數時候沒有什麼關系,但在某些情況下,我們希望圖像顯示到最後一張時再重第1張開始顯示,也就是循環顯示。要實作這種風格的Gallery元件,就需要對Gallery的Adapter對象進行一番改進。

  Gallery元件的傳統用法

  在實作可循環顯示圖像的Gallery元件之前先來回顧一下Gallery元件的傳統用法。Gallery元件可以橫向顯示一個圖像清單,當單擊目前圖像的後一個圖像時,這個圖像清單會向左 移動一格,當單擊目前圖像的前一個圖像時,這個圖像清單會向右移動一樣。也可以通過拖動的方式來向左和向右移動圖像清單。目前顯示的是第1個圖像的效果如圖1所示。Gallery元件顯示到最後一個圖像的效果如圖2所示

  

  圖1

  

  圖2

  從圖2可以看出,當顯示到最後一個圖像時,清單後面就沒有圖像的,這也是Gallery元件的基本顯示效果。在本文後面的部分将詳細介紹如何使Gallery元件顯示到最後一個圖像時會從第1個圖像開始顯示。

  好了,現在我們來看一下圖1和圖2的效果是如何做出來的吧。Gallery既然用于顯示圖像,那第1步就必須要有一些圖像檔案用來顯示。現在可以随意準備一些圖像。在本文的例子中準備了6個jpg檔案(item1.jpg至item15.jpg)。将這些檔案都放在res\drawable目錄中

  下面将這些圖像的資源ID都儲存在int數組中,代碼如下: private int[] myImageIds = {R.drawable.photo1, R.drawable.photo2, R.drawable.photo3, R.drawable.photo4, R.drawable.photo5, R.drawable.photo6,}; 在本例的main.xml檔案中配置了一個Gallery元件,代碼如下: 現在在onCreate方法中裝載這個元件,代碼如下: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 裝載Gallery元件 Gallery gallery = (Gallery) findViewById(R.id.gallery); // 建立用于描述圖像資料的ImageAdapter對象 ImageAdapter imageAdapter = new ImageAdapter(this); // 設定Gallery元件的Adapter對象 gallery.setAdapter(imageAdapter); } 在上面的代碼中涉及到一個非常重要的類:ImageAdapter。該類是android.widget.BaseAdapter的子類,用于描述圖像資訊。下面先看一下這個類的完整代碼 public class ImageAdapter extends BaseAdapter { int mGalleryItemBackground; private Context mContext; public ImageAdapter(Context context) { mContext = context; // 獲得Gallery元件的屬性 TypedArray typedArray = obtainStyledAttributes(R.styleable.Gallery); mGalleryItemBackground = typedArray.getResourceId( R.styleable.Gallery_android_galleryItemBackground, 0); } // 傳回圖像總數 public int getCount() { return resIds.length; } public Object getItem(int position) { return position; } public long getItemId(int position) { return position; } // 傳回具體位置的ImageView對象 public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView = new ImageView(mContext); // 設定目前圖像的圖像(position為目前圖像清單的位置) imageView.setImageResource(myImageIds[position]); imageView.setScaleType(ImageView.ScaleType.FIT_XY) ; imageView.setLayoutParams(new Gallery.LayoutParams(163, 106)); // 設定Gallery元件的背景風格 imageView.setBackgroundResource(mGalleryItemBackgr ound); return imageView; } } 在編寫ImageAdapter類時應注意的兩點:

  1. 在ImageAdapter類的構造方法中獲得了Gallery元件的屬性資訊。這些資訊被定義在res\values\attrs.xml檔案中,代碼如下: 上面的屬性資訊用于設定Gallery的背景風格。

  2. 在ImageAdapter類中有兩個非常重要的方法:getCount和getView。其中getCount方法用于傳回圖像總數,要注意的是,這個總數不能大于圖像的實際數(可以小于圖像的實際數),否則會抛出越界異常。當Gallery元件要顯示某一個圖像時,就會調用getView方法,并将目前的圖像索引(position參數)傳入該方法。一般getView方法用于傳回每一個顯示圖像的元件(ImageView對象)。從這一點可以看出,Gallery元件是即時顯示圖像的,而不是一下将所有的圖像都顯示出來。在getView方法中除了建立了ImageView對象,還用從resIds數組中獲得了相應的圖像資源ID來設定在ImageView中顯示的圖像。最後還設定了Gallery元件的背景顯示風格。

  OK,現在來運作這個程式,來回拖動圖像清單,就會看到如圖1和圖2所示的效果了。

  循環顯示圖像的原理

  循環顯示有些類似于循環連結清單,最後一個結點的下一個結點又是第1個結點。循環顯示圖像也可以模拟這一點。

  也許細心的讀者從上一節實作的ImageAdapter類中會發現些什麼。對!就是getView方法中的position參數和getCount方法的關系。position參數的值是不可能超過getCount方法傳回的值的,也就是說,position參數值的範圍是0至getCount() - 1。

  如果這時Gallery元件正好顯示到最後一個圖像,position參數值正好為getCount() - 1。那麼我們如何再讓Gallery顯示下一個圖像呢?也就是說讓position參數值再增1,對!将getCount()方法的傳回值也增1。

  那麼這裡還有一個問題,如果position參數值無限地增加,就意味着myImageIds數組要不斷地增大,這樣會大大消耗系統的資源。想到這,就需要解決兩個問題:既要position不斷地增加,又讓resIds數組中儲存的圖像資源ID是有限的,該怎麼做呢?對于getCount()方法非常好解決,可以讓getCount方法傳回一個很大的數,例如,Integer.MAX_VALUE。這時position參數值就可以随着Gallery元件的圖像不斷向前移動而增大。現在myImageIds數組隻有6個元素,如果position的值超過數組邊界,要想繼續循環取得數組中的元素(也就是說,當position的值是6時,取myImageIds數組的第0個元素,是6時取第1個元素),最簡單的方法就是取餘,代碼如下:

  myImageIds[position % myImageIds.length] 在本節對ImageAdapter類做了如下兩個改進:

  1. 使getCount方法傳回一個很大的值。建議傳回Integer.MAX_VALUE。

  2. 在getView方法中通過取餘來循環取得resIds數組中的圖像資源ID。

  通過上面兩點改進,可以使圖像清單在向右移動時會循環顯示圖像。當然,這種方法從本質上說隻是僞循環,也就是說,如果真把圖像移動到getCount方法傳回的值那裡,那也就顯示到最後一個圖像的。不過在這裡getCount方法傳回的是Integer.MAX_VALUE,這個值超過了20億,除非有人真想把圖像移動到第20億的位置,否則Gallery元件看着就是一個循環顯示圖像的元件。

  實作循環顯示圖像的Gallery元件

  在本節将組出與循環顯示圖像相關的ImageAdapter類的完整代碼。讀者可以從中看到上一節介紹的兩點改進。為了使界面看上去更豐滿,本例還在單擊某一個Gallery元件中的圖像時在下方顯示一個放大的圖像(使用ImageSwitcher元件)。本例的顯示效果如圖3所示。當不斷向後移動圖像時,圖像可不斷顯示,讀者可以自己運作本例來體驗一下。

  本例中Main類的完整代碼如下: package irdc.EX04_10; import android.app.Activity; import android.os.Bundle; import android.content.Context; import android.content.res.TypedArray; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.Gallery; import android.widget.ImageView; import android.widget.Toast; import android.widget.AdapterView.OnItemClickListener; public class EX04_10 extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Gallery g = (Gallery) findViewById(R.id.mygallery); g.setAdapter(new ImageAdapter(this)); setTitle("Gallery 實作循環浏覽圖檔"); g.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View v, int position, long id) { Toast.makeText(EX04_10.this, getString(R.string.my_gallery_text_pre) + position + getString(R.string.my_gallery_text_post), Toast.LENGTH_SHORT).show(); } }); } public class ImageAdapter extends BaseAdapter { int mGalleryItemBackground; private Context mContext; private int[] myImageIds = {R.drawable.photo1, R.drawable.photo2, R.drawable.photo3, R.drawable.photo4, R.drawable.photo5, R.drawable.photo6,}; public ImageAdapter(Context c) { mContext = c; TypedArray a = obtainStyledAttributes(R.styleable.Gallery); mGalleryItemBackground = a.getResourceId(R.styleable.Gallery_android_galler yItemBackground, 0); // } public int getCount() { //return myImageIds.length; return Integer.MAX_VALUE; } public Object getItem(int position) { return position; } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { // if (position == getCount()) // { // position = 0; // } ImageView i = new ImageView(mContext); i.setImageResource(myImageIds[position%myImageIds. length]); i.setScaleType(ImageView.ScaleType.FIT_XY); i.setLayoutParams(new Gallery.LayoutParams(136, 88)); i.setBackgroundResource(mGalleryItemBackground); return i; } } } 2011-01-15 14:33:17