首页 > 系统 > Android > 正文

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

2019-12-12 04:40:14
字体:
来源:转载
供稿:网友

想要实现无限轮播,一直向左滑动,当到最后一个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);}

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表