Welcome

首页 / 移动开发 / Android / Android组件banner实现左右滑屏效果

什么是banner组件?在许多Android应用上,比如爱奇艺客户端、百度美拍、应用宝等上面,都有一个可以手动滑动的小广告条,这就是banner,实际应用中的banner,其信息(图片和点击行为)是后台可配置的,是需要通过网络从后台拉取的。网上有许多手动滑屏的例子,但是一般只是个demo,无法在实际中使用,因为其一般没有考虑如下几类问题:图片缓存、OOM问题、是否可灵活配置、是否预留外部接口以及是否封装良好。没有良好的封装,手动滑屏加在代码中,会使得代码变得很烂很脆弱。

1.原理
参见下图。整个组件是一个FrameLayout,里面有两个view,第一个是LinearLayout,承载了4个(或多个)可以滑动的view,见图中绿色背景的部分;第二个是一个RelativeLayout,在其底部放置了一个LinearLayout,在LinearLayout的内部放置了若干个小圆点,用来指示当前屏幕的索引。手势检测用了GestureDetector,并实现了OnGestureListener接口。为了能控制滑动速度,采用了Scroller弹性滑动对象。
为什么组件继承FrameLayout,是因为用于指示的小圆点是出现在view上面的,一个view叠在另一个view上面,这就是FrameLayout的特性


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的子viewprivate LinearLayout linearLayoutScrolLayout; //linearLayoutScrolLayout的子view,用于放置若干个小圆点private LinearLayout linearLayoutForDot; private Scroller mScroller;private Context mContext;private OnBannerClickListener mBannerClickListener; //屏幕及其bitmapprivate 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 indexprivate 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.3125fpublic 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(); //定时器的时间间隔 单位:mspublic static final int TIMER_DURATION = 5000; private TimerTask mTimerTask = new TimerTask(){@Overridepublic 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; }};}; //用于获取bitmapprivate 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;}//初始化时不显示bannerthis.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设置默认bitmapBitmapFactory.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向其获取bitmapImageManager 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的低版本bugif(mVersionCode <= 5){ linearLayoutScrolLayout.setBaselineAligned(false);}//初始化四个滑动viewfor(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);//小圆点距底部的距离 单位:pxlayoutParams.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 implementsOnGestureListener{ 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触发 */@Overridepublic 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");} @Overridepublic 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;} @Overridepublic void computeScroll(){ if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); }} @Overrideprotected 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;} } }} @Overrideprotected 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/>* 注意:在这里,设置宽和高将不起作用*/@Overridepublic void setLayoutParams(android.view.ViewGroup.LayoutParams params){params.width = mScreenWidth;params.height = mScreenHeight; super.setLayoutParams(params);} //标志view AttachedToWindow@Overrideprotected void onAttachedToWindow(){super.onAttachedToWindow();mTimerResume = true;} //标志view已经脱离window,典型的情形是view被销毁了,此时取消timer@Overrideprotected 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;} //单击事件@Overridepublic 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中屏幕的indexprivate int index = -1;//响应urlprivate String responseUrl = "";//动作种类private int action = -1;//gameidprivate 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")@Overridepublic String toString(){ return String.format("BannerMotionEvent { index=%d, action=%d, responseUrl=%s, gameId=%s, gameType=%s, title=%s }",index, action, responseUrl, gameId, gameType, title);}} @Overridepublic void onBannerInfoSuccess(List<BannerItem> items){Logger.d(TAG, "onBannerInfoSuccess");mBannerItemsList = items;mHandler.sendEmptyMessage(MESSAGE_FETCH_BANNER_SUCCESS);} @Overridepublic 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 );}} 
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。