Android Viewpager實現真正無限循環的輪播圖

在網上找了很多viewpager實現圖片輪播的,但是大多數通過以下方式在PagerAdapter的getCount()返回一個無限大的數,來實現 僞無限

    @Override
    public int getCount() {
        return Integer.MAX_VALUE;//返回一個無限大的值,可以 無限循環
    }

雖然通過這種方式是能達到效果,但是從嚴格意義上來說並不是真正的無限。

假如有五張輪播圖 item的編號爲(0,1,2,3,4) 要想實現 無限循環  我們在這五張的頭部和尾部各加一張即(5+2)張,item編號爲(0,1,2,3,4,5,6)其中編號爲0,6的兩張不做展示只是爲了做循環輪播的鋪墊,使得播放更加平滑。

     1、當我們從編號爲5 右滑的時候到了編號6 這時候就將當前頁面設置爲1

     2、當我們從編號爲1左滑的時候到了編號0  這時候就將當前頁面設置爲5

 

這麼做之後就可以實現無限輪播  怎麼保證從編號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) {
       super.finishUpdate(container);

       int position = viewPager.getCurrentItem();
       
       if (position == 0) {
           position = simpleDraweeViewList.size() - 2;
           viewPager.setCurrentItem(position,false);
       } else if (position == simpleDraweeViewList.size() - 1) {
           position = 1;
           viewPager.setCurrentItem(position,false);
       }
   }

話不多說,上代碼:

佈局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/frameLayout"
        android:layout_width="0dp"
        android:layout_height="200dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:layout_editor_absoluteX="8dp"
            tools:layout_editor_absoluteY="0dp" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="35dip"
            android:layout_gravity="bottom"
            android:background="#33000000"
            android:gravity="center_vertical"
            android:orientation="horizontal"
            android:weightSum="10">

            <TextView
                android:id="@+id/tv_pager_title"
                android:layout_width="0dp"
                android:layout_height="35dip"
                android:layout_weight="8"
                android:gravity="center_vertical"
                android:paddingLeft="8dip"
                android:text="加載圖片輪播失敗"
                android:textColor="@android:color/white" />

            <LinearLayout
                android:id="@+id/lineLayout_dot"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_marginRight="5dp"
                android:layout_weight="2"
                android:gravity="center|right"
                android:orientation="horizontal"
                android:paddingLeft="3dp"
                android:paddingRight="3dp" />

        </LinearLayout>

    </FrameLayout>

</android.support.constraint.ConstraintLayout>

最主要的PagerAdapter:


import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import com.facebook.drawee.view.SimpleDraweeView;

import java.util.List;

public class ImagesPagerAdapter extends PagerAdapter {
    private List<SimpleDraweeView> simpleDraweeViewList;
    private ViewPager viewPager;
    private Context context;

    private SimpleDraweeView simpleDraweeView;

    public ImagesPagerAdapter(List<SimpleDraweeView> simpleDraweeViewList, ViewPager viewPager, Context context) {
        this.simpleDraweeViewList = simpleDraweeViewList;
        this.viewPager = viewPager;
        this.context = context;
    }

    @Override
    public int getCount() {
		return simpleDraweeViewList.size();
    }

    //刪除指定位置的頁面;適配器負責從view容器中刪除view,然而它只保證在finishUpdate(ViewGroup)返回時才完成。
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        // 把ImageView從ViewPager中移除掉
        viewPager.removeView(simpleDraweeViewList.get(position));
        //super.destroyItem(container, position, object);
    }

    //是否獲取緩存
    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }


    //實例化Item
    //在指定的位置創建頁面;適配器負責添加view到這個容器中,然而它只保證在finishUpdate(ViewGroup)返回時才完成。
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        simpleDraweeView = simpleDraweeViewList.get(position);
        viewPager.addView(simpleDraweeView);
        return simpleDraweeView;
    }
	
    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    //無論是創建view添加到容器中  還是 銷燬view 都是在此方法結束之後執行的
	@Override
   public void finishUpdate(ViewGroup container) {
       super.finishUpdate(container);

       int position = viewPager.getCurrentItem();
       
       if (position == 0) {
           position = simpleDraweeViewList.size() - 2;
           viewPager.setCurrentItem(position,false);
       } else if (position == simpleDraweeViewList.size() - 1) {
           position = 1;
           viewPager.setCurrentItem(position,false);
       }
   }



/*    private int mChildCount = 0;

    @Override
    public void notifyDataSetChanged() {
        mChildCount = getCount();
        super.notifyDataSetChanged();
    }

    @Override
    public int getItemPosition(Object object) {
        if (mChildCount > 0) {
            mChildCount--;
            Log.e("image","getItemPosition");
            return POSITION_NONE;
        }
        return super.getItemPosition(object);
    }*/
}


import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.facebook.drawee.view.SimpleDraweeView;

import java.util.ArrayList;
import java.util.List;



public class ImageCarousel {
    private Context context;
    private ViewPager viewPager;
    private TextView tvTitle;
    private LinearLayout dotsRoot;
    private int time;


    private List<View> dots;//小點
    private int previousPosition = 1;//前一個被選中的position
    private List<SimpleDraweeView> simpleDraweeViewList;
    private String[] titles;//標題數組

    private ImagesPagerAdapter adapter;

    private AutoPlayThread autoPlayThread;
    private volatile boolean isExit = true;

    private static final int FIRST_PAGE = 1;


    public ImageCarousel(Context context, ViewPager viewPager, TextView tvTitle,
                         List<View> dots, int time) {
        this.context = context;
        this.viewPager = viewPager;
        this.tvTitle = tvTitle;
        this.dots = dots;
        this.time = time;
        Log.e("image", "構造方法");
    }



    /**
     * 傳入數據
     *
     * @param simpleDraweeViewList SimpleDraweeView集合
     * @param titles               標題數組
     * @return this 本身
     */
    public ImageCarousel init(List<SimpleDraweeView> simpleDraweeViewList, String[] titles) {
        this.simpleDraweeViewList = simpleDraweeViewList;
        this.titles = titles;
        Log.e("image", "init");
        autoPlayThread = new AutoPlayThread();

        return this;
    }

    /**
     * 重新加載,有待考驗...
     *
     * @param simpleDraweeViewList SimpleDraweeView集合
     * @param titles               標題數組
     */
    public void reload(List<SimpleDraweeView> simpleDraweeViewList, String[] titles) {
        init(simpleDraweeViewList, titles);
        previousPosition = 0;
        start();
    }

    /**
     * 設置設配器,並實現輪播功能
     */
    public void start() {
        if (adapter != null) {
            adapter = null;
        }
        adapter = new ImagesPagerAdapter(this.simpleDraweeViewList, viewPager, context);
        viewPager.setAdapter(adapter);
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            //當被選擇
            @Override
            public void onPageSelected(int position) {

                int currentPosition = 1;
                if (position == simpleDraweeViewList.size() - 1) {
                    // 設置當前值爲1
                    currentPosition = FIRST_PAGE;
                } else if (position == 0) {
                    // 如果索引值爲0了,就設置索引值爲倒數第二個
                    currentPosition = simpleDraweeViewList.size() - 2;
                } else {
                    currentPosition = position;
                }

                // 把當前選中的點給切換了, 還有描述信息也切換
                tvTitle.setText(titles[currentPosition]);//圖片下面設置顯示文本
                //設置輪播點 可設置成傳入的圖

                Log.d("dots", "previousPosition=" + previousPosition + " currentPosition=" + currentPosition);
                dots.get(previousPosition-1).setBackgroundResource(R.drawable.ic_dot_focused);
                dots.get(currentPosition-1).setBackgroundResource(R.drawable.ic_dot_normal);
                // 把當前的索引賦值給前一個索引變量, 方便下一次再切換.
                previousPosition = currentPosition;
            }

            @Override
            public void onPageScrollStateChanged(int state) {
				// SCROLL_STATE_IDLE :空閒狀態 
				// SCROLL_STATE_DRAGGING :滑動狀態 
				// SCROLL_STATE_SETTLING :滑動後滑翔的狀態
                if (state == ViewPager.SCROLL_STATE_DRAGGING) {

                } else if(state == ViewPager.SCROLL_STATE_IDLE){
					
				}
            }
        });

        setFirstLocation();
        //autoPlayThread.start();

    }

    /**
     * 設置剛打開app時顯示的圖片和文字
     */
    private void setFirstLocation() {
        tvTitle.setText(titles[0]);
        dots.get(0).setBackgroundResource(R.drawable.ic_dot_normal);
        viewPager.setCurrentItem(1);
    }

    /**
     * 設置是否輪播
     *
     * @param b
     */
    private void setAutoPlay(boolean b) {
        /*if (b && suspendRequested) {
            autoPlayThread.requestResume();

        } else if (!b){
            autoPlayThread.requestSuspend();
        }*/
    }


    public void stopAutoPlay() {
        if (autoPlayThread != null) {
            Log.e("thrad", "暫停");
            isExit = true;
            autoPlayThread.interrupt();
            autoPlayThread = null;
        }
    }

    /**
     * 請求繼續
     */
    public void startAutoPlay() {
        Log.e("thrad", "開始");
        isExit = false;
        autoPlayThread = null;
        autoPlayThread = new AutoPlayThread();
        autoPlayThread.start();
    }

    /**
     * 自動播放線程,添加暫停和繼續方法
     */
    class AutoPlayThread extends Thread {

        @Override
        public synchronized void run() {
            while (!isExit) {
                try {
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    Log.e("thrad", "強制請求退出線程");
                    break;
                }
                ((Activity) context).runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
                    }
                });

                if (this.interrupted()) {
                    Log.e("thrad", "已經是停止狀態了,我要退出了");
                    break;
                }
            }

        }

    }

}

mainActivity.java:



import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.backends.pipeline.PipelineDraweeController;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.common.ResizeOptions;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    // 圖片輪播控件
    private ViewPager mViewPager;
    private TextView mTvPagerTitle;
    private LinearLayout mLineLayoutDot;
    private ImageCarousel imageCarousel;
    private List<View> dots;//小點

    // 圖片數據,包括圖片標題、圖片鏈接、數據、點擊要打開的網站(點擊打開的網頁或一些提示指令)
    private List<ImageInfo> imageInfoList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initEvent();
        imageStart();

    }

    @Override
    public void onClick(View v) {

    }

    /**
     * 初始化事件
     * 左右多添加一張圖片
     */
    private void initEvent() {
        imageInfoList = new ArrayList<>();
		imageInfoList.add(new ImageInfo(1, "圖片5,公告5啦啦啦啦", "", "http://e.hiphotos.baidu.com/image/h%3D300/sign=73443062281f95cab9f594b6f9177fc5/72f082025aafa40fafb5fbc1a664034f78f019be.jpg", ""));
        imageInfoList.add(new ImageInfo(2, "圖片1,公告1啦啦啦啦", "", "http://d.hiphotos.baidu.com/image/pic/item/6159252dd42a2834a75bb01156b5c9ea15cebf2f.jpg", ""));
        imageInfoList.add(new ImageInfo(3, "圖片2,公告2啦啦啦啦", "", "http://c.hiphotos.baidu.com/image/h%3D300/sign=cfce96dfa251f3dedcb2bf64a4eff0ec/4610b912c8fcc3ce912597269f45d688d43f2039.jpg", ""));
        imageInfoList.add(new ImageInfo(4, "圖片3,公告3啦啦啦啦", "", "http://e.hiphotos.baidu.com/image/pic/item/6a600c338744ebf85ed0ab2bd4f9d72a6059a705.jpg", ""));
        imageInfoList.add(new ImageInfo(5, "圖片4,公告4啦啦啦啦", "", "http://b.hiphotos.baidu.com/image/h%3D300/sign=8ad802f3801001e9513c120f880e7b06/a71ea8d3fd1f4134be1e4e64281f95cad1c85efa.jpg", ""));
        imageInfoList.add(new ImageInfo(6, "圖片5,公告5啦啦啦啦", "", "http://e.hiphotos.baidu.com/image/h%3D300/sign=73443062281f95cab9f594b6f9177fc5/72f082025aafa40fafb5fbc1a664034f78f019be.jpg", ""));
		imageInfoList.add(new ImageInfo(7, "圖片1,公告1啦啦啦啦", "", "http://d.hiphotos.baidu.com/image/pic/item/6159252dd42a2834a75bb01156b5c9ea15cebf2f.jpg", ""));

    }

    /**
     * 初始化控件
     */
    private void initView() {

        mViewPager = findViewById(R.id.viewPager);
        mTvPagerTitle = findViewById(R.id.tv_pager_title);
        mLineLayoutDot = findViewById(R.id.lineLayout_dot);

    }

    private void imageStart() {
        //設置圖片輪播
        int[] imgaeIds = new int[]{R.id.pager_image1, R.id.pager_image2, R.id.pager_image3, R.id.pager_image4,
                R.id.pager_image5, R.id.pager_image6, R.id.pager_image7, R.id.pager_image8};
        String[] titles = new String[imageInfoList.size()];
        List<SimpleDraweeView> simpleDraweeViewList = new ArrayList<>();

        for (int i = 0; i < imageInfoList.size(); i++) {
            titles[i] = imageInfoList.get(i).getTitle();
            SimpleDraweeView simpleDraweeView = new SimpleDraweeView(this);
            simpleDraweeView.setAspectRatio(1.78f);
            // 設置一張默認的圖片
            GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(this.getResources())
                    .setPlaceholderImage(ContextCompat.getDrawable(this, R.drawable.defult), ScalingUtils.ScaleType.CENTER_CROP).build();
            simpleDraweeView.setHierarchy(hierarchy);
            simpleDraweeView.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.WRAP_CONTENT));

            //加載高分辨率圖片;
            ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageInfoList.get(i).getImage()))
                    .setResizeOptions(new ResizeOptions(1280, 720))
                    .build();
            PipelineDraweeController controller = (PipelineDraweeController) Fresco.newDraweeControllerBuilder()
                    //.setLowResImageRequest(ImageRequest.fromUri(Uri.parse(listItemBean.test_pic_low))) //在加載高分辨率圖片之前加載低分辨率圖片
                    .setImageRequest(imageRequest)
                    .setOldController(simpleDraweeView.getController())
                    .build();
            simpleDraweeView.setController(controller);

            simpleDraweeView.setId(imgaeIds[i]);//給view設置id
            simpleDraweeView.setTag(imageInfoList.get(i));
            simpleDraweeView.setOnClickListener(this);
            titles[i] = imageInfoList.get(i).getTitle();
            simpleDraweeViewList.add(simpleDraweeView);

        }

        dots = addDots(mLineLayoutDot, fromResToDrawable(this, R.drawable.ic_dot_focused), simpleDraweeViewList.size());
        imageCarousel = new ImageCarousel(this, mViewPager, mTvPagerTitle, dots, 5000);
        imageCarousel.init(simpleDraweeViewList, titles)
                .startAutoPlay();
        imageCarousel.start();

    }


    /**
     * 動態添加一個點
     *
     * @param linearLayout 添加到LinearLayout佈局
     * @param backgount    設置
     * @return 小點的Id
     */
    private int addDot(final LinearLayout linearLayout, Drawable backgount) {
        final View dot = new View(this);
        LinearLayout.LayoutParams dotParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        dotParams.width = 16;
        dotParams.height = 16;
        dotParams.setMargins(4, 0, 4, 0);
        dot.setLayoutParams(dotParams);
        dot.setBackground(backgount);
        dot.setId(View.generateViewId());
        ((Activity) this).runOnUiThread(new Runnable() {
            @Override
            public void run() {
                linearLayout.addView(dot);
            }
        });

        return dot.getId();
    }


    /**
     * 資源圖片轉Drawable
     *
     * @param context 上下文
     * @param resId   資源ID
     * @return 返回Drawable圖像
     */
    public static Drawable fromResToDrawable(Context context, int resId) {
        return ContextCompat.getDrawable(context, resId);
    }

    /**
     * 添加多個輪播小點到橫向線性佈局
     *
     * @param linearLayout 線性橫向佈局
     * @param backgount    小點資源圖標
     * @param number       數量
     * @return 返回小點View集合
     */
    private List<View> addDots(final LinearLayout linearLayout, Drawable backgount, int number) {
        List<View> dots = new ArrayList<>();
        for (int i = 2; i < number; i++) {    // 注意這裏的 i 從 2 開始,只畫出5個點

            int dotId = addDot(linearLayout, backgount);
            dots.add(findViewById(dotId));

        }
        return dots;
    }


}

ic_dot_focused.xml:

<vector android:height="5dp" android:viewportHeight="24.0"
    android:viewportWidth="24.0" android:width="5dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#c8ffffff" android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"/>
</vector>

ic_dot_normal.xml:

<vector android:height="5dp" android:viewportHeight="24.0"
    android:viewportWidth="24.0" android:width="5dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#c8fd8888" android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"/>
</vector>

當然這裏主要是實現真正的無限輪播,其中對於 用戶手動滑動圖片時需要暫停輪播沒有做相關處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章