标签:
最近在开发一款android APP,项目中采用了推送广告的方案,即在手机屏幕上方空出一块区域,加载来自服务器的广告图片,形成banner广告的效果。
开发过程中,百度出了好多种解决方案,其中以ViewPager的方案和重写Gallery的方案居多,学生党的我比较倾向于后者。在编写定制Gallery的过程中参考了ZAKER 5.0.4源代码中的ScrollGallery类(反编译得到的),优化了Gallery向两边滑动到头自动跳转的问题,详细的代码如下:
1 package org.warnier.zhang.support.v1.widget; 2 3 import java.util.Timer; 4 5 import android.content.Context; 6 import android.util.AttributeSet; 7 import android.view.MotionEvent; 8 import android.widget.Gallery; 9 10 public class AdsGallery extends Gallery { 11 12 public Context context; 13 14 public AdsGallery(Context context) { 15 super(context); 16 this.context = context; 17 } 18 19 public AdsGallery(Context context, AttributeSet attrs) { 20 super(context, attrs); 21 this.context = context; 22 } 23 24 public AdsGallery(Context context, AttributeSet attrs, int defStyleAttr) { 25 super(context, attrs, defStyleAttr); 26 this.context = context; 27 } 28 29 public AdsGallery(Context context, AttributeSet attrs, int defStyleAttr, 30 int defStyleRes) { 31 super(context, attrs, defStyleAttr, defStyleRes); 32 this.context = context; 33 } 34 35 @Override 36 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 37 float velocityY) { 38 if (isScrollingLeft(e1, e2)) { 39 playPrevious(); 40 } 41 for (;;) { 42 playNext(); 43 return true; 44 } 45 } 46 47 private boolean isScrollingLeft(MotionEvent paramMotionEvent1, 48 MotionEvent paramMotionEvent2) { 49 return paramMotionEvent2.getX() > paramMotionEvent1.getX(); 50 } 51 52 public boolean playNext() { 53 int i = getSelectedItemPosition(); 54 int j = computeHorizontalScrollRange(); 55 if ((j > 0) && (i < j - 1)) { 56 onKeyDown(22, null); 57 return true; 58 } 59 return false; 60 } 61 62 public boolean playPrevious() { 63 int i = getSelectedItemPosition(); 64 if ((computeHorizontalScrollRange() > 0) && (i > 0)) { 65 onKeyDown(21, null); 66 return true; 67 } 68 return false; 69 } 70 }
滑动广告栏核心类有AdsGallery 和 AdsAdapter,核心类只是优化了滑动体验效果。在org.warnier.zhang.sample包的Demo中,AdsAdapter直接加载了本地的图片,在实际的APP中需要打开新的网络线程从服务器上读取图片资源。滑动广告栏具体功能的实现在org.warnier.zhang.sample包的MainActivity中。在MainActivity的onCreate()方法中初始化AdsGallery ,显示当前广告获得焦点的布局,和计时器;利用Timer和Handler之间进行线程间通信,在Handler中更新AdsGallery当前项。详细的代码如下:
1 package org.warnier.zhang.sample; 2 3 import java.util.Timer; 4 import java.util.TimerTask; 5 6 import org.warnier.zhang.support.v1.widget.AdsAdapter; 7 import org.warnier.zhang.support.v1.widget.AdsGallery; 8 9 import android.util.Log; 10 import android.view.View; 11 import android.widget.ImageView; 12 import android.widget.LinearLayout; 13 import android.app.Activity; 14 import android.graphics.Color; 15 import android.os.Bundle; 16 import android.os.Handler; 17 import android.os.Message; 18 19 public class MainActivity extends Activity { 20 21 private AdsGallery adsGallery; 22 private LinearLayout linearLayout; 23 private int delay = 2500; 24 private int period = 2500; 25 26 @Override 27 protected void onCreate(Bundle savedInstanceState) { 28 super.onCreate(savedInstanceState); 29 setContentView(R.layout.activity_main); 30 // 初始化广告栏控件; 31 adsGallery = (AdsGallery) this.findViewById(R.id.myAdsGallery); 32 adsGallery.setAdapter(new AdsAdapter(this)); 33 34 // 初始化广告焦点指示器; 35 linearLayout = (LinearLayout) this.findViewById(R.id.myAdsIndicator); 36 linearLayout.setBackgroundColor(Color.argb(200, 135, 135, 152)); 37 for (int i = 0; i < 4; i++) { 38 ImageView imageView = new ImageView(this); 39 if (i == 0) { 40 imageView.setBackgroundResource(R.drawable.feature_point_cur); 41 } else 42 imageView.setBackgroundResource(R.drawable.feature_point); 43 linearLayout.addView(imageView); 44 } 45 46 // 初始化计时器和计时器任务; 47 new Timer().schedule(new TimerTask() { 48 49 @Override 50 public void run() { 51 int position = adsGallery.getSelectedItemPosition() + 1; 52 53 // 存放广告栏的当前项; 54 Bundle bundle = new Bundle(); 55 bundle.putInt("position", position); 56 Message msg = new Message(); 57 58 // 设置当前的消息标识符; 59 msg.what = 1; 60 msg.setData(bundle); 61 handler.sendMessage(msg); 62 } 63 }, delay, period); 64 } 65 66 // 初始化Handler,供UI主线程与计时器线程交换数据; 67 private Handler handler = new Handler() { 68 @Override 69 public void handleMessage(android.os.Message msg) { 70 super.handleMessage(msg); 71 switch (msg.what) { 72 case 1: 73 Bundle bundle = msg.getData(); 74 int position = bundle.getInt("position"); 75 Log.i("指示器", "" + position); 76 adsGallery.setSelection(position); 77 refreshIndicator(position); 78 break; 79 80 default: 81 Log.i("msg.what", "消息标识符错误!"); 82 break; 83 } 84 }; 85 }; 86 87 // 刷新广告栏焦点 88 public void refreshIndicator(int position) { 89 LinearLayout layout = (LinearLayout) findViewById(R.id.myAdsIndicator); 90 View v = layout.getChildAt(position % 4); 91 View p = layout.getChildAt((position - 1) % 4); 92 ((ImageView) p).setImageResource(R.drawable.feature_point); 93 ((ImageView) v).setImageResource(R.drawable.feature_point_cur); 94 } 95 }
当然项目中还存在如下问题,欢迎读者交流指正!
(1)广告焦点指示器的第一个圆形图标出现一圈红色背景;
(2)当手动滑动广告栏的过程中,计时器继续运行,广告焦点指示器不止一个出现红色;
(3)能否定制一个能够自动运行的AdsGallery,而不是在Activity中控制运行;
上述问题已经在开发的过程中得到解决,但还是期待读者能够拿出新颖的方案,交流一下!展示和分享的代码是早期的原型Demo,不是项目的实际代码,大家如果采用的话需要根据自己的实际情况加以更改。完整的Eclipse工程下载访问链接: http://pan.baidu.com/s/1dDH7nSd 密码: ah8p。
参考文献:
[1] Android开发权威指南,李宁著,2013-09,北京,人民邮电出版社。
本文历史:
标签:
原文地址:http://www.cnblogs.com/warnier-zhang/p/4262773.html