zoukankan      html  css  js  c++  java
  • Android实现Banner界面广告图片循环轮播(包括实现手动滑动循环)

    前言:经常会看到有一些app的banner界面可以实现循环播放多个广告图片和手动滑动循环。本以为单纯的ViewPager就可以实现这些功能。但是蛋疼的事情来了,ViewPager并不支持循环翻页。所以要实现循环还得需要自己去动手。自己在网上也找了些例子,本博文的Demo是结合自己找到的一些相关例子的基础上去改造,也希望对读者有用。

      Demo实现的效果图如下:

     

    Demo代码:

     1.主Activity代码如下:

      1 package com.stevenhu.android.phone.ui;
      2 
      3 import java.util.ArrayList;
      4 import java.util.List;
      5 
      6 import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
      7 import com.nostra13.universalimageloader.core.DisplayImageOptions;
      8 import com.nostra13.universalimageloader.core.ImageLoader;
      9 import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
     10 import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
     11 import com.stevenhu.android.phone.bean.ADInfo;
     12 import com.stevenhu.android.phone.utils.ViewFactory;
     13 
     14 import android.annotation.SuppressLint;
     15 import android.app.Activity;
     16 import android.os.Bundle;
     17 import android.view.View;
     18 import android.widget.ImageView;
     19 import android.widget.Toast;
     20 import cn.androiddevelop.cycleviewpager.lib.CycleViewPager;
     21 import cn.androiddevelop.cycleviewpager.lib.CycleViewPager.ImageCycleViewListener;
     22 /**
     23  * 描述:主页
     24  *
     25  * @author stevenhu
     26  * @version 2015年5月8日 上午10:47:37
     27  */
     28 public class MainActivity extends Activity {
     29 
     30     private List<ImageView> views = new ArrayList<ImageView>();
     31     private List<ADInfo> infos = new ArrayList<ADInfo>();
     32     private CycleViewPager cycleViewPager;
     33     
     34     private String[] imageUrls = {"http://img.taodiantong.cn/v55183/infoimg/2013-07/130720115322ky.jpg",
     35             "http://pic30.nipic.com/20130626/8174275_085522448172_2.jpg",
     36             "http://pic18.nipic.com/20111215/577405_080531548148_2.jpg",
     37             "http://pic15.nipic.com/20110722/2912365_092519919000_2.jpg",
     38             "http://pic.58pic.com/58pic/12/64/27/55U58PICrdX.jpg"};
     39     
     40     @Override
     41     protected void onCreate(Bundle savedInstanceState) {
     42         super.onCreate(savedInstanceState);
     43         setContentView(R.layout.ui_main);
     44         configImageLoader();
     45         initialize();
     46     }
     47     
     48     @SuppressLint("NewApi")
     49     private void initialize() {
     50         
     51         cycleViewPager = (CycleViewPager) getFragmentManager()
     52                 .findFragmentById(R.id.fragment_cycle_viewpager_content);
     53         
     54         for(int i = 0; i < imageUrls.length; i ++){
     55             ADInfo info = new ADInfo();
     56             info.setUrl(imageUrls[i]);
     57             info.setContent("图片-->" + i );
     58             infos.add(info);
     59         }
     60         
     61         // 将最后一个ImageView添加进来
     62         views.add(ViewFactory.getImageView(this, infos.get(infos.size() - 1).getUrl()));
     63         for (int i = 0; i < infos.size(); i++) {
     64             views.add(ViewFactory.getImageView(this, infos.get(i).getUrl()));
     65         }
     66         // 将第一个ImageView添加进来
     67         views.add(ViewFactory.getImageView(this, infos.get(0).getUrl()));
     68         
     69         // 设置循环,在调用setData方法前调用
     70         cycleViewPager.setCycle(true);
     71 
     72         // 在加载数据前设置是否循环
     73         cycleViewPager.setData(views, infos, mAdCycleViewListener);
     74         //设置轮播
     75         cycleViewPager.setWheel(true);
     76 
     77         // 设置轮播时间,默认5000ms
     78         cycleViewPager.setTime(2000);
     79         //设置圆点指示图标组居中显示,默认靠右
     80         cycleViewPager.setIndicatorCenter();
     81     }
     82     
     83     private ImageCycleViewListener mAdCycleViewListener = new ImageCycleViewListener() {
     84 
     85         @Override
     86         public void onImageClick(ADInfo info, int position, View imageView) {
     87             if (cycleViewPager.isCycle()) {
     88                 position = position - 1;
     89                 Toast.makeText(MainActivity.this,
     90                         "position-->" + info.getContent(), Toast.LENGTH_SHORT)
     91                         .show();
     92             }
     93             
     94         }
     95 
     96     };
     97     
     98     /**
     99      * 配置ImageLoder
    100      */
    101     private void configImageLoader() {
    102         // 初始化ImageLoader
    103         @SuppressWarnings("deprecation")
    104         DisplayImageOptions options = new DisplayImageOptions.Builder().showStubImage(R.drawable.icon_stub) // 设置图片下载期间显示的图片
    105                 .showImageForEmptyUri(R.drawable.icon_empty) // 设置图片Uri为空或是错误的时候显示的图片
    106                 .showImageOnFail(R.drawable.icon_error) // 设置图片加载或解码过程中发生错误显示的图片
    107                 .cacheInMemory(true) // 设置下载的图片是否缓存在内存中
    108                 .cacheOnDisc(true) // 设置下载的图片是否缓存在SD卡中
    109                 // .displayer(new RoundedBitmapDisplayer(20)) // 设置成圆角图片
    110                 .build(); // 创建配置过得DisplayImageOption对象
    111 
    112         ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()).defaultDisplayImageOptions(options)
    113                 .threadPriority(Thread.NORM_PRIORITY - 2).denyCacheImageMultipleSizesInMemory()
    114                 .discCacheFileNameGenerator(new Md5FileNameGenerator()).tasksProcessingOrder(QueueProcessingType.LIFO).build();
    115         ImageLoader.getInstance().init(config);        
    116     }
    117 }

     2.主文件ui_main.xml代码如下:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:orientation="vertical" >
     6     
     7 
     8     <fragment
     9         android:id="@+id/fragment_cycle_viewpager_content"
    10         android:name="cn.androiddevelop.cycleviewpager.lib.CycleViewPager"
    11         android:layout_width="match_parent"
    12         android:layout_height="180dip" />
    13      
    14      
    15     <RelativeLayout 
    16         android:layout_width="fill_parent"
    17         android:layout_height="0dip"
    18         android:layout_weight="1">
    19         
    20         <TextView 
    21             android:layout_width="wrap_content"
    22             android:layout_height="wrap_content"
    23             android:layout_centerInParent="true"
    24             android:text="content"/>
    25     </RelativeLayout>
    26     
    27 </LinearLayout>

    3.CycleViewPager类代码如下:

      1 package cn.androiddevelop.cycleviewpager.lib;
      2 
      3 import java.util.ArrayList;
      4 import java.util.List;
      5 
      6 import android.annotation.SuppressLint;
      7 import android.app.Fragment;
      8 import android.os.Bundle;
      9 import android.os.Message;
     10 import android.support.v4.view.PagerAdapter;
     11 import android.support.v4.view.ViewPager.OnPageChangeListener;
     12 import android.view.LayoutInflater;
     13 import android.view.View;
     14 import android.view.View.OnClickListener;
     15 import android.view.ViewGroup;
     16 import android.widget.FrameLayout;
     17 import android.widget.ImageView;
     18 import android.widget.LinearLayout;
     19 import android.widget.RelativeLayout;
     20 
     21 import com.stevenhu.android.phone.bean.ADInfo;
     22 import com.stevenhu.android.phone.ui.R;
     23 
     24 /**
     25  * 实现可循环,可轮播的viewpager
     26  */
     27 @SuppressLint("NewApi")
     28 public class CycleViewPager extends Fragment implements OnPageChangeListener {
     29     
     30     private List<ImageView> imageViews = new ArrayList<ImageView>();
     31     private ImageView[] indicators;
     32     private FrameLayout viewPagerFragmentLayout;
     33     private LinearLayout indicatorLayout; // 指示器
     34     private BaseViewPager viewPager;
     35     private BaseViewPager parentViewPager;
     36     private ViewPagerAdapter adapter;
     37     private CycleViewPagerHandler handler;
     38     private int time = 5000; // 默认轮播时间
     39     private int currentPosition = 0; // 轮播当前位置
     40     private boolean isScrolling = false; // 滚动框是否滚动着
     41     private boolean isCycle = false; // 是否循环
     42     private boolean isWheel = false; // 是否轮播
     43     private long releaseTime = 0; // 手指松开、页面不滚动时间,防止手机松开后短时间进行切换
     44     private int WHEEL = 100; // 转动
     45     private int WHEEL_WAIT = 101; // 等待
     46     private ImageCycleViewListener mImageCycleViewListener;
     47     private List<ADInfo> infos;
     48 
     49     @Override
     50     public View onCreateView(LayoutInflater inflater, ViewGroup container,
     51             Bundle savedInstanceState) {
     52         View view = LayoutInflater.from(getActivity()).inflate(
     53                 R.layout.view_cycle_viewpager_contet, null);
     54 
     55         viewPager = (BaseViewPager) view.findViewById(R.id.viewPager);
     56         indicatorLayout = (LinearLayout) view
     57                 .findViewById(R.id.layout_viewpager_indicator);
     58 
     59         viewPagerFragmentLayout = (FrameLayout) view
     60                 .findViewById(R.id.layout_viewager_content);
     61 
     62         handler = new CycleViewPagerHandler(getActivity()) {
     63 
     64             @Override
     65             public void handleMessage(Message msg) {
     66                 super.handleMessage(msg);
     67                 if (msg.what == WHEEL && imageViews.size() != 0) {
     68                     if (!isScrolling) {
     69                         int max = imageViews.size() + 1;
     70                         int position = (currentPosition + 1) % imageViews.size();
     71                         viewPager.setCurrentItem(position, true);
     72                         if (position == max) { // 最后一页时回到第一页
     73                             viewPager.setCurrentItem(1, false);
     74                         }
     75                     }
     76 
     77                     releaseTime = System.currentTimeMillis();
     78                     handler.removeCallbacks(runnable);
     79                     handler.postDelayed(runnable, time);
     80                     return;
     81                 }
     82                 if (msg.what == WHEEL_WAIT && imageViews.size() != 0) {
     83                     handler.removeCallbacks(runnable);
     84                     handler.postDelayed(runnable, time);
     85                 }
     86             }
     87         };
     88 
     89         return view;
     90     }
     91 
     92     public void setData(List<ImageView> views, List<ADInfo> list, ImageCycleViewListener listener) {
     93         setData(views, list, listener, 0);
     94     }
     95 
     96     /**
     97      * 初始化viewpager
     98      * 
     99      * @param views
    100      *            要显示的views
    101      * @param showPosition
    102      *            默认显示位置
    103      */
    104     public void setData(List<ImageView> views, List<ADInfo> list, ImageCycleViewListener listener, int showPosition) {
    105         mImageCycleViewListener = listener;
    106         infos = list;
    107         this.imageViews.clear();
    108 
    109         if (views.size() == 0) {
    110             viewPagerFragmentLayout.setVisibility(View.GONE);
    111             return;
    112         }
    113 
    114         for (ImageView item : views) {
    115             this.imageViews.add(item);
    116         }
    117 
    118         int ivSize = views.size();
    119 
    120         // 设置指示器
    121         indicators = new ImageView[ivSize];
    122         if (isCycle)
    123             indicators = new ImageView[ivSize - 2];
    124         indicatorLayout.removeAllViews();
    125         for (int i = 0; i < indicators.length; i++) {
    126             View view = LayoutInflater.from(getActivity()).inflate(
    127                     R.layout.view_cycle_viewpager_indicator, null);
    128             indicators[i] = (ImageView) view.findViewById(R.id.image_indicator);
    129             indicatorLayout.addView(view);
    130         }
    131 
    132         adapter = new ViewPagerAdapter();
    133 
    134         // 默认指向第一项,下方viewPager.setCurrentItem将触发重新计算指示器指向
    135         setIndicator(0);
    136 
    137         viewPager.setOffscreenPageLimit(3);
    138         viewPager.setOnPageChangeListener(this);
    139         viewPager.setAdapter(adapter);
    140         if (showPosition < 0 || showPosition >= views.size())
    141             showPosition = 0;
    142         if (isCycle) {
    143             showPosition = showPosition + 1;
    144         }
    145         viewPager.setCurrentItem(showPosition);
    146 
    147     }
    148 
    149     /**
    150      * 设置指示器居中,默认指示器在右方
    151      */
    152     public void setIndicatorCenter() {
    153         RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
    154                 RelativeLayout.LayoutParams.WRAP_CONTENT,
    155                 RelativeLayout.LayoutParams.WRAP_CONTENT);
    156         params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
    157         params.addRule(RelativeLayout.CENTER_HORIZONTAL);
    158         indicatorLayout.setLayoutParams(params);
    159     }
    160 
    161     /**
    162      * 是否循环,默认不开启,开启前,请将views的最前面与最后面各加入一个视图,用于循环
    163      * 
    164      * @param isCycle
    165      *            是否循环
    166      */
    167     public void setCycle(boolean isCycle) {
    168         this.isCycle = isCycle;
    169     }
    170 
    171     /**
    172      * 是否处于循环状态
    173      * 
    174      * @return
    175      */
    176     public boolean isCycle() {
    177         return isCycle;
    178     }
    179 
    180     /**
    181      * 设置是否轮播,默认不轮播,轮播一定是循环的
    182      * 
    183      * @param isWheel
    184      */
    185     public void setWheel(boolean isWheel) {
    186         this.isWheel = isWheel;
    187         isCycle = true;
    188         if (isWheel) {
    189             handler.postDelayed(runnable, time);
    190         }
    191     }
    192 
    193     /**
    194      * 是否处于轮播状态
    195      * 
    196      * @return
    197      */
    198     public boolean isWheel() {
    199         return isWheel;
    200     }
    201 
    202     final Runnable runnable = new Runnable() {
    203 
    204         @Override
    205         public void run() {
    206             if (getActivity() != null && !getActivity().isFinishing()
    207                     && isWheel) {
    208                 long now = System.currentTimeMillis();
    209                 // 检测上一次滑动时间与本次之间是否有触击(手滑动)操作,有的话等待下次轮播
    210                 if (now - releaseTime > time - 500) {
    211                     handler.sendEmptyMessage(WHEEL);
    212                 } else {
    213                     handler.sendEmptyMessage(WHEEL_WAIT);
    214                 }
    215             }
    216         }
    217     };
    218 
    219     /**
    220      * 释放指示器高度,可能由于之前指示器被限制了高度,此处释放
    221      */
    222     public void releaseHeight() {
    223         getView().getLayoutParams().height = RelativeLayout.LayoutParams.MATCH_PARENT;
    224         refreshData();
    225     }
    226 
    227     /**
    228      * 设置轮播暂停时间,即没多少秒切换到下一张视图.默认5000ms
    229      * 
    230      * @param time
    231      *            毫秒为单位
    232      */
    233     public void setTime(int time) {
    234         this.time = time;
    235     }
    236 
    237     /**
    238      * 刷新数据,当外部视图更新后,通知刷新数据
    239      */
    240     public void refreshData() {
    241         if (adapter != null)
    242             adapter.notifyDataSetChanged();
    243     }
    244 
    245     /**
    246      * 隐藏CycleViewPager
    247      */
    248     public void hide() {
    249         viewPagerFragmentLayout.setVisibility(View.GONE);
    250     }
    251 
    252     /**
    253      * 返回内置的viewpager
    254      * 
    255      * @return viewPager
    256      */
    257     public BaseViewPager getViewPager() {
    258         return viewPager;
    259     }
    260 
    261     /**
    262      * 页面适配器 返回对应的view
    263      * 
    264      * @author Yuedong Li
    265      * 
    266      */
    267     private class ViewPagerAdapter extends PagerAdapter {
    268 
    269         @Override
    270         public int getCount() {
    271             return imageViews.size();
    272         }
    273 
    274         @Override
    275         public boolean isViewFromObject(View arg0, Object arg1) {
    276             return arg0 == arg1;
    277         }
    278 
    279         @Override
    280         public void destroyItem(ViewGroup container, int position, Object object) {
    281             container.removeView((View) object);
    282         }
    283 
    284         @Override
    285         public View instantiateItem(ViewGroup container, final int position) {
    286             ImageView v = imageViews.get(position);
    287             if (mImageCycleViewListener != null) {
    288                 v.setOnClickListener(new OnClickListener() {
    289                     
    290                     @Override
    291                     public void onClick(View v) {
    292                         mImageCycleViewListener.onImageClick(infos.get(currentPosition - 1), currentPosition, v);
    293                     }
    294                 });
    295             }
    296             container.addView(v);
    297             return v;
    298         }
    299 
    300         @Override
    301         public int getItemPosition(Object object) {
    302             return POSITION_NONE;
    303         }
    304     }
    305 
    306     @Override
    307     public void onPageScrollStateChanged(int arg0) {
    308         if (arg0 == 1) { // viewPager在滚动
    309             isScrolling = true;
    310             return;
    311         } else if (arg0 == 0) { // viewPager滚动结束
    312             if (parentViewPager != null)
    313                 parentViewPager.setScrollable(true);
    314 
    315             releaseTime = System.currentTimeMillis();
    316 
    317             viewPager.setCurrentItem(currentPosition, false);
    318             
    319         }
    320         isScrolling = false;
    321     }
    322 
    323     @Override
    324     public void onPageScrolled(int arg0, float arg1, int arg2) {
    325     }
    326 
    327     @Override
    328     public void onPageSelected(int arg0) {
    329         int max = imageViews.size() - 1;
    330         int position = arg0;
    331         currentPosition = arg0;
    332         if (isCycle) {
    333             if (arg0 == 0) {
    334                 currentPosition = max - 1;
    335             } else if (arg0 == max) {
    336                 currentPosition = 1;
    337             }
    338             position = currentPosition - 1;
    339         }
    340         setIndicator(position);
    341     }
    342 
    343     /**
    344      * 设置viewpager是否可以滚动
    345      * 
    346      * @param enable
    347      */
    348     public void setScrollable(boolean enable) {
    349         viewPager.setScrollable(enable);
    350     }
    351 
    352     /**
    353      * 返回当前位置,循环时需要注意返回的position包含之前在views最前方与最后方加入的视图,即当前页面试图在views集合的位置
    354      * 
    355      * @return
    356      */
    357     public int getCurrentPostion() {
    358         return currentPosition;
    359     }
    360 
    361     /**
    362      * 设置指示器
    363      * 
    364      * @param selectedPosition
    365      *            默认指示器位置
    366      */
    367     private void setIndicator(int selectedPosition) {
    368         for (int i = 0; i < indicators.length; i++) {
    369             indicators[i]
    370                     .setBackgroundResource(R.drawable.icon_point);
    371         }
    372         if (indicators.length > selectedPosition)
    373             indicators[selectedPosition]
    374                     .setBackgroundResource(R.drawable.icon_point_pre);
    375     }
    376 
    377     /**
    378      * 如果当前页面嵌套在另一个viewPager中,为了在进行滚动时阻断父ViewPager滚动,可以 阻止父ViewPager滑动事件
    379      * 父ViewPager需要实现ParentViewPager中的setScrollable方法
    380      */
    381     public void disableParentViewPagerTouchEvent(BaseViewPager parentViewPager) {
    382         if (parentViewPager != null)
    383             parentViewPager.setScrollable(false);
    384     }
    385 
    386     
    387     /**
    388      * 轮播控件的监听事件
    389      * 
    390      * @author minking
    391      */
    392     public static interface ImageCycleViewListener {
    393 
    394         /**
    395          * 单击图片事件
    396          * 
    397          * @param position
    398          * @param imageView
    399          */
    400         public void onImageClick(ADInfo info, int postion, View imageView);
    401     }
    402 }

    CycleViewPager类为实现可循环,可轮播的ViewPager的核心类,继承自Fragment,具体实现原理就不多说了,代码中都有相关的注释。

      ok,接下来的其他类就不多说了。自己下载Demo学习吧。

       本博文Demo下载链接地址如下:

       http://download.csdn.net/detail/stevenhu_223/8675717

       另外,还有一种通过自定义ViewPager实现和本博文相同效果的广告界面Demo,这里就不再贴代码,可以通过如下地址下载:

       http://download.csdn.net/detail/stevenhu_223/8697903

  • 相关阅读:
    Log4j appender、layout
    EhCache缓存框架的使用
    Log4j rootLogger根配置以及4种日志级别
    开发chrome 插件, background.js中 console log 看不到解决方法
    Windows cmd 长时间不输出新内容 直到按下ctrl + c 取消或者回车的解决办法
    如何查看当前分支从哪个支线创建而来
    C# 获取相对路径的字符串
    解决adobe air sdk打包 apk后自动在包名前面加上air. (有个点)前缀的问题
    sublime text 输入法候选词不跟随光标
    Windows 批处理设置dns ,解决能上qq不能开网页
  • 原文地址:https://www.cnblogs.com/huolongluo/p/5509408.html
Copyright © 2011-2022 走看看