Android實(shí)現(xiàn)帶指示點(diǎn)的自動(dòng)輪播無(wú)限循環(huán)效果
想要實(shí)現(xiàn)無(wú)限輪播,一直向左滑動(dòng),當(dāng)?shù)阶詈笠粋€(gè)view時(shí),會(huì)滑動(dòng)到第一個(gè),無(wú)限…
可以自己寫ViewPager然后加handler先實(shí)現(xiàn)自動(dòng)滾動(dòng),當(dāng)然這里我為了項(xiàng)目的進(jìn)度直接使用了Trinea的Android-auto-scroll-view-pager庫(kù),網(wǎng)址:點(diǎn)擊進(jìn)入github 引用庫(kù)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" /> <!--點(diǎn)點(diǎn)的布局--> <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 (后面會(huì)貼出來(lái)源碼)
`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() { //是:最大(讓集合的長(zhǎng)度無(wú)限,從而模擬無(wú)限循環(huán)) 否,集合長(zhǎng)度 return isInfiniteLoop ? Integer.MAX_VALUE : imageIdList.size(); } /** * @return the isInfiniteLoop */ public boolean isInfiniteLoop() { return isInfiniteLoop; } /** * @param是否無(wú)限循環(huán) */ public Indicator1Adapter setInfiniteLoop(boolean isInfiniteLoop) { this.isInfiniteLoop = isInfiniteLoop; return this; } /** * 真實(shí)的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; //承載小點(diǎn)點(diǎn)的控件容器(布局里有) @BindView(R.id.ll_dot1) LinearLayout mLlDot1;
Indicator1Adapter adapter1 = new Indicator1Adapter( mData,act).setInfiniteLoop(true);//開啟無(wú)限循環(huán) mPager1.setAdapter(adapter1); mPager1.setInterval(PLAY_TIME);//輪播時(shí)間間隔 mPager1.startAutoScroll();//開啟自動(dòng)輪播 mPager1.setCurrentItem(Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % mData.size());
然后你嫌棄官方的換圖間隔時(shí)間太短,一閃而過(guò),可以通過(guò)反射 設(shè)置
//通過(guò)反射讓滾動(dòng)速度為自己的喜好的(這里設(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 然后我們的小點(diǎn)點(diǎn)還沒(méi)有使用呢
這里我寫了方法:
/** * 設(shè)置狀態(tài)點(diǎn)1 */ private void setOvalLayout1() { for (int i = 0; i < mData.size(); i++) { /** * 生成對(duì)應(yīng)數(shù)量的點(diǎn)點(diǎn)(布局,結(jié)果提供) */ mLlDot1.addView(inflater.inflate(R.layout.dot, null)); } // 默認(rèn)顯示第一頁(yè) 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()){ // 圓點(diǎn)選中 /** * 這里需要注意如果直接寫position,由于我們是無(wú)限循環(huán),他的position是無(wú)限往上 *增加的,那么就會(huì)報(bào)空指針,因?yàn)槲覀兛偣膊派闪薽Data.size()個(gè)點(diǎn)點(diǎn),這里可以讓當(dāng)前的 *position取余,得到的即是當(dāng)前位置的點(diǎn)點(diǎn) */ mLlDot1.getChildAt(position%mData.size()) .findViewById(R.id.v_dot) .setBackgroundResource(R.drawable.dot_selected); }else{ // 取消圓點(diǎn)選中 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(); }
好了,無(wú)限循環(huán)自動(dòng)輪播,完成了.
5點(diǎn)點(diǎn)布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <!-- 小圓點(diǎn)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 點(diǎn)點(diǎn)的background
dot_normal.xml
<?xml version="1.0" encoding="utf-8"?><!-- 圓點(diǎn)未選中 --> <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"?><!-- 圓點(diǎn)選中 --> <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類,一并貼出來(lái)
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); }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android 使用viewpager實(shí)現(xiàn)無(wú)限循環(huán)(定時(shí)+手動(dòng))
- Android viewpager中動(dòng)態(tài)添加view并實(shí)現(xiàn)偽無(wú)限循環(huán)的方法
- Android ViewPager無(wú)限循環(huán)實(shí)現(xiàn)底部小圓點(diǎn)動(dòng)態(tài)滑動(dòng)
- Android ViewPager無(wú)限循環(huán)滑動(dòng)并可自動(dòng)滾動(dòng)完整實(shí)例
- Android無(wú)限循環(huán)RecyclerView的完美實(shí)現(xiàn)方案
- Android ViewPager實(shí)現(xiàn)無(wú)限循環(huán)效果
- Android實(shí)現(xiàn)ViewPager無(wú)限循環(huán)效果(一)
- Android實(shí)現(xiàn)基于ViewPager的無(wú)限循環(huán)自動(dòng)播放帶指示器的輪播圖CarouselFigureView控件
- Android實(shí)戰(zhàn)打飛機(jī)游戲之無(wú)限循環(huán)的背景圖(2)
- Android TV 3D卡片無(wú)限循環(huán)效果
相關(guān)文章
Android ListView列表控件的介紹和性能優(yōu)化
這篇文章主要介紹了Android ListView列表控件的介紹和性能優(yōu)化,需要的朋友可以參考下2017-06-06Android開發(fā)之5.0activity跳轉(zhuǎn)時(shí)共享元素的使用方法
下面小編就為大家分享一篇Android開發(fā)之5.0activity跳轉(zhuǎn)時(shí)共享元素的使用方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01談?wù)凙ndroid開發(fā)之RecyclerView的使用全解
這篇文章主要介紹了談?wù)凙ndroid開發(fā)之RecyclerView的使用全解,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。2016-12-12Android 中 Activity顯示隱式跳轉(zhuǎn)
這篇文章主要介紹了Android 中 Activity顯示隱式跳轉(zhuǎn)的實(shí)現(xiàn)方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02Android實(shí)現(xiàn)視頻播放--騰訊瀏覽服務(wù)(TBS)功能
TBS視頻播放器可以支持市面上幾乎所有的視頻格式,包括mp4, flv, avi, 3gp, webm, ts, ogv, m3u8, asf, wmv, rm, rmvb, mov, mkv等18種視頻格式。這篇文章主要介紹了Android實(shí)現(xiàn)視頻播放--騰訊瀏覽服務(wù)(TBS),需要的朋友可以參考下2018-07-07Android自定義星星可滑動(dòng)評(píng)分控件
這篇文章主要介紹了Android自定義星星可滑動(dòng)評(píng)分控件,通過(guò)線性布局結(jié)合ImageView實(shí)現(xiàn)評(píng)分控件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03Flutter實(shí)現(xiàn)webview與原生組件組合滑動(dòng)的示例代碼
這篇文章主要介紹了Flutter實(shí)現(xiàn)webview與原生組件組合滑動(dòng)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03