網上80%的思路關於Android輪播圖無限循環都是不正確的,不是真正意義上的無限循環,html
其思路大可能是將ViewPager的getCount方法返回值設置爲Integer.MAX_VALUE,android
而後呢將ViewPager的當前展現頁設置爲第1000頁或者是10000頁,這樣用戶通常狀況下是滑不到邊界的網絡
例若有5張圖片的輪播圖,item的編號爲(0,1,2,3,4)當前頁的頁號若是是5, 這時候就將編號設置爲0,即 ide
actPosition %= datas.size();這個公式就是這麼來的
這種思路實現的無限輪播雖然能夠實現需求 可是卻不是真正意義的無限輪播,結合了iOS 、HTML5的無限輪播圖實現思路,總結以下:佈局
例如:有五張輪播圖 item的編號爲(0,1,2,3,4) 要想實現 無限循環 咱們在這五張的頭部和尾部各加一張即(5+2)張,item編號爲(0,1,2,3,4,5,6)其中編號爲0,6的兩張不作展現只是爲了作循環輪播的鋪墊,this
一、當咱們從編號爲5 右滑的時候到了編號6 這時候就將當前頁面設置爲1url
二、當咱們從編號爲1左滑的時候到了編號0 這時候就將當前頁面設置爲5spa
第一種狀況:線程
第二種狀況:code
這麼作以後就能夠實現無限輪播 怎麼保證從編號6跳轉編號1的時候不出現頁面停頓 忽然跳到下一頁的現象呢?
public Object instantiateItem (ViewGroup container, int position)
在指定的位置建立頁面;適配器負責添加view到這個容器中,然而它只保證在finishUpdate(ViewGroup)返回時才完成。
public void destroyItem (ViewGroup container, int position, Object object)
刪除指定位置的頁面;適配器負責從view容器中刪除view,然而它只保證在finishUpdate(ViewGroup)返回時才完成。
因此說 重點就在於finishUpdate(ViewGroup)這個方法 其實不管是建立view添加到容器中 仍是 銷燬view 都是在此方法結束以後執行的
換句話說 就是 我在這個方法裏讓頁面完成從 編號5跳轉到編號1 或者從編號1跳轉到編號5,此方法完成時 視圖還未完成建立或者 銷燬 這樣也就不會出現 頁面停頓 忽然跳到下一頁的現象
@Override public void finishUpdate(ViewGroup container) { int position = mBanner.getCurrentItem(); if (position == 0) { position = datas.size(); viewPager.setCurrentItem(position,false); } else if (position == (datas.size()+2) - 1) { position = 1; viewPager.setCurrentItem(position,false); } }
如此 完美解決 無限輪播
通常狀況下 輪播圖要求自動輪播 不要緊 咱們能夠利用Handler去開啓線程 讓其每隔必定時間去輪播
這裏的重點是 若是咱們定義每隔3秒輪播一張,當咱們用手滑動了以後這時候要從新計時,防止用戶剛滑動完 程序立馬又滑動一次,
handler.removeCallbacksAndMessages(null);
此方法意思是移除全部的定消息 handler.sendEmptyMessageDelayed(0,3000);
此方法是三秒以後發送一個 message.what=0的消息
完整的代碼
我定義了一個View名字叫TopView 實現每隔3秒輪播,而且下方有小圓點(當前顯示的編號小圓點會變成白色,其餘小圓點顯示爲灰色)的輪播圖
基本思路是 在FrameLayout裏邊底層是一個Viewpager 上層是一個LinearLayout 裏邊有對應張數的小圓點 小圓點是根據數據的個數動態生成的
類裏邊還定義了一個 點擊監聽接口 ,點擊對應的圖片能夠回調給調用者
public class TopView extends FrameLayout implements ViewPager.OnPageChangeListener { private ViewPager vPager; private List<ImageView> imgViews; private List<String> datas;// 數據源 private LinearLayout navLayout; private LinearLayout.LayoutParams layoutParams;//線性佈局中子控件使用的佈局參數,做用設置子控件大小,外邊距 private Context mContext; private DownLoadImage imageLoader; private int currentPosition=0; private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); currentPosition = (++currentPosition) % imgViews.size(); vPager.setCurrentItem(currentPosition,false); //處理完以前的消息以後再次發送一個3秒以後的消息 如此 可實現每隔三秒輪播 if(handler!=null){ handler.sendEmptyMessageDelayed(0,3000); } } }; public TopView(Context context) { this(context,null); } public TopView(Context context, AttributeSet attrs) { this(context,attrs,0); } public TopView(Context context,AttributeSet attrs,int defStyle) { super(context,attrs,defStyle); mContext=context; // 第二個參數this: 佈局資源中根標籤內聲明的佈局參數參考的父控件對象 // 第三個參數true: 表明是將第一個參數中聲明的子控件歸屬到第二個參數對象中,false不歸屬 LayoutInflater.from(context).inflate(R.layout.topview, this, true); initView(); } private void initView() { // 查找相關的UI控件 vPager = (ViewPager) findViewById(R.id.viewPager); navLayout = (LinearLayout) findViewById(R.id.navLayout); } public void setData(List<String> datas) { this.datas = datas; createViews(); } private void createViews() { // 根據數據源建立ViewPager中顯示的UI imgViews = new ArrayList<ImageView>();//加入數據源 layoutParams =new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT); // layoutParams.leftMargin=20; layoutParams.rightMargin=10;//px layoutParams.width=20; layoutParams.height=20; ImageView imgView = null; ImageView navImg = null; for (int i=0;i<datas.size();i++) { imgView = new ImageView(getContext()); imgView.setScaleType(ImageView.ScaleType.FIT_XY); imgView.setTag(datas.get(i)); imgViews.add(imgView); navImg = new ImageView(getContext()); navImg.setScaleType(ImageView.ScaleType.CENTER_CROP); if(i==0) navImg.setImageResource(R.drawable.page_now); else navImg.setImageResource(R.drawable.page); //設置導航圖片的標籤: 當前導航圖片的位置 navImg.setTag(i); navImg.setLayoutParams(layoutParams); navLayout.addView(navImg); } vPager.setAdapter(new ImageAdapter()); vPager.addOnPageChangeListener(this); loadImgs(); //開啓handler的線程 3秒以後發出此消息 if(handler!=null){ handler.sendEmptyMessageDelayed(0,3000); } } private void loadImgs() { // 加載網絡圖片加載後放入imageView for (int i=0;i<datas.size();i++) { String data=datas.get(i); for (ImageView imageView : imgViews) { if(imageView.getTag().equals(data)){ getImageView(imageView,data,i); } } } } class ImageAdapter extends PagerAdapter { @Override public int getCount() { return datas.size()+2; } @Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub return arg0 == arg1; } @Override public Object instantiateItem(ViewGroup container, int actPosition) { //對Viewpager頁號求模去除View列表中要顯示的項 actPosition %= datas.size(); ImageView view = imgViews.get(actPosition); //若是View已經在以前添加到了一個父組件,則必須先remove,不然會拋出IllegalStateException。 ViewParent viewParent = view.getParent(); if (viewParent!=null){ ViewGroup parent = (ViewGroup)viewParent; parent.removeView(view); } container.addView(view); return view; } @Override public void destroyItem(ViewGroup container, int actPosition, Object object) { //注意不在此方法進行removeView } @Override public void finishUpdate(ViewGroup container) { super.finishUpdate(container); int position = vPager.getCurrentItem(); if (position == 0) { position = datas.size(); currentPosition=position; if(handler!=null){ handler.removeCallbacksAndMessages(null); handler.sendEmptyMessageDelayed(0,3000); } vPager.setCurrentItem(position,false); } else if (position == (datas.size()+2) - 1) { position = 1; currentPosition=position; if(handler!=null){ handler.removeCallbacksAndMessages(null); handler.sendEmptyMessageDelayed(0,3000); } vPager.setCurrentItem(position,false); } } } @Override public void onPageScrollStateChanged(int arg0) { // TODO Auto-generated method stub } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { // TODO Auto-generated method stub } @Override public void onPageSelected(int position) { position=position % datas.size(); if(handler!=null){ handler.removeCallbacksAndMessages(null); } currentPosition=position; ImageView navImg = null; //遍歷 導航佈局中全部的子控件,判斷子控件的位置是否爲選擇位置,如果,則改變圖片的內容 for(int i=0;i<navLayout.getChildCount();i++){ navImg = (ImageView) navLayout.getChildAt(i );//獲取佈局中指定位置的子控件 if(i==position) navImg.setImageResource(R.drawable.page_now); else navImg.setImageResource(R.drawable.page); } if(handler!=null){ handler.sendEmptyMessageDelayed(0,3000); } } public interface TopViewClickListener{ public void onTopViewClick(int position); } public TopViewClickListener mTopViewClickListener; public void setTopViewClickListener(TopViewClickListener topViewClickListener){ mTopViewClickListener=topViewClickListener; } private ImageView getImageView(ImageView imageView,String url, final int position) { imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mTopViewClickListener != null) { mTopViewClickListener.onTopViewClick(position); } } }); if (imageLoader == null) { imageLoader = new DownLoadImage(mContext, R.drawable.bannerdefault, R.drawable.bannerdefault, null); } imageLoader.displayImage(url, imageView, null); return imageView; } }
TopView類中用到的佈局文件
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:id="@+id/navLayout" android:layout_height="30dp" android:layout_width="match_parent" android:layout_gravity="bottom" android:gravity="center" android:orientation="horizontal" /> </FrameLayout>
如何調用:
在activity_main.xml中
<com.myview.TopView android:id="@+id/topview" android:layout_width="match_parent" android:layout_height="@dimen/size_600px"/>
在MainActivity 中的僞代碼:
private TopView topView; public class ActivityMain extends Activity implements TopView.TopViewClickListener{
public void onCreate(。。。。。){ //urls是圖片的地址 topView.setData(urls); topView= (TopView) findViewById(R.id.topview); //設置點擊圖片事件的監聽器 topView.setTopViewClickListener(this); } @Override public void onTopViewClick(int position) { if (datas!= null && datas.size() > 0) { //用position去加載對應的數據便可 } } }
如此 完美解決真正意義上的無限輪播圖
嚴禁盜版
轉載請註明出處:https://www.cnblogs.com/bimingcong/p/9028515.html