最近在做自定义控件时,发现一个极其常用的效果--广告条,即图片的自动轮播效果。现在市面上大多数的APP软件都在使用这种展示广告的效果。闲来无事,我简单翻看了一下自己的手机软件,几乎都使用了这种图片自动轮播的策略来实现展示广告的效果:

                                

结合自己所掌握的技术,不难分析这种广告轮播策略的实现原理:

1、利用ViewPager来接收来自网络的图片

2、定时的切换ViewPager里展示的图片

想要实现上面的效果,我们需要掌握三方面的知识:ViewPager的使用原理、网络图片的读取原理、定时器的原理。OK,下面就让我们一起去剖析每一部分的原理,进而实现我们想要的效果吧。先上一个效果图看看效果:

           

1、ViewPager的基本使用

ViewPager是Android扩展包V4包中的类,这个类可以让用户左右切换当前的View。

1、ViewPager类直接继承了ViewGroup类,所以它是一个容器类,可以在其中添加其他的view对象。

2、ViewPager类需要一个PagerAdapter适配器来给它提供数据。

3、ViewPager经常和Fragment一起使用,并且提供了专门的FragmentPagerAdapter和FragmentStatePagerAdapter类供Fragment中的ViewPager使用。

在使用ViewPager的时候,需要现在布局文件中定义该控件,我们项目中的布局如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><android.support.v4.view.ViewPagerandroid:id="@+id/viewPager"android:layout_width="match_parent"android:layout_height="200dp" /><LinearLayoutandroid:id="@+id/desc_layout"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignBottom="@id/viewPager"android:background="#33000000"android:orientation="vertical" ><TextViewandroid:id="@+id/tv_image_desc"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:text="@string/app_name"android:textColor="@android:color/white"android:textSize="18sp" /><!-- 小点点动态的通过代码区添加,这里只提供一个容器,用来存储小点点 --><LinearLayoutandroid:id="@+id/point_group"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:orientation="horizontal" ></LinearLayout></LinearLayout></RelativeLayout>

经过我们的分析可知,ViewPager其实就是一个容器,我们向容器中添加的是View对象,显然我们需要展示的 广告图片不会只有一条,所以我们采用一个List<View>集合来存放需要展示的广告的View对象,然后通过PagerAdapter将数据设置给ViewPager来完成展示工作。在实际开发中,我们要展示的广告图片一般都是来自互联网的,所以我采用了Volley来获取网络图片。

2、Volley方式获取网络图片

volley获取网络图片的基本方法请参考Android Volley完全解析(二),使用Volley加载网络图片。

在这个Demo中,根据图片轮播的需求,我对Volley进行了一些简单的封装,集成了一个处理网络图片的工具,代码如下:

/*** 使用Volley框架获得网络图片* * @author Administrator* */
public class ImageUtils {/*** 如果宽高不指定,会根据ImageView的设置进行图片压缩* * @param context* @param imageView*            将图片设置到哪一个ImageView上* @param iamgeUrl*            图片地址* @param defaultImageResId*            默认显示的图片资源id* @param errorImageResId*            加载失败时显示的图片资源id*/public static void getImage(Context context, ImageView imageView, String iamgeUrl, int defaultImageResId, int errorImageResId) {getImage(context, imageView, iamgeUrl, defaultImageResId, errorImageResId, 0, 0);}/*** * @param context* @param imageView* @param iamgeUrl* @param defaultImageResId* @param errorImageResId* @param maxWidth* @param maxHeight*/public static void getImage(Context context, ImageView imageView, String iamgeUrl, int defaultImageResId, int errorImageResId, int maxWidth, int maxHeight) {try {/* volley */// 获得请求队列RequestQueue mQueue = Volley.newRequestQueue(context);// 图片的缓存暂时是一个空实现,没有做任何处理ImageLoader imageLoader = new ImageLoader(mQueue, new com.android.volley.toolbox.ImageLoader.ImageCache() {@Overridepublic void putBitmap(String arg0, Bitmap arg1) {}@Overridepublic Bitmap getBitmap(String arg0) {return null;}});// 第一个参数是将图片设置到哪一个ImageView上,第二个参数是默认的图片资源id,第三个参数是失败时显示的图片资源idImageListener listener = ImageLoader.getImageListener(imageView, defaultImageResId, errorImageResId);ImageSize imageSize = getImageViewWidth(imageView);if (maxWidth != 0 && maxHeight != 0) {imageSize.width = maxWidth;imageSize.height = maxHeight;}Log.d("imageSize", "width>>" + imageSize.width + "height>>" + imageSize.height);imageLoader.get(iamgeUrl, listener, imageSize.width, imageSize.height);} catch (Exception e) {// TODO: handle exception}}/*** 根据ImageView获得适当的压缩的宽和高* * @param imageView* @return*/private static ImageSize getImageViewWidth(ImageView imageView) {ImageSize imageSize = new ImageSize();final DisplayMetrics displayMetrics = imageView.getContext().getResources().getDisplayMetrics();final LayoutParams params = imageView.getLayoutParams();int width = params.width == LayoutParams.WRAP_CONTENT ? 0 : imageView.getWidth(); // Get// actual// image// widthif (width <= 0)width = params.width; // Get layout width parameterif (width <= 0)width = getImageViewFieldValue(imageView, "mMaxWidth"); // Check// maxWidth// parameterif (width <= 0)// width = displayMetrics.widthPixels;width = 350;int height = params.height == LayoutParams.WRAP_CONTENT ? 0 : imageView.getHeight(); // Get// actual// image// heightif (height <= 0)height = params.height; // Get layout height parameterif (height <= 0)height = getImageViewFieldValue(imageView, "mMaxHeight"); // Check// maxHeight// parameterif (height <= 0)// height = displayMetrics.heightPixels;height = 350;imageSize.width = width;imageSize.height = height;return imageSize;}private static class ImageSize {int width;int height;}/*** 反射获得ImageView设置的最大宽度和高度* * @param object* @param fieldName* @return*/private static int getImageViewFieldValue(Object object, String fieldName) {int value = 0;try {Field field = ImageView.class.getDeclaredField(fieldName);field.setAccessible(true);int fieldValue = (Integer) field.get(object);if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {value = fieldValue;}} catch (Exception e) {}return value;}}

代码中的注释已经很详细了,我这里就不做过多的赘述,在后面我也会提供源码下载,需要的朋友可以直接看源码。

PS:本人写代码很烂,所有代码中有好多地方有待优化,期盼着您能及时指出我的不足之处,以便大家共同学习进步。

网络资源的地址采用JSONArray的方式加载,在主Activity的onCreate方法中初始化的时候,就加载网络资源,初始化的代码如下:

/*** 初始化的操作*/private void initView() {viewPager = (ViewPager) findViewById(R.id.viewPager);desc_image = (TextView) findViewById(R.id.tv_image_desc);point_group = (LinearLayout) findViewById(R.id.point_group);// 广告的图片资源ArrayadvertiseArray = new JSONArray();try {JSONObject advertise0 = new JSONObject();advertise0.putOpt("advertise", "http://pic1.ooopic.com/uploadfilepic/sheji/2009-09-12/OOOPIC_wenneng837_200909122b2c8368339dd52a.jpg:小泡泡");JSONObject advertise1 = new JSONObject();advertise1.putOpt("advertise", "http://image.zcool.com.cn/59/54/m_1303967870670.jpg:时代会远去,记忆不会,流行会过时,也会回来");JSONObject advertise2 = new JSONObject();advertise2.putOpt("advertise", "http://image.zcool.com.cn/47/19/1280115949992.jpg:小心闪电");JSONObject advertise3 = new JSONObject();advertise3.putOpt("advertise", "http://image.zcool.com.cn/59/11/m_1303967844788.jpg:闪亮的年代");JSONObject advertise4 = new JSONObject();advertise4.putOpt("advertise", "http://image.zcool.com.cn/56/35/1303967876491.jpg:时光会紧锁,美梦不曾停");advertiseArray.put(advertise0);advertiseArray.put(advertise1);advertiseArray.put(advertise2);advertiseArray.put(advertise3);advertiseArray.put(advertise4);initSource(advertiseArray, true);} catch (JSONException e) {e.printStackTrace();}}

网络图片的地址后边跟的是描述信息,在真正的项目开发中,这一部分可以使用配置文件来定义图片的地址和描述信息。

图片下边的小点点是通过代码动态添加的,需要展示几张图片,就添加几个小点点,定义ViewPager的图片滑动的监听,当图片滑动的时候,设置小点点的背景以及显示的描述信息,这一部分对应的代码如下所示:

<span style="white-space:pre">  </span>/*** 初始化资源。将资源Array封装成List<ImageView>集合,传递给ViewPager的适配器* * @param advertiseArray* @param fitXY*            拉伸展开,适应屏幕的xy,否则水平居中*/private void initSource(final JSONArray advertiseArray, boolean fitXY) {views = new ArrayList<View>();for (int i = 0; i < advertiseArray.length(); i++) {if (fitXY) {views.add(View.inflate(MainActivity.this, R.layout.image_advertise_fit, null));} else {views.add(View.inflate(MainActivity.this, R.layout.image_advertise_center, null));}// 添加指示点ImageView point = new ImageView(this);LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);params.rightMargin = 20;params.gravity = Gravity.CENTER;point.setLayoutParams(params);point.setBackgroundResource(R.drawable.point_bg);if (i == 0) {point.setEnabled(true);// 将小点点设置成灰色} else {point.setEnabled(false);}point_group.addView(point);}// 准备好了views,之后设置ViewPager的适配器AdvertiseAdapter adapter = new AdvertiseAdapter(this, views, advertiseArray);// 设置适配器,向viewpager容器中添加图片viewPager.setAdapter(adapter);// 让ViewPager左右滑动的时候无限循环viewPager.setCurrentItem(Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2 % views.size()));// 设置viewpager滑动时候的监听,设置图片的描述和小点点的切换viewPager.setOnPageChangeListener(new OnPageChangeListener() {/*** 页面切换后调用*/@Overridepublic void onPageSelected(int position) {position = position % views.size();// 设置图片的文字描述信息String result = advertiseArray.optJSONObject(position).optString("advertise");String desc = result.substring(result.lastIndexOf(":") + 1, result.length());desc_image.setText(desc);// 改变指示点的状态// 当前位置的点设为灰色,truepoint_group.getChildAt(position).setEnabled(true);// 上一个位置的点设为透明的 falsepoint_group.getChildAt(lastPosition).setEnabled(false);lastPosition = position;}/*** 页面正在滑动的时候的回调*/@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}/*** 页面状态发生改变的时候回调*/@Overridepublic void onPageScrollStateChanged(int state) {}});}

ViewPager的适配器如下:

public class AdvertiseAdapter extends PagerAdapter {private Context context;private List<View> views;JSONArray advertiseArray;public AdvertiseAdapter() {super();}public AdvertiseAdapter(Context context, List<View> views, JSONArray advertiseArray) {this.context = context;this.views = views;this.advertiseArray = advertiseArray;}/*** 获得页面的总数*/@Overridepublic int getCount() {return Integer.MAX_VALUE;}/*** 判断View和object的对应关系*/@Overridepublic boolean isViewFromObject(View view, Object object) {return (view == object);}/*** 销毁对应位置的object*/@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {((ViewPager) container).removeView(views.get(position % views.size()));}/*** 获取相应位置的view * container view的容器,其实就是ViewPager本身 * position 相应的位置*/@Overridepublic Object instantiateItem(ViewGroup container, int position) {((ViewPager) container).addView(views.get(position % views.size()));View view = views.get(position % views.size());// 读取图片url的地址String result = advertiseArray.optJSONObject(position % views.size()).optString("advertise");// String desc = result.substring(result.lastIndexOf(":") + 1,// result.length());String imageUrl = result.substring(0, result.lastIndexOf(":"));// 广告图片存放的ImageViewImageView ivAdvertise = (ImageView) view.findViewById(R.id.ivAdvertise);// ImageUtils工具就已经将网络图片设置到了ivAdvertise这个ImageView上了ImageUtils.getImage(context, ivAdvertise, imageUrl, R.drawable.ic_launcher, R.drawable.ic_launcher);return view;}
}

在适配器中,将页面的总数设置成整数的最大值,其实就是无限大了,目的就是为了实现ViewPager左右的无限滑动,需要注意的就是position的位置需要做一些运算来获得view在集合中的位置,position % views.size(),获取view在views集合中真实的位置。

3、定时切换ViewPager,实现轮播效果

定时轮播我目前想到有三种策略:

1、定时器timer

2、开启子线程,while true循环

3、使用handler方式发送延时消息,实现循环
这里我使用的是第三种,handler发送延时消息来完成轮播效果。首先定义一个Handler,在它的handleMessage方法中,发送一个延时消息,这就实现了循环发送消息的循环效果

private Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {// viewPager滑动到下一页viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);// 发送一个延时消息,延时2秒钟继续执行handler,达到循环的效果if (isRunning) {handler.sendEmptyMessageDelayed(0, 2000);}};};

OK,写到这里一个Android广告条的轮播效果也就实现了,通过这个例子,我们学习了如何使用volley加载 网络图片以及ViewPager的基本使用方式,同时对于定时器 又有了一个全新的认识。
PS:本人写代码很烂,所有代码中有好多地方有待优化,期盼着您能及时指出我的不足之处,以促进大家的共同进步。

点我下载源码

Android广告条效果--使用Volley实现网络图片的自动轮播(仿淘宝、网易广告页轮播效果)相关推荐

  1. Android 实现图片轮播(仿淘宝首页商品轮播展示)

    一  引用依赖 // 图片轮播图implementation 'com.github.dongjunkun:BannerLayout:1.0.6' 二 创建图片加载工具类 public class G ...

  2. ViewFlipper实现文字轮播(仿淘宝头条垂直滚动广告)

    ViewFlipper实现文字轮播(仿淘宝头条垂直滚动广告) 广告条目可以单独写成布局文件,然后在布局文件或者代码中添加到总布局中 从源码可以看出,其实ViewFlipper间接的继承了FrameLa ...

  3. jQuery仿淘宝精品服饰广告的实现

    技术栈涉及 隐式迭代的遍历  筛选选择器 和为元素排序等 代码如下: <!DOCTYPE html> <html><head><meta charset=&q ...

  4. 仿淘宝网站的TabPage导航效果

    代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w ...

  5. 原生JS写仿淘宝搜索框(代码+效果),可实现3级搜索哦!

    闲来无事,用原生JS写了一个淘宝搜索框,用的淘宝的接口,可直接进行商品搜索. 写在前面: 1.记得引用jquery啊! 2.有人私信我说css样式不能用,那是因为复制代码的时候,有空格,只需要自己把c ...

  6. Android中顶部Tab带滑动选项卡之二选一,仿淘宝宝贝收藏和店铺收藏

    周末刚过,对于礼拜一可能大家的心情还沉浸在周末那种放松的那种状态下.我也是.出于无聊,随便翻看了一下之前写过的一个商城类项目,来这里和大家分享其中的一个小功能,就当是练练手,进入工作状态. 在这里声明 ...

  7. jQuery 仿淘宝 鼠标悬停显示大图效果

    页面只需要包含 jquery库, bigpic.js 和 bigpic.css即可自动给页面上符合条件的图片加上悬停效果. <script type="text/javascript& ...

  8. vue-element-admin 简单实现仿淘宝实现商品图片放大镜效果

    1.HTML <template><div v-loading="Loading" class="goodsUpload"><!- ...

  9. Android基础控件——ViewFlipper的使用,仿淘宝头条垂直滚动广告条

    ViewFlipper的使用,仿淘宝头条垂直滚动广告条 学习,学习,学以致用 ViewFlipper是安卓自带的控件,很多人可能很少知道这个控件,这个控件很简单,也很好理解,能不能用上实战就看你们的本 ...

最新文章

  1. 编码小记(未整理-持续更新)
  2. IOS Xcode提交代码到github上
  3. CTO梁军离职,市值蒸发59亿,核心技术人才仅剩3人!寒武纪“动荡”的6周年
  4. 国内外包行业的现状分析
  5. 3)机器学习基石笔记 Lecture3:Types of Learning
  6. 关系的三类完整性约束
  7. 感动 ∣她养我长大,我陪她到老!90后女孩带痴呆症养母读研
  8. C语言逗号表达式 - C语言零基础入门教程
  9. Ajax基石脚本异步并发调用参数传递
  10. 资源放送丨数据安全:Oracle多场景下比特币勒索的揭密与恢复实战
  11. 【js】js传递对象
  12. IOS 开展 分别制定了iphone 和 ipad 好? 或开发一个 Universal好?
  13. 计算机专业范文推荐信,出国留学推荐信范文,计算机专业
  14. 计算机八进制 算法视频,八进制转二进制计算器
  15. 腾讯应用宝市场的app 安全评估报告怎么写
  16. 树的直径,树的中心,树的重心
  17. Java用户注册服务器发送短信验证码功能实现
  18. CS269I:Incentives in Computer Science 学习笔记 Lecture 17 评分规则和同辈预测(诚实预报和反馈激励)
  19. 会计与计算机发展现状及发展趋势,论会计电算化的发展现状和趋势分析
  20. cglib BeanCopier的使用

热门文章

  1. 各种数据结构及其应用场景
  2. html5plus (H5 WebApp)
  3. Oracle 的 decode 函数用法
  4. python 保存xls文件
  5. 【100亿次的挑战】之拜年红包和春晚彩蛋
  6. 小米笔记本pro蓝屏记录
  7. 利用Python制作动图演示坐标变换理论
  8. 什么是python全栈_什么是python全栈
  9. java框架ssm_【Java】SSM框架整合 附源码
  10. 苹果ios 11系统无法连接服务器,ios11 App Store无法连接解决办法,亲测可用