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組件,代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <Gallery android:id="@+id/gallery" android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:layout_marginTop="30dp" />
</LinearLayout>

現在在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(mGalleryItemBackground);
            return imageView;
        }
    }

在編寫ImageAdapter類時應注意的兩點:

  1. 在ImageAdapter類的構造方法中獲得了Gallery組件的屬性信息。這些信息被定義在res/values/attrs.xml文件中,代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="Gallery">
        <attr name="android:galleryItemBackground" />
    </declare-styleable>
</resources>

上面的屬性信息用於設置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; /*本範例需使用到的class*/
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
{
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);                      /* 透過findViewById取得 */
    Gallery g = (Gallery) findViewById(R.id.mygallery); /* 新增一ImageAdapter並設定給Gallery對象 */
    g.setAdapter(new ImageAdapter(this));               /* 設定一個itemclickListener並Toast被點選圖片的位置 */
    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         /* 改寫BaseAdapter自定義一ImageAdapter class */
  { 
    int     mGalleryItemBackground;
    private Context mContext;         /* ImageAdapter的建構子 */
    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); /* 使用在res/values/attrs.xml中的定義 的Gallery屬性. */
      mGalleryItemBackground = a.getResourceId(R.styleable.Gallery_android_galleryItemBackground, 0); ///*取得Gallery屬性的Index
      a.recycle();/* 讓對象的styleable屬性能夠反覆使用 */
    } 

    public int getCount()               /* 一定要重寫的方法getCount,傳回圖片數目總數 */
    {
       //return myImageIds.length;
      return Integer.MAX_VALUE;
    } 

    public Object getItem(int position) /* 一定要重寫的方法getItem,傳回position */
    {
      return position;
    } 

    public long getItemId(int position) /* 一定要重寫的方法getItemId,傳回position */
    {
      return position;
    } 

    public View getView(int position, View convertView, ViewGroup parent)/* 一定要重寫的方法getView,傳回一View對象 */
    {  
//      if (position == getCount())
//      {
//        position = 0;
//      }
      ImageView i = new ImageView(mContext);                
      i.setImageResource(myImageIds[position%myImageIds.length]);              /* 設定圖片給imageView對象 */
      i.setScaleType(ImageView.ScaleType.FIT_XY);            /* 重新設定圖片的寬高 */
      i.setLayoutParams(new Gallery.LayoutParams(136, 88));  /* 重新設定Layout的寬高 */
      i.setBackgroundResource(mGalleryItemBackground);       /* 設定Gallery背景圖 */
      return i;                                              /* 傳回imageView物件 */
    }  
  }
}


發佈了38 篇原創文章 · 獲贊 12 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章