Android实现Banner界面广告图片循环轮播(包括实现手动滑动循环)
前言:经常会看到有一些app的banner界面可以实现循环播放多个广告图片和手动滑动循环。本以为单纯的ViewPager就可以实现这些功能。但是蛋疼的事情来了,ViewPager并不支持循环翻页。所以要实现循环还得需要自己去动手。自己在网上也找了些例子,本博文的Demo是结合自己找到的一些相关例子的基础上去改造,也希望对读者有用。
Demo实现的效果图如下:
Demo代码:
工程目录如下图:
废话不多说,上代码。
1.主Activity代码如下:
- package com.stevenhu.android.phone.ui;
- import java.util.ArrayList;
- import java.util.List;
- import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
- import com.nostra13.universalimageloader.core.DisplayImageOptions;
- import com.nostra13.universalimageloader.core.ImageLoader;
- import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
- import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
- import com.stevenhu.android.phone.bean.ADInfo;
- import com.stevenhu.android.phone.utils.ViewFactory;
- import android.annotation.SuppressLint;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.ImageView;
- import android.widget.Toast;
- import cn.androiddevelop.cycleviewpager.lib.CycleViewPager;
- import cn.androiddevelop.cycleviewpager.lib.CycleViewPager.ImageCycleViewListener;
- /**
- * 描述:主页
- *
- * @author stevenhu
- * @version 2015年5月8日 上午10:47:37
- */
- public class MainActivity extends Activity {
- private List<ImageView> views = new ArrayList<ImageView>();
- private List<ADInfo> infos = new ArrayList<ADInfo>();
- private CycleViewPager cycleViewPager;
- private String[] imageUrls = {"http://img.taodiantong.cn/v55183/infoimg/2013-07/130720115322ky.jpg",
- "http://pic30.nipic.com/20130626/8174275_085522448172_2.jpg",
- "http://pic18.nipic.com/20111215/577405_080531548148_2.jpg",
- "http://pic15.nipic.com/20110722/2912365_092519919000_2.jpg",
- "http://pic.58pic.com/58pic/12/64/27/55U58PICrdX.jpg"};
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.ui_main);
- configImageLoader();
- initialize();
- }
- @SuppressLint("NewApi")
- private void initialize() {
- cycleViewPager = (CycleViewPager) getFragmentManager()
- .findFragmentById(R.id.fragment_cycle_viewpager_content);
- for(int i = 0; i < imageUrls.length; i ++){
- ADInfo info = new ADInfo();
- info.setUrl(imageUrls[i]);
- info.setContent("图片-->" + i );
- infos.add(info);
- }
- // 将最后一个ImageView添加进来
- views.add(ViewFactory.getImageView(this, infos.get(infos.size() - 1).getUrl()));
- for (int i = 0; i < infos.size(); i++) {
- views.add(ViewFactory.getImageView(this, infos.get(i).getUrl()));
- }
- // 将第一个ImageView添加进来
- views.add(ViewFactory.getImageView(this, infos.get(0).getUrl()));
- // 设置循环,在调用setData方法前调用
- cycleViewPager.setCycle(true);
- // 在加载数据前设置是否循环
- cycleViewPager.setData(views, infos, mAdCycleViewListener);
- //设置轮播
- cycleViewPager.setWheel(true);
- // 设置轮播时间,默认5000ms
- cycleViewPager.setTime(2000);
- //设置圆点指示图标组居中显示,默认靠右
- cycleViewPager.setIndicatorCenter();
- }
- private ImageCycleViewListener mAdCycleViewListener = new ImageCycleViewListener() {
- @Override
- public void onImageClick(ADInfo info, int position, View imageView) {
- if (cycleViewPager.isCycle()) {
- position = position - 1;
- Toast.makeText(MainActivity.this,
- "position-->" + info.getContent(), Toast.LENGTH_SHORT)
- .show();
- }
- }
- };
- /**
- * 配置ImageLoder
- */
- private void configImageLoader() {
- // 初始化ImageLoader
- @SuppressWarnings("deprecation")
- DisplayImageOptions options = new DisplayImageOptions.Builder().showStubImage(R.drawable.icon_stub) // 设置图片下载期间显示的图片
- .showImageForEmptyUri(R.drawable.icon_empty) // 设置图片Uri为空或是错误的时候显示的图片
- .showImageOnFail(R.drawable.icon_error) // 设置图片加载或解码过程中发生错误显示的图片
- .cacheInMemory(true) // 设置下载的图片是否缓存在内存中
- .cacheOnDisc(true) // 设置下载的图片是否缓存在SD卡中
- // .displayer(new RoundedBitmapDisplayer(20)) // 设置成圆角图片
- .build(); // 创建配置过得DisplayImageOption对象
- ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()).defaultDisplayImageOptions(options)
- .threadPriority(Thread.NORM_PRIORITY - 2).denyCacheImageMultipleSizesInMemory()
- .discCacheFileNameGenerator(new Md5FileNameGenerator()).tasksProcessingOrder(QueueProcessingType.LIFO).build();
- ImageLoader.getInstance().init(config);
- }
- }
2.主文件ui_main.xml代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
- <fragment
- android:id="@+id/fragment_cycle_viewpager_content"
- android:name="cn.androiddevelop.cycleviewpager.lib.CycleViewPager"
- android:layout_width="match_parent"
- android:layout_height="180dip" />
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:text="content"/>
- </RelativeLayout>
- </LinearLayout>
3.CycleViewPager类代码如下:
- package cn.androiddevelop.cycleviewpager.lib;
- import java.util.ArrayList;
- import java.util.List;
- import android.annotation.SuppressLint;
- import android.app.Fragment;
- import android.os.Bundle;
- import android.os.Message;
- import android.support.v4.view.PagerAdapter;
- import android.support.v4.view.ViewPager.OnPageChangeListener;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.ViewGroup;
- import android.widget.FrameLayout;
- import android.widget.ImageView;
- import android.widget.LinearLayout;
- import android.widget.RelativeLayout;
- import com.stevenhu.android.phone.bean.ADInfo;
- import com.stevenhu.android.phone.ui.R;
- /**
- * 实现可循环,可轮播的viewpager
- */
- @SuppressLint("NewApi")
- public class CycleViewPager extends Fragment implements OnPageChangeListener {
- private List<ImageView> imageViews = new ArrayList<ImageView>();
- private ImageView[] indicators;
- private FrameLayout viewPagerFragmentLayout;
- private LinearLayout indicatorLayout; // 指示器
- private BaseViewPager viewPager;
- private BaseViewPager parentViewPager;
- private ViewPagerAdapter adapter;
- private CycleViewPagerHandler handler;
- private int time = 5000; // 默认轮播时间
- private int currentPosition = 0; // 轮播当前位置
- private boolean isScrolling = false; // 滚动框是否滚动着
- private boolean isCycle = false; // 是否循环
- private boolean isWheel = false; // 是否轮播
- private long releaseTime = 0; // 手指松开、页面不滚动时间,防止手机松开后短时间进行切换
- private int WHEEL = 100; // 转动
- private int WHEEL_WAIT = 101; // 等待
- private ImageCycleViewListener mImageCycleViewListener;
- private List<ADInfo> infos;
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View view = LayoutInflater.from(getActivity()).inflate(
- R.layout.view_cycle_viewpager_contet, null);
- viewPager = (BaseViewPager) view.findViewById(R.id.viewPager);
- indicatorLayout = (LinearLayout) view
- .findViewById(R.id.layout_viewpager_indicator);
- viewPagerFragmentLayout = (FrameLayout) view
- .findViewById(R.id.layout_viewager_content);
- handler = new CycleViewPagerHandler(getActivity()) {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- if (msg.what == WHEEL && imageViews.size() != 0) {
- if (!isScrolling) {
- int max = imageViews.size() + 1;
- int position = (currentPosition + 1) % imageViews.size();
- viewPager.setCurrentItem(position, true);
- if (position == max) { // 最后一页时回到第一页
- viewPager.setCurrentItem(1, false);
- }
- }
- releaseTime = System.currentTimeMillis();
- handler.removeCallbacks(runnable);
- handler.postDelayed(runnable, time);
- return;
- }
- if (msg.what == WHEEL_WAIT && imageViews.size() != 0) {
- handler.removeCallbacks(runnable);
- handler.postDelayed(runnable, time);
- }
- }
- };
- return view;
- }
- public void setData(List<ImageView> views, List<ADInfo> list, ImageCycleViewListener listener) {
- setData(views, list, listener, 0);
- }
- /**
- * 初始化viewpager
- *
- * @param views
- * 要显示的views
- * @param showPosition
- * 默认显示位置
- */
- public void setData(List<ImageView> views, List<ADInfo> list, ImageCycleViewListener listener, int showPosition) {
- mImageCycleViewListener = listener;
- infos = list;
- this.imageViews.clear();
- if (views.size() == 0) {
- viewPagerFragmentLayout.setVisibility(View.GONE);
- return;
- }
- for (ImageView item : views) {
- this.imageViews.add(item);
- }
- int ivSize = views.size();
- // 设置指示器
- indicators = new ImageView[ivSize];
- if (isCycle)
- indicators = new ImageView[ivSize - 2];
- indicatorLayout.removeAllViews();
- for (int i = 0; i < indicators.length; i++) {
- View view = LayoutInflater.from(getActivity()).inflate(
- R.layout.view_cycle_viewpager_indicator, null);
- indicators[i] = (ImageView) view.findViewById(R.id.image_indicator);
- indicatorLayout.addView(view);
- }
- adapter = new ViewPagerAdapter();
- // 默认指向第一项,下方viewPager.setCurrentItem将触发重新计算指示器指向
- setIndicator(0);
- viewPager.setOffscreenPageLimit(3);
- viewPager.setOnPageChangeListener(this);
- viewPager.setAdapter(adapter);
- if (showPosition < 0 || showPosition >= views.size())
- showPosition = 0;
- if (isCycle) {
- showPosition = showPosition + 1;
- }
- viewPager.setCurrentItem(showPosition);
- }
- /**
- * 设置指示器居中,默认指示器在右方
- */
- public void setIndicatorCenter() {
- RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
- RelativeLayout.LayoutParams.WRAP_CONTENT,
- RelativeLayout.LayoutParams.WRAP_CONTENT);
- params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
- params.addRule(RelativeLayout.CENTER_HORIZONTAL);
- indicatorLayout.setLayoutParams(params);
- }
- /**
- * 是否循环,默认不开启,开启前,请将views的最前面与最后面各加入一个视图,用于循环
- *
- * @param isCycle
- * 是否循环
- */
- public void setCycle(boolean isCycle) {
- this.isCycle = isCycle;
- }
- /**
- * 是否处于循环状态
- *
- * @return
- */
- public boolean isCycle() {
- return isCycle;
- }
- /**
- * 设置是否轮播,默认不轮播,轮播一定是循环的
- *
- * @param isWheel
- */
- public void setWheel(boolean isWheel) {
- this.isWheel = isWheel;
- isCycle = true;
- if (isWheel) {
- handler.postDelayed(runnable, time);
- }
- }
- /**
- * 是否处于轮播状态
- *
- * @return
- */
- public boolean isWheel() {
- return isWheel;
- }
- final Runnable runnable = new Runnable() {
- @Override
- public void run() {
- if (getActivity() != null && !getActivity().isFinishing()
- && isWheel) {
- long now = System.currentTimeMillis();
- // 检测上一次滑动时间与本次之间是否有触击(手滑动)操作,有的话等待下次轮播
- if (now - releaseTime > time - 500) {
- handler.sendEmptyMessage(WHEEL);
- } else {
- handler.sendEmptyMessage(WHEEL_WAIT);
- }
- }
- }
- };
- /**
- * 释放指示器高度,可能由于之前指示器被限制了高度,此处释放
- */
- public void releaseHeight() {
- getView().getLayoutParams().height = RelativeLayout.LayoutParams.MATCH_PARENT;
- refreshData();
- }
- /**
- * 设置轮播暂停时间,即没多少秒切换到下一张视图.默认5000ms
- *
- * @param time
- * 毫秒为单位
- */
- public void setTime(int time) {
- this.time = time;
- }
- /**
- * 刷新数据,当外部视图更新后,通知刷新数据
- */
- public void refreshData() {
- if (adapter != null)
- adapter.notifyDataSetChanged();
- }
- /**
- * 隐藏CycleViewPager
- */
- public void hide() {
- viewPagerFragmentLayout.setVisibility(View.GONE);
- }
- /**
- * 返回内置的viewpager
- *
- * @return viewPager
- */
- public BaseViewPager getViewPager() {
- return viewPager;
- }
- /**
- * 页面适配器 返回对应的view
- *
- * @author Yuedong Li
- *
- */
- private class ViewPagerAdapter extends PagerAdapter {
- @Override
- public int getCount() {
- return imageViews.size();
- }
- @Override
- public boolean isViewFromObject(View arg0, Object arg1) {
- return arg0 == arg1;
- }
- @Override
- public void destroyItem(ViewGroup container, int position, Object object) {
- container.removeView((View) object);
- }
- @Override
- public View instantiateItem(ViewGroup container, final int position) {
- ImageView v = imageViews.get(position);
- if (mImageCycleViewListener != null) {
- v.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mImageCycleViewListener.onImageClick(infos.get(currentPosition - 1), currentPosition, v);
- }
- });
- }
- container.addView(v);
- return v;
- }
- @Override
- public int getItemPosition(Object object) {
- return POSITION_NONE;
- }
- }
- @Override
- public void onPageScrollStateChanged(int arg0) {
- if (arg0 == 1) { // viewPager在滚动
- isScrolling = true;
- return;
- } else if (arg0 == 0) { // viewPager滚动结束
- if (parentViewPager != null)
- parentViewPager.setScrollable(true);
- releaseTime = System.currentTimeMillis();
- viewPager.setCurrentItem(currentPosition, false);
- }
- isScrolling = false;
- }
- @Override
- public void onPageScrolled(int arg0, float arg1, int arg2) {
- }
- @Override
- public void onPageSelected(int arg0) {
- int max = imageViews.size() - 1;
- int position = arg0;
- currentPosition = arg0;
- if (isCycle) {
- if (arg0 == 0) {
- currentPosition = max - 1;
- } else if (arg0 == max) {
- currentPosition = 1;
- }
- position = currentPosition - 1;
- }
- setIndicator(position);
- }
- /**
- * 设置viewpager是否可以滚动
- *
- * @param enable
- */
- public void setScrollable(boolean enable) {
- viewPager.setScrollable(enable);
- }
- /**
- * 返回当前位置,循环时需要注意返回的position包含之前在views最前方与最后方加入的视图,即当前页面试图在views集合的位置
- *
- * @return
- */
- public int getCurrentPostion() {
- return currentPosition;
- }
- /**
- * 设置指示器
- *
- * @param selectedPosition
- * 默认指示器位置
- */
- private void setIndicator(int selectedPosition) {
- for (int i = 0; i < indicators.length; i++) {
- indicators[i]
- .setBackgroundResource(R.drawable.icon_point);
- }
- if (indicators.length > selectedPosition)
- indicators[selectedPosition]
- .setBackgroundResource(R.drawable.icon_point_pre);
- }
- /**
- * 如果当前页面嵌套在另一个viewPager中,为了在进行滚动时阻断父ViewPager滚动,可以 阻止父ViewPager滑动事件
- * 父ViewPager需要实现ParentViewPager中的setScrollable方法
- */
- public void disableParentViewPagerTouchEvent(BaseViewPager parentViewPager) {
- if (parentViewPager != null)
- parentViewPager.setScrollable(false);
- }
- /**
- * 轮播控件的监听事件
- *
- * @author minking
- */
- public static interface ImageCycleViewListener {
- /**
- * 单击图片事件
- *
- * @param position
- * @param imageView
- */
- public void onImageClick(ADInfo info, int postion, View imageView);
- }
- }
CycleViewPager类为实现可循环,可轮播的ViewPager的核心类,继承自Fragment,具体实现原理就不多说了,代码中都有相关的注释。
ok,接下来的其他类就不多说了。自己下载Demo学习吧。
本博文Demo下载链接地址如下:
http://download.csdn.net/detail/stevenhu_223/8675717
另外,还有一种通过自定义ViewPager实现和本博文相同效果的广告界面Demo,这里就不再贴代码,可以通过如下地址下载: