http://blog.csdn.net/singwhatiwanna/article/details/8875241
- 原理
参见下图。整个组件是一个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.BannerInfoHandler
- {
- private 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 = 0;
- public static final int MESSAGE_AUTO_SCROLL = 1;
- public static final int MESSAGE_FETCH_BANNER_SUCCESS = 2;
- public 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 = 5000;
- private 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;
- mBannerItemsList.clear();
- mBannerItemsList = null;
- }
- //单击事件
- @Override
- public void onBannerClick( BannerMotionEvent bannerMotionEvent )
- {
- final int position = bannerMotionEvent.index;
- if(mContext == null)
- return;
- NotificationInfo notificationInfo = new NotificationInfo();
- notificationInfo.msgType = bannerMotionEvent.getAction();
- int action = bannerMotionEvent.getAction();
- if(action == NotificationInfo.NOTIFICATION_SINGLEGAME_MSG) //单个游戏消息,直接启动该游戏
- {
- try
- {
- notificationInfo.gameId = Integer.parseInt( bannerMotionEvent.getGameId() );
- notificationInfo.gameType = Integer.parseInt( bannerMotionEvent.getGameType() );
- }
- catch (NumberFormatException e)
- {
- Logger.e(TAG, e.toString());
- return;
- }
- }
- else if(action == NotificationInfo.NOTIFICATION_GAMEPAGE_MSG) //游戏主页消息,通过客户端展示游戏主页
- {
- try
- {
- notificationInfo.gameId = Integer.parseInt( bannerMotionEvent.getGameId() );
- }
- catch (NumberFormatException e)
- {
- Logger.e(TAG, e.toString());
- return;
- }
- notificationInfo.issueTitle = bannerMotionEvent.getTitle();
- }
- else if(action == NotificationInfo.NOTIFICATION_SHOW_WEBVIEW_MSG) //交叉推广消息,通过一个webview展示
- {
- notificationInfo.issueTitle = bannerMotionEvent.getTitle();
- notificationInfo.openUrl = bannerMotionEvent.getResponseUrl();
- }
- else //reserved
- {
- return;
- }
- Intent intent = notificationInfo.generateIntent(mContext);
- if(intent != null)
- mContext.startActivity(intent);
- }
- /**
- * ScrollBanner所关联的banner项 可以为多个 一个为一屏
- */
- public static class BannerItem extends Object
- {
- public static final String ACTION = "action";
- public static final String URL = "url";
- public static final String IMGURL = "imgurl";
- public static final String GAMEID = "gameid";
- public static final String GAMETYPE = "gametype";
- public static final String TITLE = "title";
- public int index = -1;
- public int action = -1;
- public String url = "";
- public String imgUrl = "";
- public String gameId = "";
- public String gameType = "";
- public String title = "";
- public BannerItem(){}
- }
- /**
- * BannerMotionEvent:单击banner所产生的事件对象<br/>
- *getAction()来获取动作类别<br/>
- *getResponseUrl()来获取响应url<br/>
- *...
- */
- public static class BannerMotionEvent extends Object
- {
- /**
- * ACTION_PLAY_FLASH: 播放游戏
- */
- public static final int ACTION_PLAY = 2;
- /**
- * ACTION_HOMEPAGE:打开官网
- */
- public static final int ACTION_HOMEPAGE = 3;
- /**
- * ACTION_OPEN_URL:打开指定url
- */
- public static final int ACTION_OPEN_URL = 4;
- //banner中屏幕的index
- private int index = -1;
- //响应url
- private String responseUrl = "";
- //动作种类
- private int action = -1;
- //gameid
- private String gameId = "";
- //gametype flash游戏(0) or h5游戏(1)
- private String gameType = "";
- //webview的标题
- private String title = "";
- public BannerMotionEvent(int index, int action, String responseUrl,
- String gameId, String gameType, String title)
- {
- BannerMotionEvent.this.index = index;
- BannerMotionEvent.this.action = action;
- BannerMotionEvent.this.responseUrl = responseUrl;
- BannerMotionEvent.this.gameId = gameId;
- BannerMotionEvent.this.gameType = gameType;
- BannerMotionEvent.this.title = title;
- }
- /**
- * 获取当前BannerMotionEvent事件对象的动作种类
- * @return 动作种类:ACTION_PLAY等
- */
- public int getAction()
- {
- return action;
- }
- /**
- * 获取当前BannerMotionEvent事件对象的title
- * @return title webview的标题
- */
- public String getTitle()
- {
- return title;
- }
- /**
- * 获取当前BannerMotionEvent事件对象的gameId
- * @return gameId
- */
- public String getGameId()
- {
- return gameId;
- }
- /**
- * 获取当前BannerMotionEvent事件对象的gameType
- * @return gameType 0 or 1
- */
- public String getGameType()
- {
- return gameType;
- }
- /**
- * 获取当前BannerMotionEvent事件对象的响应url
- * @return 响应url
- */
- public String getResponseUrl()
- {
- return responseUrl;
- }
- @SuppressLint("DefaultLocale")
- @Override
- public String toString()
- {
- return String.format("BannerMotionEvent { index=%d, action=%d, responseUrl=%s, gameId=%s, gameType=%s, title=%s }",
- index, action, responseUrl, gameId, gameType, title);
- }
- }
- @Override
- public void onBannerInfoSuccess(List<BannerItem> items)
- {
- Logger.d(TAG, "onBannerInfoSuccess");
- mBannerItemsList = items;
- mHandler.sendEmptyMessage(MESSAGE_FETCH_BANNER_SUCCESS);
- }
- @Override
- public void onBannerInfoFailed()
- {
- Logger.e(TAG, "onBannerInfoFailed");
- }
- }
ComponentCallBack.java
- public interface ComponentCallBack
- {
- public static interface OnBannerClickListener
- {
- /**
- * banner单击事件
- * @param bannerMotionEvent 单击事件对象,包含所需的响应信息
- * 参见 {@link BannerMotionEvent}
- */
- public abstract void onBannerClick( BannerMotionEvent bannerMotionEvent );
- }