Android实现带指示点的自动轮播无限循环效果

想要实现无限轮播,一直向左滑动,当到最后一个view时,会滑动到第一个,无限…

可以自己写ViewPager然后加handler先实现自动滚动,当然这里我为了项目的进度直接使用了Trinea的Android-auto-scroll-view-pager库,网址:点击进入github 引用库compile('cn.trinea.android.view.autoscrollviewpager:android-auto-scroll-view-pager:1.1.2') {
exclude module: 'support-v4'
之后

1布局为

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/y150">
<cn.trinea.android.view.autoscrollviewpager.AutoScrollViewPager
android:id="@+id/viewpager1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!--点点的布局-->
<LinearLayout
android:id="@+id/ll_dot1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="8dp"
android:gravity="center"
android:orientation="horizontal" />
</RelativeLayout>

2 构建PagerAdapter
继承自RecyclingPagerAdapter (后面会贴出来源码)

 `public class Indicator1Adapter extends RecyclingPagerAdapter {
 private List<Integer> imageIdList;
 Context context;
 //是否循环(创造构造方法,在activity里设置是否)
 //集合大小
 private int size;

 public Indicator1Adapter(List<Integer> mData, Context context) {
  this.imageIdList = mData;
  this.context = context;
  this.size = mData.size();
  isInfiniteLoop = false;
 }
 @Override
 public int getCount() {
 //是:最大(让集合的长度无限,从而模拟无限循环) 否,集合长度
  return isInfiniteLoop ? Integer.MAX_VALUE : imageIdList.size();
 }

 /**
  * @return the isInfiniteLoop
  */
 public boolean isInfiniteLoop() {
  return isInfiniteLoop;
 }

 /**
  * @param是否无限循环
  */
 public Indicator1Adapter setInfiniteLoop(boolean isInfiniteLoop) {
  this.isInfiniteLoop = isInfiniteLoop;
  return this;
 }

 /**
  * 真实的position
  *
  * @param position
  * @return
  */
 private int getPosition(int position) {
  return isInfiniteLoop ? position % size : position;
 }
 @Override
 public View getView(int position, View view, ViewGroup container) {
  ViewHolder holder;
  if (view == null) {
   holder = new ViewHolder();
   view = holder.imageView = new ImageView(context);
   view.setTag(holder);
  } else {
   holder = (ViewHolder)view.getTag();
  }
  holder.imageView.setImageResource(imageIdList.get(getPosition(position)));
  holder.imageView.setScaleType(ImageView.ScaleType.FIT_XY);
  return view;
 }

 private static class ViewHolder {

  ImageView imageView;
 }
}

3 在activity里或者fragment里就可以设置ViewPager

定义的成员变量:

//viewpager1
 @BindView(R.id.viewpager1)
 AutoScrollViewPager mPager1;
 //承载小点点的控件容器(布局里有)
 @BindView(R.id.ll_dot1)
 LinearLayout mLlDot1;
Indicator1Adapter adapter1 = new Indicator1Adapter( mData,act).setInfiniteLoop(true);//开启无限循环
  mPager1.setAdapter(adapter1);
  mPager1.setInterval(PLAY_TIME);//轮播时间间隔
  mPager1.startAutoScroll();//开启自动轮播
  mPager1.setCurrentItem(Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % mData.size());

然后你嫌弃官方的换图间隔时间太短,一闪而过,可以通过反射 设置

//通过反射让滚动速度为自己的喜好的(这里设为1.2s)
  try {
   Field field = ViewPager.class.getDeclaredField("mScroller");
   field.setAccessible(true);
   FixedSpeedScroller scroller = new FixedSpeedScroller(mPager1.getContext(),
     new AccelerateInterpolator());
   field.set(mPager1, scroller);
   scroller.setmDuration(1200);
  } catch (Exception e) {
   Log.e(TAG, "Exception", e);
  }

4 然后我们的小点点还没有使用呢
这里我写了方法:

/**
 * 设置状态点1
 */
 private void setOvalLayout1() {
  for (int i = 0; i < mData.size(); i++) {
  /**
   * 生成对应数量的点点(布局,结果提供)
   */
   mLlDot1.addView(inflater.inflate(R.layout.dot, null));
  }
  // 默认显示第一页
  mLlDot1.getChildAt(0).findViewById(R.id.v_dot)
    .setBackgroundResource(R.drawable.dot_selected);
  mPager1.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
   public void onPageSelected(int position) {
    //遍历图片数组
//    Toast.makeText(act, "position"+position, Toast.LENGTH_SHORT).show();
    for (int i = 0; i < mData.size(); i++) {
     if(i==position%mData.size()){
      // 圆点选中
      /**
      * 这里需要注意如果直接写position,由于我们是无限循环,他的position是无限往上
      *增加的,那么就会报空指针,因为我们总共才生成了mData.size()个点点,这里可以让当前的
      *position取余,得到的即是当前位置的点点
      */
      mLlDot1.getChildAt(position%mData.size())
        .findViewById(R.id.v_dot)
        .setBackgroundResource(R.drawable.dot_selected);
     }else{
      // 取消圆点选中
      mLlDot1.getChildAt(curIndex1%mData.size())
        .findViewById(R.id.v_dot)
        .setBackgroundResource(R.drawable.dot_normal);
     }
    }
    curIndex1 = position;
   }

   public void onPageScrolled(int arg0, float arg1, int arg2) {
   }

   public void onPageScrollStateChanged(int arg0) {
   }
  });

 }

别忘了重写

 @Override
 public void onPause() {
  super.onPause();
  // stop auto scroll when onPause
  mPager1.stopAutoScroll();
 }

 @Override
 public void onResume() {
  super.onResume();
  // start auto scroll when onResume
  mPager1.startAutoScroll();
 }

好了,无限循环自动轮播,完成了.

5点点布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content">
 <!-- 小圆点View -->
 <View
  android:id="@+id/v_dot"
  android:layout_width="8dp"
  android:layout_height="8dp"
  android:layout_marginLeft="2dp"
  android:layout_marginRight="2dp"
  android:background="@drawable/dot_normal"/>
</RelativeLayout>

6 点点的background
dot_normal.xml

<?xml version="1.0" encoding="utf-8"?><!-- 圆点未选中 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
 android:shape="oval">
 <solid android:color="@color/background_color" />

 <corners android:radius="5dp" />
</shape>

dot_selected.xml

<?xml version="1.0" encoding="utf-8"?><!-- 圆点选中 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
 android:shape="oval">
 <solid android:color="@color/red" />
 <corners android:radius="5dp" />
</shape>

RecyclingPagerAdapter的源码依赖RecycleBin类,一并贴出来

public class RecycleBin {
 /**
 * Views that were on screen at the start of layout. This array is populated at the start of
 * layout, and at the end of layout all view in activeViews are moved to scrapViews.
 * Views in activeViews represent a contiguous range of Views, with position of the first
 * view store in mFirstActivePosition.
 */
 private View[] activeViews = new View[0];
 private int[] activeViewTypes = new int[0];

 /** Unsorted views that can be used by the adapter as a convert view. */
 private SparseArray<View>[] scrapViews;

 private int viewTypeCount;

 private SparseArray<View> currentScrapViews;

 public void setViewTypeCount(int viewTypeCount) {
 if (viewTypeCount < 1) {
  throw new IllegalArgumentException("Can't have a viewTypeCount < 1");
 }
 //noinspection unchecked
 SparseArray<View>[] scrapViews = new SparseArray[viewTypeCount];
 for (int i = 0; i < viewTypeCount; i++) {
  scrapViews[i] = new SparseArray<View>();
 }
 this.viewTypeCount = viewTypeCount;
 currentScrapViews = scrapViews[0];
 this.scrapViews = scrapViews;
 }

 protected boolean shouldRecycleViewType(int viewType) {
 return viewType >= 0;
 }

 /** @return A view from the ScrapViews collection. These are unordered. */
 View getScrapView(int position, int viewType) {
 if (viewTypeCount == 1) {
  return retrieveFromScrap(currentScrapViews, position);
 } else if (viewType >= 0 && viewType < scrapViews.length) {
  return retrieveFromScrap(scrapViews[viewType], position);
 }
 return null;
 }

 /**
 * Put a view into the ScrapViews list. These views are unordered.
 *
 * @param scrap The view to add
 */
 void addScrapView(View scrap, int position, int viewType) {
 if (viewTypeCount == 1) {
  currentScrapViews.put(position, scrap);
 } else {
  scrapViews[viewType].put(position, scrap);
 }

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
  scrap.setAccessibilityDelegate(null);
 }
 }

 /** Move all views remaining in activeViews to scrapViews. */
 void scrapActiveViews() {
 final View[] activeViews = this.activeViews;
 final int[] activeViewTypes = this.activeViewTypes;
 final boolean multipleScraps = viewTypeCount > 1;

 SparseArray<View> scrapViews = currentScrapViews;
 final int count = activeViews.length;
 for (int i = count - 1; i >= 0; i--) {
  final View victim = activeViews[i];
  if (victim != null) {
  int whichScrap = activeViewTypes[i];

  activeViews[i] = null;
  activeViewTypes[i] = -1;

  if (!shouldRecycleViewType(whichScrap)) {
   continue;
  }

  if (multipleScraps) {
   scrapViews = this.scrapViews[whichScrap];
  }
  scrapViews.put(i, victim);

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
   victim.setAccessibilityDelegate(null);
  }
  }
 }

 pruneScrapViews();
 }

 /**
 * Makes sure that the size of scrapViews does not exceed the size of activeViews.
 * (This can happen if an adapter does not recycle its views).
 */
 private void pruneScrapViews() {
 final int maxViews = activeViews.length;
 final int viewTypeCount = this.viewTypeCount;
 final SparseArray<View>[] scrapViews = this.scrapViews;
 for (int i = 0; i < viewTypeCount; ++i) {
  final SparseArray<View> scrapPile = scrapViews[i];
  int size = scrapPile.size();
  final int extras = size - maxViews;
  size--;
  for (int j = 0; j < extras; j++) {
  scrapPile.remove(scrapPile.keyAt(size--));
  }
 }
 }

 static View retrieveFromScrap(SparseArray<View> scrapViews, int position) {
 int size = scrapViews.size();
 if (size > 0) {
  // See if we still have a view for this position.
  for (int i = 0; i < size; i++) {
  int fromPosition = scrapViews.keyAt(i);
  View view = scrapViews.get(fromPosition);
  if (fromPosition == position) {
   scrapViews.remove(fromPosition);
   return view;
  }
  }
  int index = size - 1;
  View r = scrapViews.valueAt(index);
  scrapViews.remove(scrapViews.keyAt(index));
  return r;
 } else {
  return null;
 }
 }
}

RecyclingPagerAdapter

public abstract class RecyclingPagerAdapter extends PagerAdapter {
 static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE;

 private final RecycleBin recycleBin;

 public RecyclingPagerAdapter() {
 this(new RecycleBin());
 }

 RecyclingPagerAdapter(RecycleBin recycleBin) {
 this.recycleBin = recycleBin;
 recycleBin.setViewTypeCount(getViewTypeCount());
 }

 @Override public void notifyDataSetChanged() {
 recycleBin.scrapActiveViews();
 super.notifyDataSetChanged();
 }

 @Override public final Object instantiateItem(ViewGroup container, int position) {
 int viewType = getItemViewType(position);
 View view = null;
 if (viewType != IGNORE_ITEM_VIEW_TYPE) {
  view = recycleBin.getScrapView(position, viewType);
 }
 view = getView(position, view, container);
 container.addView(view);
 return view;
 }

 @Override public final void destroyItem(ViewGroup container, int position, Object object) {
 View view = (View) object;
 container.removeView(view);
 int viewType = getItemViewType(position);
 if (viewType != IGNORE_ITEM_VIEW_TYPE) {
  recycleBin.addScrapView(view, position, viewType);
 }
 }

 @Override public final boolean isViewFromObject(View view, Object object) {
 return view == object;
 }

 /**
 * <p>
 * Returns the number of types of Views that will be created by
 * {@link #getView}. Each type represents a set of views that can be
 * converted in {@link #getView}. If the adapter always returns the same
 * type of View for all items, this method should return 1.
 * </p>
 * <p>
 * This method will only be called when when the adapter is set on the
 * the {@link AdapterView}.
 * </p>
 *
 * @return The number of types of Views that will be created by this adapter
 */
 public int getViewTypeCount() {
 return 1;
 }

 /**
 * Get the type of View that will be created by {@link #getView} for the specified item.
 *
 * @param position The position of the item within the adapter's data set whose view type we
 *  want.
 * @return An integer representing the type of View. Two views should share the same type if one
 *   can be converted to the other in {@link #getView}. Note: Integers must be in the
 *   range 0 to {@link #getViewTypeCount} - 1. {@link #IGNORE_ITEM_VIEW_TYPE} can
 *   also be returned.
 * @see #IGNORE_ITEM_VIEW_TYPE
 */
 @SuppressWarnings("UnusedParameters") // Argument potentially used by subclasses.
 public int getItemViewType(int position) {
 return 0;
 }

 /**
 * Get a View that displays the data at the specified position in the data set. You can either
 * create a View manually or inflate it from an XML layout file. When the View is inflated, the
 * parent View (GridView, ListView...) will apply default layout parameters unless you use
 * {@link android.view.LayoutInflater#inflate(int, ViewGroup, boolean)}
 * to specify a root view and to prevent attachment to the root.
 *
 * @param position The position of the item within the adapter's data set of the item whose view
 *  we want.
 * @param convertView The old view to reuse, if possible. Note: You should check that this view
 *  is non-null and of an appropriate type before using. If it is not possible to convert
 *  this view to display the correct data, this method can create a new view.
 *  Heterogeneous lists can specify their number of view types, so that this View is
 *  always of the right type (see {@link #getViewTypeCount()} and
 *  {@link #getItemViewType(int)}).
 * @return A View corresponding to the data at the specified position.
 */
 public abstract View getView(int position, View convertView, ViewGroup container);
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android 使用ViewPager自动滚动循环轮播效果

    对Android 利用ViewPager实现图片可以左右循环滑动效果,感兴趣的朋友可以直接点击查看内容详情. 主要介绍如何实现ViewPager自动播放,循环滚动的效果及使用.顺便解决ViewPager嵌套(ViewPager inside ViewPager)影响触摸滑动及ViewPager滑动速度设置问题. 先给大家展示下效果图,喜欢的朋友可以下载源码: 1.实现 没有通过ScheduledExecutorService或Timer定期执行某个任务实现,而是简单的通过handler发送消息去

  • Android仿开心消消乐大树星星无限循环效果

    啥都不说先上效果图,这个是我项目里的效果: 下面的是我抽取出来的 demo 适配啥的我基本上都做好了没做其他的 ok 下面 说一下思路把 首先 说一下原理 我是使用bitmap 创建两张图 一开始的时候 一张在下面记为1号 一张在上面 记为2号 当手指向下滑动时 判断 1号 的起点位置 是否完全超出屏幕 如果超出屏幕的话 那么将2号变为下面 1号变为上面 (移动1号的Y坐标) 大体思路 是这样. 里面还有许多判断 比如 是否能向下滑动 起点位置, 星星的判定 哎呀 好烦 说的东西太多啦 来张我的

  • Android ViewPager无限循环实现底部小圆点动态滑动

    页面拖动到最后一页 再向下滑动回复到 第一页,第一页向前滑动回到 最后一页 同时,底部红色小圆点随着页面的滑动距离比例随时改变位置 布局: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas

  • Android ViewPager实现无限循环效果

    最近项目里有用到ViewPager来做广告运营位展示,看到现在很多APP的广告运营位都是无限循环的,所以就研究了一下这个功能的实现. 先看看效果 从一个方向上一直滑动,么有滑到尽头的感觉,具体是怎么实现的呢?看下面的思路. 实现思路 此处画了一幅图来表达实现无限循环的思路,即在数据起始位置前插入最后一项数据,在最后一项数据后插入第一项数据,当滑动到此处时,更新页面的索引位置就ok了 . 代码实现 这个方法用于数据处理,其中mediaList是原始数据,newMediaList是处理完的数据,mM

  • Android viewpager中动态添加view并实现伪无限循环的方法

    本文实例讲述了Android viewpager中动态添加view并实现伪无限循环的方法.分享给大家供大家参考,具体如下: viewpager的使用,大家都熟悉,它可以实现页面之间左右滑动的切换,这里有一个需求,就是viewpager里面加载的页数不是确定的,而是根据数据的多少来确定的.常见的应用就是在一个新闻的详细页面中,显示与此新闻有关的图片. 下面我们来看一下代码: activity_main.xml <RelativeLayout xmlns:android="http://sch

  • Android简单实现无限滚动自动滚动的ViewPager

    经常我们会在应用中看到一个可以自动滚动,并且无限滚动的一个ViewPager,百度谷歌上面也有很多关于这方面的教程,但是感觉都略显麻烦,而且封装的都不是很彻底.所以试着封装一个比较好用的ViewPager 效果如下: 简单的说一下实现思路,要实现无限滚动的话就要在PagerAdapter上面做一些手脚,在PagerAdapter的getCount的函数的返回值设置成Integer.MXA_VALUE就可以实现向右无限滚动,但是要实现向左无限滚动呢?就是一开始的时候setCurrentItem的时

  • Android实战打飞机游戏之无限循环的背景图(2)

    首先分析下游戏界面内的元素: 无限滚动的背景图, 可以操作的主角,主角的子弹, 主角的血量,两种怪物(敌机),一个boss, boss的爆炸效果. 先看效果图 1.首先实现无限滚动的背景图 原理: 定义两个位图对象 当第一个位图到末尾是 第二个位图从第一个位图的末尾跟上. public class GameBg { // 游戏背景的图片资源 // 为了循环播放,这里定义两个位图对象, // 其资源引用的是同一张图片 private Bitmap bmpBackGround1; private B

  • Android ViewPager实现智能无限循环滚动回绕效果

    android系统提供的ViewPager标准方式是左右可以自由滑动,但是滑动到最左边的极限位置是第一个page,滑动到最右边的位置是最后一个page,当滑动到最左或者最右时候,就不能再滑动/滚动了,这是Android系统默认的ViewPager实现方式. 但是有些情况下开发者可能希望ViewPager能够智能的无限循环滚动回绕,比如现在总共有编号1, 2, 3, 4, 5的5个Page. (1)当用户手指从右往左滚动到最右边/最后面的页面5时候,如果此时用户继续拖住ViewPager往左边滑动

  • Android实现基于ViewPager的无限循环自动播放带指示器的轮播图CarouselFigureView控件

    最近用到需要无限轮播自动播放的轮播轮播图,网上感觉都有这样那样的问题,于是自己写了一个通用的控件CarouselFigureView. 特点: 1.可以轮播view可以自己定义,不一定是要是ImageView2.指示器默认显示,但是可以隐藏3.可以设置指示器的颜色.间距.大小 4.有基础的可以自己修改代码改变指示器位置,这个应该不难5.可以自己开启和关闭自动轮播,开启轮播的时候可以设置轮播时间间隔,默认3000毫秒 我们先来看看效果图: 然后来看看使用代码 xml代码 <?xml version

  • Android 使用viewpager实现无限循环(定时+手动)

    循环轮播的方法有两种,一种是使用定时器另外一种是使用手指拨动,相比较而言,定时器实现循环播放比较容易,只要在定时器的消息里加上简单几段代码即可,下面分别就这两种方法给大家详解,具体详情请看下文吧. int count = adapter.getCount(); if (count > 1) { // 多于1个,才循环 int index = viewPager.getCurrentItem(); index = (index + 1) % count; viewPager.setCurrentI

随机推荐