• Android实现Banner界面广告图片循环轮播(包括实现手动滑动循环)


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

      Demo实现的效果图如下:

      

       

       Demo代码:

         工程目录如下图:

      

          废话不多说,上代码。

        1.主Activity代码如下:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    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代码如下:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
    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类代码如下:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    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

  • 相关阅读:
    Spring:dispatchservlet
    信息系统设计
    数据流图的绘制方法
    信息系统管理工程师学习笔记
    JS语法学习笔记
    jQuery
    用Excel生成Sql
    JAVA-Reflect
    Java创建对象的过程
    有关死锁那点事儿
  • 原文地址:https://www.cnblogs.com/likeju/p/4780180.html
Copyright © 2020-2023  润新知