Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自動輪播(無限循環),帶指示點

Android自動輪播(無限循環),帶指示點

編輯:關於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布局為
android:layout_width="match_parent"
android:layout_height="@dimen/y150">
android:id="@+id/viewpager1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

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" />


2 構建PagerAdapter
繼承自RecyclingPagerAdapter (後面會貼出來源碼)

  `public class Indicator1Adapter extends RecyclingPagerAdapter {
    private List imageIdList;
    Context context;
    //是否循環(創造構造方法,在activity裡設置是否)
    //集合大小
    private int  size;

    public Indicator1Adapter(List 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點點布局:


    
    

6 點點的background
dot_normal.xml



    

    

dot_selected.xml



    
    

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[] scrapViews;

  private int viewTypeCount;

  private SparseArray currentScrapViews;

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


  /**
   * 
* 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. *

*
* This method will only be called when when the adapter is set on the * the {@link AdapterView}. *

* * @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); }

–>路要一步一步走,記住自己走過的路,不再犯同樣的錯誤,才是真正的成長!歡迎指點、交流。<–

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved