天天看點

ViewPager實作無限循環切換和手勢滑動效果

在上一次的代碼中加入了無限循環的功能,這一次我詳細講解一下我的邏輯。

1.實作添加imageview 進入viewpager

   a.首先寫一個CusViewpage繼承自ViewPager 

public class CusViewpage extends ViewPager{
	public CusViewpage(Context context, AttributeSet attrs) {
		super(context, attrs);
	}
}
           

  b.定義變量 List<ImageView> viewPagerImage和展示小點的LinearLayout

private List<ImageView> viewPagerImage;
        private LinearLayout dotslayout;
           

  c.自定義OnPageChangListener,和PagerAdapter,傳說ViewPager如果不傳入這個兩個東西就會報錯,我也沒試過額,有興趣的大蝦們試試後告訴我一聲哈,

/**
	  * 
	  * @author 任愛民
	  * 自定義的OnPageChangeListener
	  */
	public class ImagePagerChangeListener implements OnPageChangeListener {

		/**
		 * 1是手指滑動
		 * 2是結束滑動
		 * 0是開始滑動
		 */
		public void onPageScrollStateChanged(int n) {

		}

		public void onPageScrolled(int arg0, float arg1, int arg2) {
			// TODO Auto-generated method stub
		}

		public void onPageSelected(int position) {
		}

	}

	/**
	 * 
	 * @author 任愛民
	 * 自定義的PagerAdapter
	 */
	public class ImagePagerAdapter extends PagerAdapter {

		private List<ImageView> list;

		public ImagePagerAdapter(List<ImageView> list) {
			this.list = list;
		}

		@Override
		public void destroyItem(View view, int index, Object arg2) {
			((ViewPager) view).removeView(list.get(index));
		}

		@Override
		public void finishUpdate(View arg0) {
			// TODO Auto-generated method stub
		}

		@Override
		public int getCount() {
			// TODO Auto-generated method stub
			return list.size();
		}

		@Override
		public Object instantiateItem(View view, int index) {
			((ViewPager) view).addView(list.get(index), 0);
			return list.get(index);
		}

		@Override
		public boolean isViewFromObject(View view, Object object) {
			// TODO Auto-generated method stub
			return view == (object);
		}

		@Override
		public void restoreState(Parcelable arg0, ClassLoader arg1) {
			// TODO Auto-generated method stub
		}

		@Override
		public Parcelable saveState() {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public void startUpdate(View arg0) {
			// TODO Auto-generated method stub
		}

	}
 
           

 d,init()方法初始化資料

public void init(List<ImageView> viewPagerImage,LinearLayout dotslayout){
		this.viewPagerImage = viewPagerImage;
		this.dotslayout = dotslayout;
		initImagePager();
		if(dotslayout != null)
		initDots();
	}
    /**
     * 初始化viewPage
     */
    private void initImagePager() {
        if(viewPagerImage != null){
            this.setImageStyle();
            this.setAdapter(new ImagePagerAdapter(viewPagerImage));
            this.setOnPageChangeListener(new ImagePagerChangeListener());
        }
    }
    /**
     * 設定圖檔的一些風格
     */
    public void setImageStyle(){
        android.widget.FrameLayout.LayoutParams viewparams = new android.widget.FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        for(ImageView imagaview:viewPagerImage){
            imagaview.setLayoutParams(viewparams);
            //允許拉伸,填充螢幕
            imagaview.setScaleType(ScaleType.FIT_XY); 
        }
    }

    /**
     * 添加小點
     */
    // 首頁面切換的小點資源id
    private int[] imagedotsid = { R.drawable.dotwhite, R.drawable.dotorange };
    private void initDots() {
        //在這裡為什麼dots[]的長度要減2,後面我會詳細說明。
        dots = new ImageView[viewPagerImage.size() - 2];
        for (int i = 0; i < dots.length; i++) {
            dots[i] = new ImageView(getContext());
            dots[i].setLayoutParams(new android.widget.FrameLayout.LayoutParams(15, 15));
            if (i == 0)
                dots[i].setImageResource(imagedotsid[1]);
            else
                dots[i].setImageResource(imagedotsid[0]);
            TextView tv = new TextView(getContext());
            tv.setLayoutParams(new android.widget.FrameLayout.LayoutParams(10, 30));
            dotslayout.addView(dots[i]);
            dotslayout.addView(tv);
        }

    }
    
           

現在已經可以顯示出PagerView了,後面我們添加圖檔的自動循環切換

2.現在我們實作圖檔的手動循環切換,并且添加點的改變

     先說一下無限循環的簡單邏輯, 先看圖,看顔色。

ViewPager實作無限循環切換和手勢滑動效果

           如圖所示,如果我要無限循環四張圖檔,那麼我需要添加6張圖檔進去,第一張是要顯示的第四張圖檔,最後一張是需要展示的第一張圖檔,初始化時實際是顯示的第二張圖檔,這樣我們才可以向前滑動到前一張即第四張圖檔,當滑動到此圖時且動作完畢時,立即切換到最後一張的前一張圖檔,位置是list.size()-2。前後一直滑動的道理也是一樣的。

          其實這就是一個簡單的循環邏輯,為了保留滑動動作,才加入了最前後兩張圖檔循環。

          是以我們需要傳入多的兩張圖檔,之前設定點的數量才是list.size() - 2;

          是以在初始化init()方法中時,我們需要将圖檔的顯示位置設為1

setCurrentItem(1, false);
           

在自定義的切換事件中,我們加入上面的邏輯代碼

public class ImagePagerChangeListener implements OnPageChangeListener {

        /**
         * 1是手指滑動
         * 2是結束滑動
         * 0是開始滑動
         */
        public void onPageScrollStateChanged(int n) {
          //這裡是加入的代碼
              if(n == 0){
                  if(dotint == 0){
                      setCurrentItem(viewPagerImage.size()-2, false);
                  }else if(dotint == viewPagerImage.size()-1){
                      setCurrentItem(1, false);
                  }
              }
        }
           

 a,實作改變的點的方法。

/**
	 * 改變小點
	 */
    // 記錄現在的原點位置
    private int dotint = 0;
    //記錄原點應該顯示的位置
    private int dotprint = 0 ;
    // 圖檔的位置
    private static int imagemoveid = 1;
    private void changedot(int dotintnew) {
        if(dots != null){
			dots[dotprint].setImageResource(imagedotsid[0]);
			if(dotintnew == 0){
				dotprint = viewPagerImage.size() - 3;
			}else if(dotintnew == viewPagerImage.size() - 1){
				dotprint = 0;
			}else{
				dotprint = dotintnew - 1;
			}
			dots[dotprint].setImageResource(imagedotsid[1]);
			imagemoveid = dotintnew;
			dotint = dotintnew;
        }
	}
           

   b.在切換圖檔時,會響應OnPageChangeListener事件,是以我們在自定義的OnPageChangeListener中加入改變小點的方法

public void onPageSelected(int position) {
			// 改變小點
			if(dotslayout != null)
			changedot(position);
		}
           

現在我們已經實作了手動無線循環切換的pagerview,

3.實作自動無限切換圖檔

這裡我先說明一個問題,我在實作這個功能的時候,開始是用的定時器Timer,過0.4秒就滑動一次。實作以後,在配合手動切換時,會出現,手動滑動一張圖檔後,立馬就會自動切換到下一張圖,這樣的體驗不是很好。後面我又改為線程去解決這個問題,每次手滑以後就重設線程,并設定0.1秒檢測一次時候是否正在滑動.

a.建立滑動的線程

/**
     * 自動切換 建立線程
     */
    public boolean isMove = true;
    private Handler switcherHandler;
    //自動切換的時間
    private int timelong = 40;
    //消息int
    private int message = 0x123;
    //給線程唯一性加鎖
    public static boolean isHaveLoop = true;
    private void startLoop() {
        new Thread() {
            public void run() {
                //表示已經有Loop開始運作
                isHaveLoop = true;
                try {// 如果移動了則休眠四秒鐘
                    //将檢測ismove提高到0.1秒檢測一次
                    int time = 0;
                    while (isMove) {
                        Thread.sleep(100);
                        if(time++ >= timelong){
                            switcherHandler.sendEmptyMessage(message);
                            time = 0;
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //表示Loop運作結束
                isHaveLoop = false;
            };
        }.start();

    }
	
           

b.在init()初始化時,啟動線程,并且在主線程中改變PagerView的位置

/**
	 * 設定廣告圖檔切換的計時器
	 */

	private void setSwitcherImage() {
		switcherHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				if (msg.what == message && isMove) {
					int m = ++imagemoveid % (viewPagerImage.size());
					setCurrentItem(m);
				}
				super.handleMessage(msg);
			}
		};
		startLoop();
	}
           

在init()中執行這個方法。

setSwitcherImage();
           

c.重寫onTouch()方法,檢測觸控事件,每次手動滑動時,都應該重開線程。

/**
	 * 檢測是否手勢滑動
	 * 如果有收手勢滑動則取消Loop線程,滑動結束後重建立立Loop線程
	 */
	 @Override
	public boolean onTouchEvent(MotionEvent arg0) {
		if(arg0.getAction() == MotionEvent.ACTION_DOWN||arg0.getAction()==arg0.ACTION_MOVE){
			isMove = false;
		}else if(arg0.getAction() == MotionEvent.ACTION_UP){
			isMove =true;
			//如果不存在loop後,可以再次建立loop
			if(!isHaveLoop){
			   startLoop();
			}
		}else{
			isMove = true;
			if(!isHaveLoop){
			  startLoop();
			}
		}
		return super.onTouchEvent(arg0);
	}
           

4.測試。

 我們放入布局檔案

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <aimin.myviewpager.CusViewpage
        android:id="@+id/cusviewpage"
        android:layout_width="match_parent"    
        android:layout_height="300dp" >
    </aimin.myviewpager.CusViewpage>

    <LinearLayout
        android:id="@+id/dots"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="280dp"
        android:layout_marginRight="30dp"
        android:gravity="right"
        android:orientation="horizontal" >
    </LinearLayout>

</RelativeLayout>
           

在主activity中初始化

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

import aimin.myviewpager.CusViewpage;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class MainActivity extends Activity {

	private CusViewpage imageSwitchertitle;
	private LinearLayout dotLayout;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		imageSwitchertitle = (CusViewpage) findViewById(R.id.cusviewpage);
		dotLayout = (LinearLayout) findViewById(R.id.dots);
		
		imageSwitchertitle.init(getTestImageView(),dotLayout);
	}
	/**
	 * 
	 * @return測試用的List<ImageView>
	 */
	public List<ImageView> getTestImageView(){
		List<ImageView> imageview = new ArrayList<ImageView>();
		
		ImageView imageviewfourq = new ImageView(this);
		imageviewfourq.setImageResource(R.drawable.title_four);
		
		ImageView imageviewone = new ImageView(this);
		imageviewone.setImageResource(R.drawable.title_one);

		ImageView imageviewtwo = new ImageView(this);
		imageviewtwo.setImageResource(R.drawable.title_two);
		
		ImageView imageviewthree = new ImageView(this);
		imageviewthree.setImageResource(R.drawable.title_three);
		
		ImageView imageviewfour = new ImageView(this);
		imageviewfour.setImageResource(R.drawable.title_four);
		
		ImageView imageviewoneh = new ImageView(this);
		imageviewoneh.setImageResource(R.drawable.title_one);
		
		imageview.add(imageviewfourq);
		imageview.add(imageviewone);
		imageview.add(imageviewtwo);
		imageview.add(imageviewthree);
		imageview.add(imageviewfour);
		imageview.add(imageviewoneh);
		return imageview;
	}
	/**
	 * 初始化CusViewpage
	 */

}
           

運作截圖:

ViewPager實作無限循環切換和手勢滑動效果

缺陷:

1.但是依然有不足之處,init方法初始化List<ImageView> viewPagerImage時,需要傳入一定順序的Imageview(即在最前和最後加入最後和最前的脫)。但這并不是我們想要的,我嘗試過在init()中,将List<ImageView> viewPagerImage添加上首尾圖檔,但隻能添加引用,在VIewpager換圖時報錯,ImageView又不能被複制對象(其實也可以做到複制,需要重寫ImagerVIew的copy()方法吧,我覺得太麻煩了,有興趣的同學可以試試),我隻好在傳入時先構造了一定順序的list。

2.不能動态添加圖檔.