在上一次的代碼中加入了無限循環的功能,這一次我詳細講解一下我的邏輯。
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.現在我們實作圖檔的手動循環切換,并且添加點的改變
先說一下無限循環的簡單邏輯, 先看圖,看顔色。
如圖所示,如果我要無限循環四張圖檔,那麼我需要添加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
*/
}
運作截圖:
缺陷:
1.但是依然有不足之處,init方法初始化List<ImageView> viewPagerImage時,需要傳入一定順序的Imageview(即在最前和最後加入最後和最前的脫)。但這并不是我們想要的,我嘗試過在init()中,将List<ImageView> viewPagerImage添加上首尾圖檔,但隻能添加引用,在VIewpager換圖時報錯,ImageView又不能被複制對象(其實也可以做到複制,需要重寫ImagerVIew的copy()方法吧,我覺得太麻煩了,有興趣的同學可以試試),我隻好在傳入時先構造了一定順序的list。
2.不能動态添加圖檔.