Android開源代碼解讀のOnScrollListener實現ListActivity滾屏首字母提示

OnScrollListener接口是定義在AbsListView中的,而AbsListView的直接子類有GridView和ListView,非直接子類有ExpandableListView。OnScrollListener的完整路徑是frameworks\base\core\java\android\widget\AbsListView.java,代碼如下:

[java]
 /**
  * Interface definition for a callback to be invoked when the list or grid
  * has been scrolled.
  */
 public interface OnScrollListener {
 
     /**
      * The view is not scrolling. Note navigating the list using the trackball counts as
      * being in the idle state since these transitions are not animated.
      */
     public static int SCROLL_STATE_IDLE = 0;
 
     /**
      * The user is scrolling using touch, and their finger is still on the screen
      */
     public static int SCROLL_STATE_TOUCH_SCROLL = 1;
 
     /**
      * The user had previously been scrolling using touch and had performed a fling. The
      * animation is now coasting to a stop
      */
     public static int SCROLL_STATE_FLING = 2;
 
     /**
      * Callback method to be invoked while the list view or grid view is being scrolled. If the
      * view is being scrolled, this method will be called before the next frame of the scroll is
      * rendered. In particular, it will be called before any calls to
      * {@link Adapter#getView(int, View, ViewGroup)}.
      *
      * @param view The view whose scroll state is being reported
      *
      * @param scrollState The current scroll state. One of {@link #SCROLL_STATE_IDLE},
      * {@link #SCROLL_STATE_TOUCH_SCROLL} or {@link #SCROLL_STATE_IDLE}.
      */
     public void onScrollStateChanged(AbsListView view, int scrollState);
 
     /**
      * Callback method to be invoked when the list or grid has been scrolled. This will be
      * called after the scroll has completed
      * @param view The view whose scroll state is being reported
      * @param firstVisibleItem the index of the first visible cell (ignore if
      *        visibleItemCount == 0)
      * @param visibleItemCount the number of visible cells
      * @param totalItemCount the number of items in the list adaptor
      */
     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
             int totalItemCount);
 }
 /**
  * Interface definition for a callback to be invoked when the list or grid
  * has been scrolled.
  */
 public interface OnScrollListener {
 
    /**
      * The view is not scrolling. Note navigating the list using the trackball counts as
      * being in the idle state since these transitions are not animated.
      */
     public static int SCROLL_STATE_IDLE = 0;
 
    /**
      * The user is scrolling using touch, and their finger is still on the screen
      */
     public static int SCROLL_STATE_TOUCH_SCROLL = 1;
 
    /**
      * The user had previously been scrolling using touch and had performed a fling. The
      * animation is now coasting to a stop
      */
     public static int SCROLL_STATE_FLING = 2;
 
    /**
      * Callback method to be invoked while the list view or grid view is being scrolled. If the
      * view is being scrolled, this method will be called before the next frame of the scroll is
      * rendered. In particular, it will be called before any calls to
      * {@link Adapter#getView(int, View, ViewGroup)}.
      *
      * @param view The view whose scroll state is being reported
      *
      * @param scrollState The current scroll state. One of {@link #SCROLL_STATE_IDLE},
      * {@link #SCROLL_STATE_TOUCH_SCROLL} or {@link #SCROLL_STATE_IDLE}.
      */
     public void onScrollStateChanged(AbsListView view, int scrollState);
 
    /**
      * Callback method to be invoked when the list or grid has been scrolled. This will be
      * called after the scroll has completed
      * @param view The view whose scroll state is being reported
      * @param firstVisibleItem the index of the first visible cell (ignore if
      *        visibleItemCount == 0)
      * @param visibleItemCount the number of visible cells
      * @param totalItemCount the number of items in the list adaptor
      */
     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
             int totalItemCount);
 }該接口定義瞭三種滾動狀態和兩個回調函數,下面的代碼使用onScroll來實現滾屏時提示內容首字母功能,當然,重點在例子的實現分析上面,並不局限於onScroll的使用。直接先看MainActivity的實現吧:(代碼來自APIDemos,有修改)
 
 
[java]
 package hust.iprai.asce1885;
 
 import android.app.ListActivity;
 import android.content.Context;
 import android.graphics.PixelFormat;
 import android.os.Bundle;
 import android.os.Handler;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.AbsListView;
 import android.widget.AbsListView.OnScrollListener;
 import android.widget.ArrayAdapter;
 import android.widget.TextView;
 
 /**
  * 直接繼承ListActivity,免去瞭ListView的繼承,同時實現OnScrollListener接口
  *
  */
 public class MainActivity extends ListActivity implements OnScrollListener {
     
     private final class RemoveWindow implements Runnable {
 
         public void run() {
             removeWindow();
         }
         
     }
     
     private RemoveWindow mRemoveWindow = new RemoveWindow();
     Handler mHandler = new Handler();
     private WindowManager mWindowManager;
     private TextView mDialogText;
     private boolean mShowing; //是否顯示mDialogText 
     private boolean mReady; //mDialogText是否已準備好 
     private char mPrevLetter = Character.MIN_VALUE;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         
         //獲取Window窗口管理服務 
         mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
         
         //使用ArrayAdapter將字符串數組中的數據映射到TextView中 
         setListAdapter(new ArrayAdapter<String>(this, 
                 android.R.layout.simple_list_item_1, mStrings));
         
         //設置滾動監聽器ScrossListener 
         getListView().setOnScrollListener(this);
         
         //獲取LayoutInflater服務 
         LayoutInflater inflate = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         
         //從xml文件生成TextView對象 
         mDialogText = (TextView) inflate.inflate(R.layout.list_position, null);
         mDialogText.setVisibility(View.INVISIBLE);
         
         //將Runnable添加到消息隊列中 
         mHandler.post(new Runnable() {
 
             public void run() {
                 mReady = true;
                 //設置mDialogText的WindowManager.LayoutParams參數 
                 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                         LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
                         WindowManager.LayoutParams.TYPE_APPLICATION,
                         WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                             | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                         PixelFormat.TRANSLUCENT);
                 mWindowManager.addView(mDialogText, lp);
             }
             
         });
         
     }
     
     @Override
     protected void onDestroy() {
         super.onDestroy();
         mWindowManager.removeView(mDialogText);
         mReady = false;
     }
 
     @Override
     protected void onPause() {
         super.onPause();
         removeWindow();
         mReady = false;
     }
 
     @Override
     protected void onResume() {
         super.onResume();
         mReady = true;
     }
 
     //OnScrollListener的回調函數 
     public void onScroll(AbsListView view, int firstVisibleItem,
             int visibleItemCount, int totalItemCount) {
         if (mReady) {
             //取得當前ListView中第一項內容的首字母 
             char firstLetter = mStrings[firstVisibleItem].charAt(0);
             
             //當mDialogText還不可見且當前首字母於前次滾動後首字母不一致時 
             //將mDialogText設置為可見 
             if (!mShowing && firstLetter != mPrevLetter) {
                 mShowing = true;
                 mDialogText.setVisibility(View.VISIBLE);
             }
             
             //將首字母顯示出來 
             mDialogText.setText(((Character)firstLetter).toString());
             //將消息隊列中還在等待post的mRemoveWindow清除 
             mHandler.removeCallbacks(mRemoveWindow);
             //將Runnable mRemoveWindow添加到消息隊列中,並延遲3s後運行 
             //實現的功能就是在mDialogText顯示3s後,將它設置為不可見 
             mHandler.postDelayed(mRemoveWindow, 3000);
             mPrevLetter = firstLetter;
         }
     }
 
     //OnScrollListener的回調函數 
     public void onScrollStateChanged(AbsListView view, int scrollState) {
         
     }
     
     //將mDialogText設置為不可見 
     private void removeWindow() {
         if (mShowing) {
             mShowing = false;
             mDialogText.setVisibility(View.INVISIBLE);
         }
     }
     
     //用於顯示的模擬數據 
     private String[] mStrings = Cheeses.sCheeseStrings;
 }
 package hust.iprai.asce1885;
 
import android.app.ListActivity;
 import android.content.Context;
 import android.graphics.PixelFormat;
 import android.os.Bundle;
 import android.os.Handler;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.AbsListView;
 import android.widget.AbsListView.OnScrollListener;
 import android.widget.ArrayAdapter;
 import android.widget.TextView;
 
/**
  * 直接繼承ListActivity,免去瞭ListView的繼承,同時實現OnScrollListener接口
  *
  */
 public class MainActivity extends ListActivity implements OnScrollListener {
 
  private final class RemoveWindow implements Runnable {
 
  public void run() {
    removeWindow();
   }
  
  }
 
  private RemoveWindow mRemoveWindow = new RemoveWindow();
  Handler mHandler = new Handler();
  private WindowManager mWindowManager;
  private TextView mDialogText;
  private boolean mShowing; //是否顯示mDialogText
  private boolean mReady; //mDialogText是否已準備好
  private char mPrevLetter = Character.MIN_VALUE;
 
    @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
       
         //獲取Window窗口管理服務
         mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
       
         //使用ArrayAdapter將字符串數組中的數據映射到TextView中
         setListAdapter(new ArrayAdapter<String>(this,
           android.R.layout.simple_list_item_1, mStrings));
       
         //設置滾動監聽器ScrossListener
         getListView().setOnScrollListener(this);
       
         //獲取LayoutInflater服務
         LayoutInflater inflate = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
       
         //從xml文件生成TextView對象
         mDialogText = (TextView) inflate.inflate(R.layout.list_position, null);
         mDialogText.setVisibility(View.INVISIBLE);
       
         //將Runnable添加到消息隊列中
         mHandler.post(new Runnable() {
 
   public void run() {
     mReady = true;
     //設置mDialogText的WindowManager.LayoutParams參數
     WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
       LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
       WindowManager.LayoutParams.TYPE_APPLICATION,
       WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
       PixelFormat.TRANSLUCENT);
     mWindowManager.addView(mDialogText, lp);
    }
         
         });
       
     }
   
     @Override
  protected void onDestroy() {
   super.onDestroy();
   mWindowManager.removeView(mDialogText);
   mReady = false;
  }
 
 @Override
  protected void onPause() {
   super.onPause();
   removeWindow();
   mReady = false;
  }
 
 @Override
  protected void onResume() {
   super.onResume();
   mReady = true;
  }
 
    //OnScrollListener的回調函數
  public void onScroll(AbsListView view, int firstVisibleItem,
    int visibleItemCount, int totalItemCount) {
   if (mReady) {
    //取得當前ListView中第一項內容的首字母
    char firstLetter = mStrings[firstVisibleItem].charAt(0);
   
    //當mDialogText還不可見且當前首字母於前次滾動後首字母不一致時
    //將mDialogText設置為可見
    if (!mShowing && firstLetter != mPrevLetter) {
     mShowing = true;
     mDialogText.setVisibility(View.VISIBLE);
    }
   
    //將首字母顯示出來
    mDialogText.setText(((Character)firstLetter).toString());
    //將消息隊列中還在等待post的mRemoveWindow清除
    mHandler.removeCallbacks(mRemoveWindow);
    //將Runnable mRemoveWindow添加到消息隊列中,並延遲3s後運行
    //實現的功能就是在mDialogText顯示3s後,將它設置為不可見
    mHandler.postDelayed(mRemoveWindow, 3000);
    mPrevLetter = firstLetter;
   }
  }
 
 //OnScrollListener的回調函數
  public void onScrollStateChanged(AbsListView view, int scrollState) {
  
  }
 
  //將mDialogText設置為不可見
  private void removeWindow() {
   if (mShowing) {
    mShowing = false;
    mDialogText.setVisibility(View.INVISIBLE);
   }
  }
 
  //用於顯示的模擬數據
  private String[] mStrings = Cheeses.sCheeseStrings;
 }mDialogText的佈局文件list_position.xml如下:[html]
 <?xml version="1.0" encoding="utf-8"?>
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
     android:textSize="50sp"
     android:textColor="#99FFFFFF"
     android:typeface="monospace"
     android:background="#BB000000"
     android:minWidth="70dip"
     android:maxWidth="70dip"
     android:padding="10dip"
     android:gravity="center"
 />
 <?xml version="1.0" encoding="utf-8"?>
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
     android:textSize="50sp"
     android:textColor="#99FFFFFF"
     android:typeface="monospace"
     android:background="#BB000000"
     android:minWidth="70dip"
     android:maxWidth="70dip"
     android:padding="10dip"
     android:gravity="center" />程序運行結果如下圖所示:

摘自 ASCE1885

發佈留言