关于广告轮播,大家肯定不会陌生,它在现手机市场各大APP出现的频率极高,它的优点在于"不占屏",可以仅用小小的固定空位来展示几个甚至几十个广告条,而且动态效果很好,具有很好的用户"友好性",下面来看几个示例图:

      

再来看下我仿写的效果:

关于广告轮播Banner这个东西,GitHub上面应该有现成的开源组件,不过我没去找过,觉得实现起来不会太难,就自己去仿写了,下面我说下实现的思路:

1、首先看到这个可以滑动切换图片的界面,我们很自然就会想到ViewPager控件。

2、需要去考虑它的伪循环(其实只是滑到末尾图片再切换到开始图片,给人一种"无限循环"的错觉),做过GalleyView画廊效果的朋友应该很熟悉,当我们滑到画廊到底端,如果想看第一张图片需要再重新滑回去,那么这样给用户的体验就不好,所以我们会在适配器Adapter的getCount()方法里,返回一个很大的数值,让它能够"无限循环"。不清楚的朋友也没关系,下面代码会详细提到。

3、就是考虑它的自动滑动效果,那么很简单的就会去想到定时器,每隔几秒让它自动滑动一次,再通过配合ViewPager的设置当前页面setCurrentItem就可以达到我们想要的效果。

4、最后就是需要考虑到细节方面的东西了,如何让画面滑动配合底部的小圆圈点,我们在做定时器操作的时候,无限循环肯定是一个while永true的状态,当我们切换退出当前界面的时候,这个定时器循环要怎么处理。

好了,考虑好实现原理和流程,我们就可以上手写代码了。

1、首先先来分析下布局:

上面截图说的很详细了,这里直接上代码:

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent" >
  5.  
  6. <android.support.v4.view.ViewPager
  7. android:id="@+id/viewpager"
  8. android:layout_width="match_parent"
  9. android:layout_height="150dp" />
  10.  
  11. <LinearLayout
  12. android:layout_width="match_parent"
  13. android:layout_height="wrap_content"
  14. android:layout_alignBottom="@id/viewpager"
  15. android:background="#33000000"
  16. android:orientation="vertical"
  17. android:padding="5dp" >
  18.  
  19. <TextView
  20. android:id="@+id/tv_bannertext"
  21. android:layout_width="wrap_content"
  22. android:layout_height="wrap_content"
  23. android:layout_gravity="center_horizontal"
  24. android:padding="5dp"
  25. android:text="我是第一个广告语"
  26. android:textColor="@android:color/white" />
  27.  
  28. <LinearLayout
  29. android:id="@+id/points"
  30. android:layout_width="match_parent"
  31. android:layout_height="wrap_content"
  32. android:gravity="center_horizontal"
  33. android:orientation="horizontal" >
  34. </LinearLayout>
  35. </LinearLayout>
  36.  
  37. </RelativeLayout>

布局文件

然后是小圆圈的样式,这里有2个xml,一个是选择状态,一个是空白状态

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <shape xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:shape="oval" >
  4.  
  5. <corners android:radius="0.5dp" />
  6.  
  7. <solid android:color="#55000000" />
  8.  
  9. </shape>

小圆圈正常状态

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <shape xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:shape="oval" >
  4.  
  5. <corners android:radius="0.5dp" />
  6.  
  7. <solid android:color="#AAFFFFFF" />
  8.  
  9. </shape>

小圆圈选中状态

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <selector xmlns:android="http://schemas.android.com/apk/res/android">
  3.  
  4. <item android:drawable="@drawable/point_bg_enable" android:state_enabled="true"></item>
  5. <item android:drawable="@drawable/point_bg_normal" android:state_enabled="false"></item>
  6.  
  7. </selector>

小圆圈背景效果

2、ViewPager适配器

  既然我们使用到了VierPager,那么必须要给它设置一个适配器来装载我们所要展示的广告图,这里需要注意的是getCount()这个方法,正常情况下,我们让它返回的是数据源的长度大小,但这里我们需要实现"无限循环"的效果,这么我们可以返回一个比较大的是比如:Integer.MAX_VALUE,这个数值可是20亿,用户再怎么滑到也不会滑到上亿次级别的吧。然后避免出现空指针异常,我们在下面addView和removeView的时候就不能再直接使用position去索引资源了,我们应该取余item的总数量,这样索引位置就不会超过资源数据的数量,例如1%777=1,1%999=1。

对于ViewPager不熟悉的朋友可以看下我之前写过的一篇文章《安卓开发笔记——ViewPager组件(仿微信引导界面)

  1. package com.lcw.rabbit.banner;
  2.  
  3. import java.util.List;
  4.  
  5. import android.support.v4.view.PagerAdapter;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8. import android.widget.ImageView;
  9. /**
  10. * ViewPager适配器
  11. * @author Rabbit_Lee
  12. *
  13. */
  14. public class BannerAdapter extends PagerAdapter {
  15.  
  16. //数据源
  17. private List<ImageView> mList;
  18.  
  19. public BannerAdapter(List<ImageView> list) {
  20. this.mList = list;
  21. }
  22.  
  23. @Override
  24. public int getCount() {
  25. //取超大的数,实现无线循环效果
  26. return Integer.MAX_VALUE;
  27. }
  28.  
  29. @Override
  30. public boolean isViewFromObject(View arg0, Object arg1) {
  31. return arg0 == arg1;
  32. }
  33.  
  34. @Override
  35. public Object instantiateItem(ViewGroup container, int position) {
  36. container.addView(mList.get(position%mList.size()));
  37. return mList.get(position%mList.size());
  38. }
  39.  
  40. @Override
  41. public void destroyItem(ViewGroup container, int position, Object object) {
  42. container.removeView(mList.get(position%mList.size()));
  43. }
  44.  
  45. }

3、主代码

  首先先说下小圆圈点的实现,这里有2种方式,一种是直接在广告图上"画死",这种方法耗时耗力而且维护起来很不灵活,所以我们使用第二种方式动态生成,根据广告图的资源长度在给定的LinearLayout里去添加圆圈点View。然后我们需要给它一个pointIndex标志位,用它来记录当前所在的页面位置,初始为0,再每次滑动的时候根据这个标志位来切换小圆圈的状态。

再来说下我们最开始的页面位置,我们不可以设置为0(第一页),如果我们设置为0,那么便不能向左滑动了。由于我们在适配器的getCount返回了Integer.MAX_VALUE ,我们可以取它的中间点来作为起始点,用setCurrentItem来出发VierPager的监听器里的onPageSelected的方法,那么左右就都可以滑动了。

  最后就是定时器SystemClock了,我们这里开辟了一条新的线程通过while永true来达到这个效果,让其每隔2秒执行一次设置当前页面的动作,每次只需要简单设置页面+1即可,最后要留意的是我们需要给这个定时器设定一个开关,在我们切换退出该页面的时候要停止掉定时器的操作,也就是去重写我们的onDestroy方法,这里把开关关掉即可。

  1. package com.lcw.rabbit.banner;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. import android.app.Activity;
  7. import android.os.Bundle;
  8. import android.os.SystemClock;
  9. import android.support.v4.view.ViewPager;
  10. import android.support.v4.view.ViewPager.OnPageChangeListener;
  11. import android.view.View;
  12. import android.widget.ImageView;
  13. import android.widget.LinearLayout;
  14. import android.widget.LinearLayout.LayoutParams;
  15. import android.widget.TextView;
  16.  
  17. public class MainActivity extends Activity {
  18.  
  19. // 声明控件
  20. private ViewPager mViewPager;
  21. private List<ImageView> mlist;
  22. private TextView mTextView;
  23. private LinearLayout mLinearLayout;
  24.  
  25. // 广告图素材
  26. private int[] bannerImages = { R.drawable.image1, R.drawable.image2, R.drawable.image3, R.drawable.image4 };
  27. // 广告语
  28. private String[] bannerTexts = { "因为专业 所以卓越", "坚持创新 行业领跑", "诚信 专业 双赢", "精细 和谐 大气 开放" };
  29.  
  30. // ViewPager适配器与监听器
  31. private BannerAdapter mAdapter;
  32. private BannerListener bannerListener;
  33.  
  34. // 圆圈标志位
  35. private int pointIndex = 0;
  36. // 线程标志
  37. private boolean isStop = false;
  38.  
  39. @Override
  40. protected void onCreate(Bundle savedInstanceState) {
  41. super.onCreate(savedInstanceState);
  42. setContentView(R.layout.activity_main);
  43. initView();
  44. initData();
  45. initAction();
  46.  
  47. // 开启新线程,2秒一次更新Banner
  48. new Thread(new Runnable() {
  49.  
  50. @Override
  51. public void run() {
  52. while (!isStop) {
  53. SystemClock.sleep(2000);
  54. runOnUiThread(new Runnable() {
  55.  
  56. @Override
  57. public void run() {
  58. mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1);
  59. }
  60. });
  61. }
  62. }
  63. }).start();
  64. }
  65.  
  66. /**
  67. * 初始化事件
  68. */
  69. private void initAction() {
  70. bannerListener = new BannerListener();
  71. mViewPager.setOnPageChangeListener(bannerListener);
  72. //取中间数来作为起始位置
  73. int index = (Integer.MAX_VALUE / 2) - (Integer.MAX_VALUE / 2 % mlist.size());
  74. //用来出发监听器
  75. mViewPager.setCurrentItem(index);
  76. mLinearLayout.getChildAt(pointIndex).setEnabled(true);
  77. }
  78.  
  79. /**
  80. * 初始化数据
  81. */
  82. private void initData() {
  83. mlist = new ArrayList<ImageView>();
  84. View view;
  85. LayoutParams params;
  86. for (int i = 0; i < bannerImages.length; i++) {
  87. // 设置广告图
  88. ImageView imageView = new ImageView(MainActivity.this);
  89. imageView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
  90. imageView.setBackgroundResource(bannerImages[i]);
  91. mlist.add(imageView);
  92. // 设置圆圈点
  93. view = new View(MainActivity.this);
  94. params = new LayoutParams(5, 5);
  95. params.leftMargin = 10;
  96. view.setBackgroundResource(R.drawable.point_background);
  97. view.setLayoutParams(params);
  98. view.setEnabled(false);
  99.  
  100. mLinearLayout.addView(view);
  101. }
  102. mAdapter = new BannerAdapter(mlist);
  103. mViewPager.setAdapter(mAdapter);
  104. }
  105.  
  106. /**
  107. * 初始化View操作
  108. */
  109. private void initView() {
  110. mViewPager = (ViewPager) findViewById(R.id.viewpager);
  111. mTextView = (TextView) findViewById(R.id.tv_bannertext);
  112. mLinearLayout = (LinearLayout) findViewById(R.id.points);
  113. }
  114.  
  115. //实现VierPager监听器接口
  116. class BannerListener implements OnPageChangeListener {
  117.  
  118. @Override
  119. public void onPageScrollStateChanged(int arg0) {
  120. }
  121.  
  122. @Override
  123. public void onPageScrolled(int arg0, float arg1, int arg2) {
  124. }
  125.  
  126. @Override
  127. public void onPageSelected(int position) {
  128. int newPosition = position % bannerImages.length;
  129. mTextView.setText(bannerTexts[newPosition]);
  130. mLinearLayout.getChildAt(newPosition).setEnabled(true);
  131. mLinearLayout.getChildAt(pointIndex).setEnabled(false);
  132. // 更新标志位
  133. pointIndex = newPosition;
  134.  
  135. }
  136.  
  137. }
  138.  
  139. @Override
  140. protected void onDestroy() {
  141. // 关闭定时器
  142. isStop = true;
  143. super.onDestroy();
  144. }
  145.  
  146. }

 

 好了,到这里代码就结束了,很简单的一个小Demo,这里只是起到抛砖引玉的作用,在我们真正的应用这种广告图不可能直接存放在我们的资源文件里面的,肯定是通过网络去获取的,然后这里就要涉及到了图片的缓存等知识点,关于图片的缓存策略可以看下我之前写过的一篇博文:《安卓开发笔记——关于图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)》。

如果大家有更好的实现方法或者有什么疑问的地方,可以在文章评论给我留言。

作者:李晨玮
出处:http://www.cnblogs.com/lichenwei/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不准,你也好回来找我!

安卓开发笔记——自定义广告轮播Banner(实现无限循环)的更多相关文章

  1. android-自定义广告轮播Banner(无限循环实现)

    关于广告轮播,大家肯定不会陌生,它在现手机市场各大APP出现的频率极高,它的优点在于"不占屏",可以仅用小小的固定空位来展示几个甚至几十个广告条,而且动态效果很好,具有很好的用户& ...

  2. UIScrollView实现图片轮播器及其无限循环效果

    图片轮播器: 一.实现效果 实现图片的自动轮播            二.实现代码 storyboard中布局 代码: 1 #import "YYViewController.h" ...

  3. 安卓开发笔记——自定义HorizontalScrollView控件(实现QQ5.0侧滑效果)

    对于滑动菜单栏SlidingMenu,大家应该都不陌生,在市场上的一些APP应用里经常可以见到,比如人人网,FaceBook等. 前段时间QQ5.0版本出来后也采用了这种设计风格:(下面是效果图) 之 ...

  4. Android真正意义上的无限轮播Banner

    在android开发的时候,经常会使用到轮播图,对于这种效果,一般情况下,我们都会使用一种叫做ViewPager的来实现. 传统的实现逻辑是自定义一个View继承ViewPager,在适配器中 将co ...

  5. 安卓开发笔记——关于开源项目SlidingMenu的使用介绍(仿QQ5.0侧滑菜单)

    记得去年年末的时候写过这个侧滑效果,当时是利用自定义HorizontalScrollView来实现的,效果如下: 有兴趣的朋友可以看看这篇文件<安卓开发笔记——自定义HorizontalScro ...

  6. iOS回顾笔记(05) -- 手把手教你封装一个广告轮播图框架

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  7. 自定义View(二)ViewPage广告轮播

    自定义View的第二个学习案例,使用ViewPage实现广告轮播,通过组合现有的View实现效果如下: 有关ViewPage使用可以学习谷歌官方API,和训练案例: 1.使用ViewPage实现屏幕滑 ...

  8. 安卓开发笔记——打造万能适配器(Adapter)

    为什么要打造万能适配器? 在安卓开发中,用到ListView和GridView的地方实在是太多了,系统默认给我们提供的适配器(ArrayAdapter,SimpleAdapter)经常不能满足我们的需 ...

  9. 安卓开发笔记——深入Activity

    在上一篇文章<安卓开发笔记——重识Activity >中,我们了解了Activity生命周期的执行顺序和一些基本的数据保存操作,但如果只知道这些是对于我们的开发需求来说是远远不够的,今天我 ...

随机推荐

  1. HighCharts之2D柱状图

    1.HighCharts之2D柱状图源码 column.html: <!DOCTYPE html> <html> <head> <meta charset=& ...

  2. xib与nib的区别

    xib和nib都是Interface Builder的图形界面设计文档,nib这个名字来自于NeXTSTEP系统,在NeXTSTEP被Apple收购之前,一直使用nib作为Interface Buil ...

  3. 在Windows Server 2012的Task Scheduler里面配置自动发送邮件

    最近在一台server上配置了每个周末备份数据库的定时任务,想顺手配置发送备份完成的邮件提醒我去Double Check一下备份结果. 悲剧地发现Send an email功能被新版的server给禁 ...

  4. 微软BI 之SSIS 系列 - 利用 SSIS 模板快速开发 SSIS Package

    开篇介绍 在做 ETL 项目的时候,往往很多 Package 的开发都是基于相同的模型和流程.比如在 Package 开始运行时需要向 Process Log 表中插入记录,在 Package 运行结 ...

  5. MS SQL SERVER索引优化相关查询

        查找缺失索引 -- =============================================   -- Description: 查询当前数据库中缺失的索引,知道你进行优化的 ...

  6. SQL Server 2008 Datetime Cast 成 Date 类型可以使用索引(转载)

    很久没写blog,不是懒,实在是最近我这的访问速度不好,用firefox经常上传不了图片 ....... 今天无意发现了SQL Server 2008 Datetime Cast 成 Date 类型可 ...

  7. Spring框架下的 “接口调用、MVC请求” 调用参数、返回值、耗时信息输出

    主要拦截前端或后天的请求,打印请求方法参数.返回值.耗时.异常的日志.方便开发调试,能很快定位到问题出现在哪个方法中. 前端请求拦截,mvc的拦截器 import java.util.Date; im ...

  8. 将复杂form表单序列化serialize-object.js

    <form class="form-horizontal" role="form" id="myform" action=" ...

  9. Scala 深入浅出实战经典 第52讲:Scala中路径依赖代码实战详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  10. HDU 3844 Mining Your Own Business

    首先,如果图本来就是一个点双联通的(即不存在割点),那么从这个图中选出任意两个点就OK了. 如果这个图存在割点,那么我们把割点拿掉后图就会变得支离破碎了.对于那种只和一个割点相连的块,这个块中至少要选 ...