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'){
excludemodule:'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(后面会贴出来源码)
`publicclassIndicator1AdapterextendsRecyclingPagerAdapter{ privateList<Integer>imageIdList; Contextcontext; //是否循环(创造构造方法,在activity里设置是否) //集合大小 privateintsize; publicIndicator1Adapter(List<Integer>mData,Contextcontext){ this.imageIdList=mData; this.context=context; this.size=mData.size(); isInfiniteLoop=false; } @Override publicintgetCount(){ //是:最大(让集合的长度无限,从而模拟无限循环)否,集合长度 returnisInfiniteLoop?Integer.MAX_VALUE:imageIdList.size(); } /** *@returntheisInfiniteLoop */ publicbooleanisInfiniteLoop(){ returnisInfiniteLoop; } /** *@param是否无限循环 */ publicIndicator1AdaptersetInfiniteLoop(booleanisInfiniteLoop){ this.isInfiniteLoop=isInfiniteLoop; returnthis; } /** *真实的position * *@paramposition *@return */ privateintgetPosition(intposition){ returnisInfiniteLoop?position%size:position; } @Override publicViewgetView(intposition,Viewview,ViewGroupcontainer){ ViewHolderholder; if(view==null){ holder=newViewHolder(); view=holder.imageView=newImageView(context); view.setTag(holder); }else{ holder=(ViewHolder)view.getTag(); } holder.imageView.setImageResource(imageIdList.get(getPosition(position))); holder.imageView.setScaleType(ImageView.ScaleType.FIT_XY); returnview; } privatestaticclassViewHolder{ ImageViewimageView; } }
3在activity里或者fragment里就可以设置ViewPager
定义的成员变量:
//viewpager1 @BindView(R.id.viewpager1) AutoScrollViewPagermPager1; //承载小点点的控件容器(布局里有) @BindView(R.id.ll_dot1) LinearLayoutmLlDot1;
Indicator1Adapteradapter1=newIndicator1Adapter(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{ Fieldfield=ViewPager.class.getDeclaredField("mScroller"); field.setAccessible(true); FixedSpeedScrollerscroller=newFixedSpeedScroller(mPager1.getContext(), newAccelerateInterpolator()); field.set(mPager1,scroller); scroller.setmDuration(1200); }catch(Exceptione){ Log.e(TAG,"Exception",e); }
4然后我们的小点点还没有使用呢
这里我写了方法:
/** *设置状态点1 */ privatevoidsetOvalLayout1(){ for(inti=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(newViewPager.OnPageChangeListener(){ publicvoidonPageSelected(intposition){ //遍历图片数组 //Toast.makeText(act,"position"+position,Toast.LENGTH_SHORT).show(); for(inti=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; } publicvoidonPageScrolled(intarg0,floatarg1,intarg2){ } publicvoidonPageScrollStateChanged(intarg0){ } }); }
别忘了重写
@Override publicvoidonPause(){ super.onPause(); //stopautoscrollwhenonPause mPager1.stopAutoScroll(); } @Override publicvoidonResume(){ super.onResume(); //startautoscrollwhenonResume mPager1.startAutoScroll(); }
好了,无限循环自动轮播,完成了.
5点点布局:
<RelativeLayoutxmlns: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
<?xmlversion="1.0"encoding="utf-8"?><!--圆点未选中--> <shapexmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solidandroid:color="@color/background_color"/> <cornersandroid:radius="5dp"/> </shape>
dot_selected.xml
<?xmlversion="1.0"encoding="utf-8"?><!--圆点选中--> <shapexmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solidandroid:color="@color/red"/> <cornersandroid:radius="5dp"/> </shape>
RecyclingPagerAdapter的源码依赖RecycleBin类,一并贴出来
publicclassRecycleBin{ /** *Viewsthatwereonscreenatthestartoflayout.Thisarrayispopulatedatthestartof *layout,andattheendoflayoutallviewinactiveViewsaremovedtoscrapViews. *ViewsinactiveViewsrepresentacontiguousrangeofViews,withpositionofthefirst *viewstoreinmFirstActivePosition. */ privateView[]activeViews=newView[0]; privateint[]activeViewTypes=newint[0]; /**Unsortedviewsthatcanbeusedbytheadapterasaconvertview.*/ privateSparseArray<View>[]scrapViews; privateintviewTypeCount; privateSparseArray<View>currentScrapViews; publicvoidsetViewTypeCount(intviewTypeCount){ if(viewTypeCount<1){ thrownewIllegalArgumentException("Can'thaveaviewTypeCount<1"); } //noinspectionunchecked SparseArray<View>[]scrapViews=newSparseArray[viewTypeCount]; for(inti=0;i<viewTypeCount;i++){ scrapViews[i]=newSparseArray<View>(); } this.viewTypeCount=viewTypeCount; currentScrapViews=scrapViews[0]; this.scrapViews=scrapViews; } protectedbooleanshouldRecycleViewType(intviewType){ returnviewType>=0; } /**@returnAviewfromtheScrapViewscollection.Theseareunordered.*/ ViewgetScrapView(intposition,intviewType){ if(viewTypeCount==1){ returnretrieveFromScrap(currentScrapViews,position); }elseif(viewType>=0&&viewType<scrapViews.length){ returnretrieveFromScrap(scrapViews[viewType],position); } returnnull; } /** *PutaviewintotheScrapViewslist.Theseviewsareunordered. * *@paramscrapTheviewtoadd */ voidaddScrapView(Viewscrap,intposition,intviewType){ 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); } } /**MoveallviewsremaininginactiveViewstoscrapViews.*/ voidscrapActiveViews(){ finalView[]activeViews=this.activeViews; finalint[]activeViewTypes=this.activeViewTypes; finalbooleanmultipleScraps=viewTypeCount>1; SparseArray<View>scrapViews=currentScrapViews; finalintcount=activeViews.length; for(inti=count-1;i>=0;i--){ finalViewvictim=activeViews[i]; if(victim!=null){ intwhichScrap=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(); } /** *MakessurethatthesizeofscrapViewsdoesnotexceedthesizeofactiveViews. *(Thiscanhappenifanadapterdoesnotrecycleitsviews). */ privatevoidpruneScrapViews(){ finalintmaxViews=activeViews.length; finalintviewTypeCount=this.viewTypeCount; finalSparseArray<View>[]scrapViews=this.scrapViews; for(inti=0;i<viewTypeCount;++i){ finalSparseArray<View>scrapPile=scrapViews[i]; intsize=scrapPile.size(); finalintextras=size-maxViews; size--; for(intj=0;j<extras;j++){ scrapPile.remove(scrapPile.keyAt(size--)); } } } staticViewretrieveFromScrap(SparseArray<View>scrapViews,intposition){ intsize=scrapViews.size(); if(size>0){ //Seeifwestillhaveaviewforthisposition. for(inti=0;i<size;i++){ intfromPosition=scrapViews.keyAt(i); Viewview=scrapViews.get(fromPosition); if(fromPosition==position){ scrapViews.remove(fromPosition); returnview; } } intindex=size-1; Viewr=scrapViews.valueAt(index); scrapViews.remove(scrapViews.keyAt(index)); returnr; }else{ returnnull; } } }
RecyclingPagerAdapter
publicabstractclassRecyclingPagerAdapterextendsPagerAdapter{ staticfinalintIGNORE_ITEM_VIEW_TYPE=AdapterView.ITEM_VIEW_TYPE_IGNORE; privatefinalRecycleBinrecycleBin; publicRecyclingPagerAdapter(){ this(newRecycleBin()); } RecyclingPagerAdapter(RecycleBinrecycleBin){ this.recycleBin=recycleBin; recycleBin.setViewTypeCount(getViewTypeCount()); } @OverridepublicvoidnotifyDataSetChanged(){ recycleBin.scrapActiveViews(); super.notifyDataSetChanged(); } @OverridepublicfinalObjectinstantiateItem(ViewGroupcontainer,intposition){ intviewType=getItemViewType(position); Viewview=null; if(viewType!=IGNORE_ITEM_VIEW_TYPE){ view=recycleBin.getScrapView(position,viewType); } view=getView(position,view,container); container.addView(view); returnview; } @OverridepublicfinalvoiddestroyItem(ViewGroupcontainer,intposition,Objectobject){ Viewview=(View)object; container.removeView(view); intviewType=getItemViewType(position); if(viewType!=IGNORE_ITEM_VIEW_TYPE){ recycleBin.addScrapView(view,position,viewType); } } @OverridepublicfinalbooleanisViewFromObject(Viewview,Objectobject){ returnview==object; } /** *<p> *ReturnsthenumberoftypesofViewsthatwillbecreatedby *{@link#getView}.Eachtyperepresentsasetofviewsthatcanbe *convertedin{@link#getView}.Iftheadapteralwaysreturnsthesame *typeofViewforallitems,thismethodshouldreturn1. *</p> *<p> *Thismethodwillonlybecalledwhenwhentheadapterissetonthe *the{@linkAdapterView}. *</p> * *@returnThenumberoftypesofViewsthatwillbecreatedbythisadapter */ publicintgetViewTypeCount(){ return1; } /** *GetthetypeofViewthatwillbecreatedby{@link#getView}forthespecifieditem. * *@parampositionThepositionoftheitemwithintheadapter'sdatasetwhoseviewtypewe *want. *@returnAnintegerrepresentingthetypeofView.Twoviewsshouldsharethesametypeifone *canbeconvertedtotheotherin{@link#getView}.Note:Integersmustbeinthe *range0to{@link#getViewTypeCount}-1.{@link#IGNORE_ITEM_VIEW_TYPE}can *alsobereturned. *@see#IGNORE_ITEM_VIEW_TYPE */ @SuppressWarnings("UnusedParameters")//Argumentpotentiallyusedbysubclasses. publicintgetItemViewType(intposition){ return0; } /** *GetaViewthatdisplaysthedataatthespecifiedpositioninthedataset.Youcaneither *createaViewmanuallyorinflateitfromanXMLlayoutfile.WhentheViewisinflated,the *parentView(GridView,ListView...)willapplydefaultlayoutparametersunlessyouuse *{@linkandroid.view.LayoutInflater#inflate(int,ViewGroup,boolean)} *tospecifyarootviewandtopreventattachmenttotheroot. * *@parampositionThepositionoftheitemwithintheadapter'sdatasetoftheitemwhoseview *wewant. *@paramconvertViewTheoldviewtoreuse,ifpossible.Note:Youshouldcheckthatthisview *isnon-nullandofanappropriatetypebeforeusing.Ifitisnotpossibletoconvert *thisviewtodisplaythecorrectdata,thismethodcancreateanewview. *Heterogeneouslistscanspecifytheirnumberofviewtypes,sothatthisViewis *alwaysoftherighttype(see{@link#getViewTypeCount()}and *{@link#getItemViewType(int)}). *@returnAViewcorrespondingtothedataatthespecifiedposition. */ publicabstractViewgetView(intposition,ViewconvertView,ViewGroupcontainer); }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。