Android實現(xiàn)帶指示點的自動輪播無限循環(huán)效果
想要實現(xiàn)無限輪播,一直向左滑動,當?shù)阶詈笠粋€view時,會滑動到第一個,無限…
可以自己寫ViewPager然后加handler先實現(xiàn)自動滾動,當然這里我為了項目的進度直接使用了Trinea的Android-auto-scroll-view-pager庫,網(wǎng)址:點擊進入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 構(gòu)建PagerAdapter
繼承自RecyclingPagerAdapter (后面會貼出來源碼)
`public class Indicator1Adapter extends RecyclingPagerAdapter {
private List<Integer> imageIdList;
Context context;
//是否循環(huán)(創(chuàng)造構(gòu)造方法,在activity里設(shè)置是否)
//集合大小
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() {
//是:最大(讓集合的長度無限,從而模擬無限循環(huán)) 否,集合長度
return isInfiniteLoop ? Integer.MAX_VALUE : imageIdList.size();
}
/**
* @return the isInfiniteLoop
*/
public boolean isInfiniteLoop() {
return isInfiniteLoop;
}
/**
* @param是否無限循環(huán)
*/
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里就可以設(shè)置ViewPager
定義的成員變量:
//viewpager1 @BindView(R.id.viewpager1) AutoScrollViewPager mPager1; //承載小點點的控件容器(布局里有) @BindView(R.id.ll_dot1) LinearLayout mLlDot1;
Indicator1Adapter adapter1 = new Indicator1Adapter( mData,act).setInfiniteLoop(true);//開啟無限循環(huán) mPager1.setAdapter(adapter1); mPager1.setInterval(PLAY_TIME);//輪播時間間隔 mPager1.startAutoScroll();//開啟自動輪播 mPager1.setCurrentItem(Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % mData.size());
然后你嫌棄官方的換圖間隔時間太短,一閃而過,可以通過反射 設(shè)置
//通過反射讓滾動速度為自己的喜好的(這里設(shè)為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 然后我們的小點點還沒有使用呢
這里我寫了方法:
/**
* 設(shè)置狀態(tài)點1
*/
private void setOvalLayout1() {
for (int i = 0; i < mData.size(); i++) {
/**
* 生成對應(yīng)數(shù)量的點點(布局,結(jié)果提供)
*/
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) {
//遍歷圖片數(shù)組
// Toast.makeText(act, "position"+position, Toast.LENGTH_SHORT).show();
for (int i = 0; i < mData.size(); i++) {
if(i==position%mData.size()){
// 圓點選中
/**
* 這里需要注意如果直接寫position,由于我們是無限循環(huán),他的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();
}
好了,無限循環(huán)自動輪播,完成了.
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);
}
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- Android 使用viewpager實現(xiàn)無限循環(huán)(定時+手動)
- Android viewpager中動態(tài)添加view并實現(xiàn)偽無限循環(huán)的方法
- Android ViewPager無限循環(huán)實現(xiàn)底部小圓點動態(tài)滑動
- Android ViewPager無限循環(huán)滑動并可自動滾動完整實例
- Android無限循環(huán)RecyclerView的完美實現(xiàn)方案
- Android ViewPager實現(xiàn)無限循環(huán)效果
- Android實現(xiàn)ViewPager無限循環(huán)效果(一)
- Android實現(xiàn)基于ViewPager的無限循環(huán)自動播放帶指示器的輪播圖CarouselFigureView控件
- Android實戰(zhàn)打飛機游戲之無限循環(huán)的背景圖(2)
- Android TV 3D卡片無限循環(huán)效果
相關(guān)文章
Android ListView列表控件的介紹和性能優(yōu)化
這篇文章主要介紹了Android ListView列表控件的介紹和性能優(yōu)化,需要的朋友可以參考下2017-06-06
Android開發(fā)之5.0activity跳轉(zhuǎn)時共享元素的使用方法
下面小編就為大家分享一篇Android開發(fā)之5.0activity跳轉(zhuǎn)時共享元素的使用方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01
談?wù)凙ndroid開發(fā)之RecyclerView的使用全解
這篇文章主要介紹了談?wù)凙ndroid開發(fā)之RecyclerView的使用全解,非常具有實用價值,需要的朋友可以參考下。2016-12-12
Android 中 Activity顯示隱式跳轉(zhuǎn)
這篇文章主要介紹了Android 中 Activity顯示隱式跳轉(zhuǎn)的實現(xiàn)方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-02-02
Android實現(xiàn)視頻播放--騰訊瀏覽服務(wù)(TBS)功能
TBS視頻播放器可以支持市面上幾乎所有的視頻格式,包括mp4, flv, avi, 3gp, webm, ts, ogv, m3u8, asf, wmv, rm, rmvb, mov, mkv等18種視頻格式。這篇文章主要介紹了Android實現(xiàn)視頻播放--騰訊瀏覽服務(wù)(TBS),需要的朋友可以參考下2018-07-07
Flutter實現(xiàn)webview與原生組件組合滑動的示例代碼
這篇文章主要介紹了Flutter實現(xiàn)webview與原生組件組合滑動的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-03-03

