最近在开发一款android APP,项目中采用了推送广告的方案,即在手机屏幕上方空出一块区域,加载来自服务器的广告图片,形成banner广告的效果。
开发过程中,百度出了好多种解决方案,其中以ViewPager的方案和重写Gallery的方案居多,学生党的我比较倾向于后者。在编写定制Gallery的过程中参考了ZAKER 5.0.4源代码中的ScrollGallery类(反编译得到的),优化了Gallery向两边滑动到头自动跳转的问题,详细的代码如下:
package org.warnier.zhang.support.v1.widget; import java.util.Timer; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.Gallery; public class AdsGallery extends Gallery { public Context context; public AdsGallery(Context context) { super(context); this.context = context; } public AdsGallery(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; } public AdsGallery(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.context = context; } public AdsGallery(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); this.context = context; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (isScrollingLeft(e1, e2)) { playPrevious(); } for (;;) { playNext(); return true; } } private boolean isScrollingLeft(MotionEvent paramMotionEvent1, MotionEvent paramMotionEvent2) { return paramMotionEvent2.getX() > paramMotionEvent1.getX(); } public boolean playNext() { int i = getSelectedItemPosition(); int j = computeHorizontalScrollRange(); if ((j > 0) && (i < j - 1)) { onKeyDown(22, null); return true; } return false; } public boolean playPrevious() { int i = getSelectedItemPosition(); if ((computeHorizontalScrollRange() > 0) && (i > 0)) { onKeyDown(21, null); return true; } return false; } }
滑动广告栏核心类有AdsGallery 和 AdsAdapter,核心类只是优化了滑动体验效果。在org.warnier.zhang.sample包的Demo中,AdsAdapter直接加载了本地的图片,在实际的APP中需要打开新的网络线程从服务器上读取图片资源。滑动广告栏具体功能的实现在org.warnier.zhang.sample包的MainActivity中。在MainActivity的onCreate()方法中初始化AdsGallery ,显示当前广告获得焦点的布局,和计时器;利用Timer和Handler之间进行线程间通信,在Handler中更新AdsGallery当前项。详细的代码如下:
package org.warnier.zhang.sample; import java.util.Timer; import java.util.TimerTask; import org.warnier.zhang.support.v1.widget.AdsAdapter; import org.warnier.zhang.support.v1.widget.AdsGallery; import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.os.Message; public class MainActivity extends Activity { private AdsGallery adsGallery; private LinearLayout linearLayout; private int delay = 2500; private int period = 2500; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化广告栏控件; adsGallery = (AdsGallery) this.findViewById(R.id.myAdsGallery); adsGallery.setAdapter(new AdsAdapter(this)); // 初始化广告焦点指示器; linearLayout = (LinearLayout) this.findViewById(R.id.myAdsIndicator); linearLayout.setBackgroundColor(Color.argb(200, 135, 135, 152)); for (int i = 0; i < 4; i++) { ImageView imageView = new ImageView(this); if (i == 0) { imageView.setBackgroundResource(R.drawable.feature_point_cur); } else imageView.setBackgroundResource(R.drawable.feature_point); linearLayout.addView(imageView); } // 初始化计时器和计时器任务; new Timer().schedule(new TimerTask() { @Override public void run() { int position = adsGallery.getSelectedItemPosition() + 1; // 存放广告栏的当前项; Bundle bundle = new Bundle(); bundle.putInt("position", position); Message msg = new Message(); // 设置当前的消息标识符; msg.what = 1; msg.setData(bundle); handler.sendMessage(msg); } }, delay, period); } // 初始化Handler,供UI主线程与计时器线程交换数据; private Handler handler = new Handler() { @Override public void handleMessage(android.os.Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: Bundle bundle = msg.getData(); int position = bundle.getInt("position"); Log.i("指示器", "" + position); adsGallery.setSelection(position); refreshIndicator(position); break; default: Log.i("msg.what", "消息标识符错误!"); break; } }; }; // 刷新广告栏焦点 public void refreshIndicator(int position) { LinearLayout layout = (LinearLayout) findViewById(R.id.myAdsIndicator); View v = layout.getChildAt(position % 4); View p = layout.getChildAt((position - 1) % 4); ((ImageView) p).setImageResource(R.drawable.feature_point); ((ImageView) v).setImageResource(R.drawable.feature_point_cur); } }
当然项目中还存在如下问题,欢迎读者交流指正!
(1)广告焦点指示器的第一个圆形图标出现一圈红色背景;
(2)当手动滑动广告栏的过程中,计时器继续运行,广告焦点指示器不止一个出现红色;
(3)能否定制一个能够自动运行的AdsGallery,而不是在Activity中控制运行;
上述问题已经在开发的过程中得到解决,但还是期待读者能够拿出新颖的方案,交流一下!展示和分享的代码是早期的原型Demo,不是项目的实际代码,大家如果采用的话需要根据自己的实际情况加以更改。完整的Eclipse工程下载访问链接: http://pan.baidu.com/s/1dDH7nSd 密码: ah8p。