自定義完美的ViewPager 真正無限循環的輪播圖

       網上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

 

相關文章
相關標籤/搜索