1. 程式人生 > >android中左右滑屏的實現(廣告位banner元件)

android中左右滑屏的實現(廣告位banner元件)

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               
  1. 原理

參見下圖。整個元件是一個FrameLayout,裡面有兩個view,第一個是LinearLayout,承載了4個(或多個)可以滑動的view,見圖中綠色背景的部分;第二個是一個RelativeLayout,在其底部放置了一個LinearLayout,在LinearLayout的內部放置了若干個小圓點,用來指示當前螢幕的索引。手勢檢測用了GestureDetector,並實現了OnGestureListener介面。為了能控制滑動速度,採用了Scroller彈性滑動物件。

為什麼元件繼承FrameLayout,是因為用於指示的小圓點是出現在view上面的,一個view疊在另一個view上面,這就是FrameLayout的特性

什麼是banner元件?在許多android應用上,比如愛奇藝客戶端、百度美拍、應用寶等上面,都有一個可以手動滑動的小廣告條,這就是banner,實際應用中的banner,其資訊(圖片和點選行為)是後臺可配置的,是需要通過網路從後臺拉取的。網上有許多手動滑屏的例子,但是一般只是個demo,無法在實際中使用,因為其一般沒有考慮如下幾類問題:圖片快取、OOM問題、是否可靈活配置、是否預留外部介面以及是否封裝良好。沒有良好的封裝,手動滑屏加在程式碼中,會使得程式碼變得很爛很脆弱。

 

        2.     功能、效果

  • banner屬性可動態設定,預設數量為4,可以調整預設的數量
  • banner資訊從後臺獲取,banner的條數就是螢幕的數量
  • 可自動滑動也能手動滑動
  • 圖片下載為多執行緒,並採用常見的三級cache策略(記憶體、檔案、網路),節省流量,並處理了OOM異常
  • 內部處理點選事件,同時預留出了介面函式
  • banner封裝成一個ViewGroup類,使用起來簡單,最少只需要兩行程式碼

 

        3.    程式碼

 

程式碼註釋寫的比較詳細,應該很好理解。分為2個檔案,一個是banner的類,另一個是介面宣告。

ScrollBanner.java

/** * ScrollBanner 支援滑屏效果的FrameLayout子類,可設定螢幕數量,尺寸。<br/> * 典型的用法:<br/> *   ScrollBanner scrollBanner = new ScrollBanner(this, mScreenWidth, 100, this);<br/> *  linearLayout.addView(scrollBanner);<br/> *注意事項:<br/> *1.如果重新設定ScrollBanner的LayoutParams,則引數中的寬和高屬性將被忽略,仍然採用物件例項化的寬和高<br/> *2.點選事件的回撥如果設為null,則採用預設的事件回撥<br/> *3.通過setOverScrollMode來設定 banner是否能夠滑出螢幕的邊界<br/> *4通過xml方式載入banner,需要進行如下呼叫:<br/> *  setResolution(width, height);<br/>  setOnBannerClickListener(bannerClickListener);<br/>  showBanner()<br/> * @author singwhatiwanna * @version 2013.3.4 * */public class ScrollBanner extends FrameLayout implements ComponentCallBack.OnBannerClickListener, ResponseHandler.BannerInfoHandlerprivate static final String TAG = "ScrollBanner"private HorizontalScrollViewEx mHorizontalScrollViewEx;  //ScrollBanner的子view private LinearLayout linearLayoutScrolLayout;  //linearLayoutScrolLayout的子view,用於放置若干個小圓點 private LinearLayout linearLayoutForDot;  private Scroller mScroller;  private Context mContext; private OnBannerClickListener mBannerClickListener; //螢幕及其bitmap private List<View> mLinearLayoutScreens = new ArrayList<View>(); private List<Bitmap> mBannerBitmaps = new ArrayList<Bitmap>(); //banner資訊 private List<BannerItem> mBannerItemsList = new ArrayList<BannerItem>(); //小圓點 private List<ImageView> mImageViewList = new ArrayList<ImageView>(); private Drawable mPageIndicator; private Drawable mPageIndicatorFocused;  //banner預設圖片 private Bitmap mDefaultBitmap; private int mScreenWidth; private int mScreenHeight; private int mScrollX; //current screen index private int mWhich = 0public static final int MESSAGE_AUTO_SCROLL = 1public static final int MESSAGE_FETCH_BANNER_SUCCESS = 2public static final int MARGIN_BOTTOM = 2;  //480*150 banner的圖片尺寸 150.0/480=0.3125f public static final float ratio = 0.3125f//banner的位置 private int mLocation = -1//banner分為幾屏 private int PAGE_COUNT = 4//滑動方向 是否向右滑動 private boolean mScrollToRight = true//是否自動滑屏 private boolean mTimerResume = true//標誌使用者是否手動滑動了螢幕 private boolean mByUserAction = false//標誌banner是否可以滑出邊界 private boolean mOverScrollMode = false//標誌banner可以滑出邊界多少畫素 private int mOverScrollDistance = 0//定時器 用於banner的自動播放 final Timer timer = new Timer(); //定時器的時間間隔 單位:ms public static final int TIMER_DURATION = 5000private TimerTask mTimerTask = new TimerTask() {  @Override  public void run()   {   if (mTimerResume && !mByUserAction)    {    mHandler.sendEmptyMessage(MESSAGE_AUTO_SCROLL);   }   mByUserAction = false;  } }; //ScrollBanner私有handler 用於處理內部邏輯 private Handler mHandler = new Handler() {  public void handleMessage(Message msg)  {   //表示已經執行了onDetachedFromWindow,banner已經被銷燬了   if( mBannerBitmaps == null || mLinearLayoutScreens == null ||      mImageViewList == null || mBannerItemsList == null || mContext == null )    return;      switch (msg.what)   {   case MESSAGE_AUTO_SCROLL:    if (mWhich == PAGE_COUNT - 1)     mScrollToRight = false;    else if(mWhich == 0)    {     mScrollToRight = true;    }    if (mScrollToRight)      mWhich++;    else     {     mWhich--;    }    mHorizontalScrollViewEx.switchView(mWhich);    break;   case MESSAGE_FETCH_BANNER_SUCCESS:    int more = 0;    if(mBannerItemsList != null)     more = mBannerItemsList.size() - PAGE_COUNT;    if(mBannerItemsList.size() > 0)    {     //如果有banner 顯示它     ScrollBanner.this.show(true);    }    //如果後臺返回的banneritem的數量大於預設值4    if(more > 0)    {     for (int i = 0; i < more; i++)      addBannerItem();    }    fetchBannerImages();    break;   default:    break;   }  }; }; //用於獲取bitmap private Handler  mBitmapHandler = new Handler() {  public void handleMessage(Message msg)  {   //表示已經執行了onDetachedFromWindow,banner已經被銷燬了   if( mBannerBitmaps == null || mLinearLayoutScreens == null ||      mImageViewList == null || mBannerItemsList == null || mContext == null )    return;      Bitmap bitmap = (Bitmap)msg.obj;   String urlString = msg.getData().getString("url");   Logger.d(TAG, "url=" + urlString);   if (urlString == null || bitmap == null || mBannerItemsList == null)   {    Logger.w(TAG, "bitmap=null imgurl=" + urlString);    return;   }   for( int i = 0; i < mBannerItemsList.size(); i++ )   {    BannerItem item = mBannerItemsList.get(i);    if(item != null && urlString.equals(item.imgUrl) )    {     Logger.d(TAG, "find " + i + urlString);     if( mBannerBitmaps != null )      {      mBannerBitmaps.set( i, bitmap );      setBannerImages(i);     }     break;    }   }     }; }; public ScrollBanner(Context context) {  this(context, null); } public ScrollBanner(Context context, AttributeSet attrs) {  super(context, attrs);  mContext = context; } public ScrollBanner(Context context, AttributeSet attrs, int defStyle) {  super(context, attrs, defStyle);  mContext = context; } /**  *   * @param context activity例項  * @param width banner的寬度 單位px  * @param height banner的高度 單位dip,-1表示根據圖片比例自適應高度  * @param bannerClickListener 單擊banner的回撥介面  */ public ScrollBanner(Context context, final int width, final int height, OnBannerClickListener bannerClickListener) {  this(context, null);  int activityId = ( (BaseActivity)context ).activityId();  if(activityId == BaseActivity.ACCOUNT_ID)//位置3   mLocation = 3;  else if(activityId == BaseActivity.GAMEZONE_ID)//位置2  {   mLocation = 2;  }    //初始化時不顯示banner  this.show(false);  setResolution(width, height);  setOnBannerClickListener(bannerClickListener);  setDefaultBannerImages();  fetchBannerInfo(); } /**  * 通過xml方式載入banner,必須呼叫此方法才能顯示  */ public void showBanner() {  int activityId = ( (BaseActivity)mContext ).activityId();  if(activityId == BaseActivity.ACCOUNT_ID)//位置3   mLocation = 3;  else if(activityId == BaseActivity.GAMEZONE_ID)//位置2  {   mLocation = 2;  }    setDefaultBannerImages();  fetchBannerInfo(); }  /**  * 暫停滾動  */ public void pauseScroll() {  mTimerResume = false; }  /**  * 恢復滾動  */ public void resumeScroll() {  mTimerResume = true; }  /**  * 設定回撥介面  * @param callBack 單擊banner的回撥介面  */ public void setOnBannerClickListener(OnBannerClickListener bannerClickListener) {  mBannerClickListener = (bannerClickListener != null ? bannerClickListener : ScrollBanner.this); } /**  * 設定banner的解析度  * @param width banner的寬度  * @param height banner的高度  */ public void setResolution(final int width, final int height) {  int heightInPx = height;    if(height == -1)   heightInPx = (int)(ratio * width) ;  else  {   Resources resources = getResources();   heightInPx = Math.round( TypedValue.applyDimension(     TypedValue.COMPLEX_UNIT_DIP, height, resources.getDisplayMetrics()) );  }    mScreenWidth = width;  mScreenHeight = heightInPx;  setLayoutParams(new LayoutParams(width, heightInPx));  initScrollView(); }  /**  * 獲取banner的高度  * @return banner的高度 單位:px  */ public int getHeightPixels() {  return mScreenHeight; } /**  * 設定banner是否可以彈性滑出邊界  * @param canOverScroll true表示可以滑出邊界,false不能  */ public void setOverScrollMode(boolean canOverScroll) {  mOverScrollMode = canOverScroll;  if(canOverScroll == false)   mOverScrollDistance = 0; } /**  * 向後臺獲取banner的各種資訊  */ private void fetchBannerInfo() {  NetworkManager netManager = (NetworkManager) AppEngine.getInstance().getManager(    IManager.NETWORK_ID);  netManager.getBannerInfo( String.valueOf(mLocation), ScrollBanner.this ); } /**  * 獲取banner的滑屏影象  */ private void setDefaultBannerImages() {  //為banner設定預設bitmap        BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options();          bitmapFactoryOptions.inJustDecodeBounds = false;          bitmapFactoryOptions.inSampleSize = 2;    Resources res=mContext.getResources();  mDefaultBitmap = BitmapFactory.decodeResource(res, R.drawable.banner_image_default, bitmapFactoryOptions);    for(int i = 0; i < PAGE_COUNT; i++)   mBannerBitmaps.add(i, mDefaultBitmap);  //初始化BannerItem物件  for (int i = 0; i < PAGE_COUNT; i++)   mBannerItemsList.add(i, null);  setBannerImages(-1); } private void fetchBannerImages() {  //表示已經執行了onDetachedFromWindow,banner已經被銷燬了  if( mBannerItemsList == null )   return;    //ImageManager 根據url向其獲取bitmap  ImageManager imageManager = (ImageManager)AppEngine.getInstance().    getManager(IManager.IMAGE_ID);  BannerItem item = null;  for(int i = 0; i < PAGE_COUNT; i++)  {   try   {    item = mBannerItemsList.get(i);   }    catch (IndexOutOfBoundsException e)   {    Logger.e(TAG, "fetchBannerImages error: " + e);   }   catch (Exception e)    {    Logger.e(TAG, "fetchBannerImages error: " + e);   }   //ImageManager為多執行緒,採用常見的三級cache策略(記憶體、檔案、網路)   if( item != null && item.imgUrl != null )    imageManager.loadBitmap( item.imgUrl, mBitmapHandler );  } } /**  * 設定banner的滑屏影象  * @param position 如果position=-1,則表示設定全部bitmap  */ private void setBannerImages(final int position) {  int size = mBannerBitmaps.size();  if (size < PAGE_COUNT || mLinearLayoutScreens == null)  {   return;  }  if(position >=0 && position < PAGE_COUNT )  {   Drawable drawable = mLinearLayoutScreens.get(position).getBackground();   mLinearLayoutScreens.get(position).setBackgroundDrawable   (new BitmapDrawable( mBannerBitmaps.get(position) ) );   drawable.setCallback(null);   drawable = null;      return;  }  for(int i = 0; i < PAGE_COUNT; i++)  {   mLinearLayoutScreens.get(i).setBackgroundDrawable(new BitmapDrawable(mBannerBitmaps.get(i)));  } } /**  * 是否顯示banner  * @param isShow true顯示 false不顯示  */ public void show(boolean isShow) {  if(isShow)  {   this.setVisibility(View.VISIBLE);   mTimerResume = true;  }  else   {   this.setVisibility(View.GONE);   mTimerResume = false;  } } /**  * 切換到指定螢幕  * @param which 螢幕索引  */ public void switchToScreen(final int which) {  mHorizontalScrollViewEx.switchView(which); }  /**  * 設定螢幕的數量 (此函式暫不開放)  * @param count 螢幕數量  */ protected void setScreenCount(final int count) {  PAGE_COUNT = count; } /**  * 設定偏移的距離 如果mOverScrollMode為false,則此設定無效 (此函式暫不開放)  * @param distance  */ protected void setOverScrollDistance(int distance) {  if(distance < 0)   distance = 0;  mOverScrollDistance = mOverScrollMode ? distance : 0; } /**  * 切換小圓點  * @param position current screen index  */ private void switchScreenPosition(final int position) {  if( mPageIndicator == null || mPageIndicatorFocused == null )   return;    int length = 0;  if(mImageViewList != null)   length = mImageViewList.size();  if (position >= length || position < 0 || length <= 0)  {   return;  }  for(int i = 0; i < length; i++)  {   mImageViewList.get(i).setImageDrawable(mPageIndicator);  }    mImageViewList.get(position).setImageDrawable(mPageIndicatorFocused); } /**  * 初始化整個FrameLayout檢視組  */ private void initScrollView() {  setLayoutParams(new LayoutParams(mScreenWidth, mScreenHeight ));  linearLayoutScrolLayout = new LinearLayout(mContext);  linearLayoutScrolLayout.setBackgroundColor(Color.WHITE);  linearLayoutScrolLayout.setOrientation(LinearLayout.HORIZONTAL);    int mVersionCode = 8;  try  {   mVersionCode = Integer.valueOf(android.os.Build.VERSION.SDK);   Logger.d(TAG, "sdk version=" + mVersionCode);  }   catch (Exception e)   {   e.printStackTrace();  }  //針對android1.6及以下的特殊處理 此為android的低版本bug  if(mVersionCode <= 5)  {   linearLayoutScrolLayout.setBaselineAligned(false);  }    //初始化四個滑動view  for(int i = 0; i < PAGE_COUNT; i++)  {   LinearLayout linearLayoutScreen = new LinearLayout(mContext);   linearLayoutScreen.setOrientation(LinearLayout.VERTICAL);   linearLayoutScrolLayout.addView(linearLayoutScreen, new LayoutParams(     mScreenWidth,      LayoutParams.FILL_PARENT));   mLinearLayoutScreens.add(i, linearLayoutScreen);  }  //初始化小圓點檢視  RelativeLayout relativeLayout = new RelativeLayout(mContext);  relativeLayout.setLayoutParams(new LayoutParams(    LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));  //linearLayoutForDot為小圓點檢視  linearLayoutForDot =new LinearLayout(mContext);  android.widget.RelativeLayout.LayoutParams layoutParams =     new android.widget.RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,       LayoutParams.WRAP_CONTENT);  //小圓點距底部的距離 單位:px  layoutParams.bottomMargin = MARGIN_BOTTOM;  layoutParams.rightMargin = MARGIN_BOTTOM;  layoutParams.addRule(android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM);  layoutParams.addRule(android.widget.RelativeLayout.CENTER_HORIZONTAL);  linearLayoutForDot.setLayoutParams(layoutParams);  linearLayoutForDot.setOrientation(LinearLayout.HORIZONTAL);  linearLayoutForDot.setHorizontalGravity(Gravity.CENTER);  linearLayoutForDot.setVerticalGravity(Gravity.CENTER);  //下面兩句實現圓角半透明效果 不採用  //  linearLayoutForDot.setBackgroundResource(R.drawable.round_corner_bg);  //  linearLayoutForDot.getBackground().setAlpha(100);  //初始化4個小圓點  mPageIndicator = getResources().getDrawable(R.drawable.page_indicator);  mPageIndicatorFocused = getResources().getDrawable(R.drawable.page_indicator_focused);  for(int i = 0; i < PAGE_COUNT; i++)  {   ImageView imageView = new ImageView(mContext);   imageView.setImageDrawable(mPageIndicator);   mImageViewList.add(i, imageView);   LinearLayout.LayoutParams layoutParamsForDot =      new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,        LayoutParams.WRAP_CONTENT);   layoutParamsForDot.rightMargin = 5;   linearLayoutForDot.addView(imageView, layoutParamsForDot);  }  mImageViewList.get(0).setImageDrawable(mPageIndicatorFocused);  relativeLayout.addView(linearLayoutForDot);  mHorizontalScrollViewEx = new HorizontalScrollViewEx(mContext, null, mBannerClickListener);  mHorizontalScrollViewEx.setLayoutParams(new LayoutParams(    mScreenWidth * PAGE_COUNT,     LayoutParams.FILL_PARENT));  mHorizontalScrollViewEx.addView(linearLayoutScrolLayout, new LayoutParams(    LayoutParams.FILL_PARENT,     LayoutParams.FILL_PARENT));  mHorizontalScrollViewEx.setHorizontalScrollBarEnabled(false);  mHorizontalScrollViewEx.setHorizontalFadingEdgeEnabled(false);  addView(mHorizontalScrollViewEx);  addView(relativeLayout);  //自動滑屏 5秒一次  timer.schedule(mTimerTask, 5000, TIMER_DURATION); } /**  * 加一個banner頁面 TODO此函式寫的不好  */ private void addBannerItem() {  //表示已經執行了onDetachedFromWindow,banner已經被銷燬了  if( mBannerBitmaps == null || mLinearLayoutScreens == null ||     mImageViewList == null || mContext == null )   return;    //調整螢幕數量和總寬度  PAGE_COUNT += 1;  mHorizontalScrollViewEx.getLayoutParams().width = mScreenWidth * PAGE_COUNT;                  //載入預設圖片資源  if(mDefaultBitmap == null)  {         BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options();           bitmapFactoryOptions.inJustDecodeBounds = false;           bitmapFactoryOptions.inSampleSize = 2;     Resources res=mContext.getResources();   mDefaultBitmap = BitmapFactory.decodeResource(res, R.drawable.banner_image_default, bitmapFactoryOptions);  }  mBannerBitmaps.add(mDefaultBitmap);  mBannerItemsList.add(null);   //加一個螢幕  LinearLayout linearLayoutScreen = new LinearLayout(mContext);  linearLayoutScreen.setOrientation(LinearLayout.VERTICAL);  linearLayoutScreen.setBackgroundDrawable(new BitmapDrawable( mBannerBitmaps.get(PAGE_COUNT - 1) ));  linearLayoutScrolLayout.addView(linearLayoutScreen, new LayoutParams(    mScreenWidth,     LayoutParams.FILL_PARENT));  mLinearLayoutScreens.add(linearLayoutScreen);    //加一個小圓點  ImageView imageView = new ImageView(mContext);  imageView.setImageDrawable(mPageIndicator);  mImageViewList.add(imageView);  LinearLayout.LayoutParams layoutParamsForDot =     new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,       LayoutParams.WRAP_CONTENT);  layoutParamsForDot.rightMargin = 5;  linearLayoutForDot.addView(imageView, layoutParamsForDot);   }  private class HorizontalScrollViewEx extends ViewGroup implements  OnGestureListener {  private GestureDetector mGestureDetector;  private int mWhichScreen;  public HorizontalScrollViewEx(Context context, AttributeSet attrs, OnBannerClickListener bannerClickListener)  {   super(context, attrs);      mGestureDetector = new GestureDetector(this);   //解決長按屏幕後無法拖動的現象   mGestureDetector.setIsLongpressEnabled(false);   //構造彈性滑動物件   mScroller = new Scroller(context);  }  /**   * 切換到指定螢幕   * @param whichScreen 螢幕index   */  public void switchView(int whichScreen)  {   if(mLinearLayoutScreens == null)    return;      // 防止非法引數   if (whichScreen < 0)    whichScreen = 0;   else if(whichScreen >= PAGE_COUNT)    whichScreen = PAGE_COUNT - 1;   Logger.i(TAG, "switch view to " + whichScreen);   int delta = whichScreen * mScreenWidth - HorizontalScrollViewEx.this.getScrollX();   //緩慢滾動到指定位置   mScroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 3);   // refresh   invalidate();   //delta>0 stands for user scroll view to right   if (delta > 0)     mScrollToRight = true;   else    {    mScrollToRight = false;   }   mWhichScreen = whichScreen;   mWhich = whichScreen;   //切換小圓點   switchScreenPosition(mWhichScreen);  }  /**   * 使用者輕觸觸控式螢幕,由1個MotionEvent ACTION_DOWN觸發   */  @Override  public boolean onDown(MotionEvent e)  {   Logger.i("MyGesture", "onDown");      mScrollX = HorizontalScrollViewEx.this.getScrollX();   return true;  }  /**   * 使用者輕觸觸控式螢幕,尚未鬆開或拖動,由一個1個MotionEvent ACTION_DOWN觸發   * 注意和onDown()的區別,強調的是沒有鬆開或者拖動的狀態   */  public void onShowPress(MotionEvent e)  {   Logger.i("MyGesture", "onShowPress");  }  /**   * 使用者(輕觸觸控式螢幕後)鬆開,由一個1個MotionEvent ACTION_UP觸發   */  public boolean onSingleTapUp(MotionEvent e)  {   Logger.i("MyGesture", "onSingleTapUp");   if(mBannerItemsList == null || mBannerItemsList.size() <= mWhichScreen)    return false;      BannerItem bannerItem = mBannerItemsList.get(mWhichScreen);   if(bannerItem != null)   {    BannerMotionEvent bannerMotionEvent =       new BannerMotionEvent(mWhichScreen, bannerItem.action, bannerItem.url,         bannerItem.gameId, bannerItem.gameType, bannerItem.title);    mBannerClickListener.onBannerClick(bannerMotionEvent);   }   return false;  }  /** 使用者按下觸控式螢幕、快速移動後鬆開,由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE,   * 1個ACTION_UP觸發   */  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,    float velocityY)  {   Logger.i("MyGesture", "onFling velocityX=" + velocityX);   mWhichScreen = velocityX > 0 ?     mWhichScreen - 1     : mWhichScreen + 1;   switchView(mWhichScreen);   return true;  }  /**    * 使用者按下觸控式螢幕,並拖動,由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE觸發   */  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,    float distanceY)  {   Logger.i("MyGesture", "onScroll");   //禁止彈性滾動   if (mOverScrollMode == false)    {    float x1 = e1.getX();    float x2 = e2.getX();    if(mWhichScreen == 0 && x1 < x2)     return false;    else if(mWhichScreen == PAGE_COUNT - 1 && x1 > x2)     return false;   }   //   int distance = Math.abs(getScrollX() - mWhichScreen * mScreenWidth); //   if ((mWhichScreen ==0 || mWhichScreen == PAGE_COUNT -1) &&  distance > mOverScrollDistance)//    return false;      this.scrollBy((int)distanceX, 0);   return true;  }  /**   *  使用者長按觸控式螢幕,由多個MotionEvent ACTION_DOWN觸發   */  public void onLongPress(MotionEvent e)  {   Logger.i("MyGesture", "onLongPress");  }  @Override  public boolean onTouchEvent(MotionEvent event)  {   if(event.getAction() == MotionEvent.ACTION_DOWN)   {    mTimerResume = false;    if ( !mScroller.isFinished() )     mScroller.abortAnimation();   }   else if(event.getAction() == MotionEvent.ACTION_UP)   {    //開始自動滑屏    mTimerResume = true;    mByUserAction = true;   }   boolean consume = mGestureDetector.onTouchEvent(event);   if (consume == false && event.getAction() == MotionEvent.ACTION_UP)    {    int curScrollX = HorizontalScrollViewEx.this.getScrollX();    int mWhichScreen = (curScrollX + mScreenWidth / 2) /mScreenWidth;    switchView(mWhichScreen);   }   return consume;  }  @Override  public void computeScroll()  {   if (mScroller.computeScrollOffset())   {    scrollTo(mScroller.getCurrX(), mScroller.getCurrY());    postInvalidate();   }  }  @Override  protected void onLayout(boolean changed, int l, int t, int r, int b)  {   if (changed)    {    int childLeft = 0;    final int childCount = getChildCount();    for (int i=0; i<childCount; i++)    {     final View childView = getChildAt(i);     if (childView.getVisibility() != View.GONE)     {      final int childWidth = childView.getMeasuredWidth();      childView.layout(childLeft, 0,         childLeft+childWidth, childView.getMeasuredHeight());      childLeft += childWidth;     }    }   }  }  @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  {   super.onMeasure(widthMeasureSpec, heightMeasureSpec);      final int width = MeasureSpec.getSize(widthMeasureSpec);      final int count = getChildCount();         for (int i = 0; i < count; i++)   {       getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);      }   scrollTo(mWhich * mScreenWidth, 0);  }   } /**  * override此函式,防止其修改構造方法所定義的寬和高<br/>  *  注意:在這裡,設定寬和高將不起作用  */ @Override public void setLayoutParams(android.view.ViewGroup.LayoutParams params) {  params.width = mScreenWidth;  params.height = mScreenHeight;  super.setLayoutParams(params); } //標誌view AttachedToWindow @Override protected void onAttachedToWindow() {  super.onAttachedToWindow();  mTimerResume = true; } //標誌view已經脫離window,典型的情形是view被銷燬了,此時取消timer @Override protected void onDetachedFromWindow() {  super.onDetachedFromWindow();  Logger.d(TAG, "onDetachedFromWindow");    mTimerResume = false;  int activityId = ( (BaseActivity)mContext ).activityId();  //如果是賬號管理頁面 則釋放記憶體  if(activityId == BaseActivity.ACCOUNT_ID)  {   destroy();  } }  /**  * 銷燬banner  */ public void destroy() {  mTimerTask.cancel();  timer.cancel();  //去除各種bitmap對activity的引用關係  destoryBitmaps();  System.gc(); }  /**  * 去除各種bitmap對activity的引用關係  */ private void destoryBitmaps() {    for (View view : mLinearLayoutScreens)   {   Drawable drawable = view.getBackground();   BitmapDrawable bitmapDrawable = null;   if(drawable instanceof BitmapDrawable)    bitmapDrawable = (BitmapDrawable)drawable;      if(bitmapDrawable != null)   {    //解除drawable對view的引用    bitmapDrawable.setCallback(null);    bitmapDrawable = null;   }  }    for (ImageView imageView : mImageViewList)   {   Drawable drawable = imageView.getDrawable();   if(drawable != null)   {    drawable.setCallback(null);    drawable = null;   }  }    mPageIndicator.setCallback(null);  mPageIndicator = null;  mPageIndicatorFocused.setCallback(null);  mPageIndicatorFocused = null;    mLinearLayoutScreens.clear();  mLinearLayoutScreens = null;    mBannerBitmaps.clear();  mBannerBitmaps = null;    mImageViewList.clear();  mImageViewList = null;    mBa