[Android]使用ViewPager實現圖片滑動展現

  在淘寶等電商的APP首頁常常能看到大幅的廣告位,一般有多幅常常更新的圖片用於展現促銷信息,以下圖所示:html

一般會自動滾動,也能夠根據手勢滑動。我沒有研究過人家的APP是經過什麼實現的,可能有第三方已經封裝好的控件能夠直接使用,也可能經過webview來實現,畢竟在網頁上也有不少相似的內容。若是有高手經驗豐富不妨指點一二。無論別人怎樣,今天我準備本身動手作一個,其實也不是特別複雜的。android

 

我主要使用的實現方法是Android自帶的ViewPager控件,這個控件主要用於實現屏幕水平切換,有自帶的動畫效果。Android官網上有使用教程:http://developer.android.com/training/animation/screen-slide.html,固然下文會有相一致的說明。web

 

而後就開始動手實現這個圖片滑動效果吧。網絡

1. 首先解釋一下ViewPager的使用過程,一般來講ViewPager能夠和Fragment結合起來用,每次ViewPager滑動,也就是展現一個新的Fragment。Fragment裏面就是咱們須要展示的內容。而這滑動的動畫就交給ViewPager來實現。因此第一步咱們須要設置好Fragment的內容,新建一個佈局文件,這裏只須要展現一張圖便可,固然能夠根據本身的須要進行改變:app

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

    <ImageView
        android:id="@+id/iv_main_pic"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:contentDescription="@string/main_image"
        android:scaleType="fitXY" />

</RelativeLayout>

 

2. 而後創建Fragment類。ide

import android.support.v4.app.Fragment;
......

public class PictureSlideFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        
        View v = inflater.inflate(R.layout.fragment_picture_slide, container, false);
        
        return v;
    }

}

3. 在Activity佈局文件的合適位置加入ViewPager控件。佈局

        <android.support.v4.view.ViewPager
            android:id="@+id/pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

 

4. 在Activity中獲得這個ViewPager而且爲其設置Adapter:動畫

private ViewPager mPager;

@Override
protected void onCreate(Bundle savedInstanceState) {   super.onCreate(savedInstanceState);   setContentView(R.layout.activity_main);   mPager = (ViewPager) findViewById(R.id.pager);   mPagerAdapter = new PictureSlidePagerAdapter(getSupportFragmentManager());   mPager.setAdapter(mPagerAdapter); }

 

5. 這個Adapter繼承自FragmentStatePagerAdapter,其中getCount()返回的值是一共須要顯示的內容數,是個常數:spa

    private class PictureSlidePagerAdapter extends FragmentStatePagerAdapter {

        public PictureSlidePagerAdapter(FragmentManager fm) {
            super(fm);
            // TODO Auto-generated constructor stub
        }

        @Override
        public Fragment getItem(int arg0) {
            // TODO Auto-generated method stub
            return new PictureSlideFragment();
        }

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

 

6. 到目前爲止全部的內容都和官方的教程一致。若是你在Fragment中的那個ImageView經過android:src屬性設置圖片,會實現數張靜態圖片滑動的效果。這離咱們的目標還有一些區別:線程

(1)圖片須要可以動態改變,而不是固定的內容;

(2)每張圖片須要有點擊的響應;

(3)通常狀況下須要實現循環滾動,即滑到最後一張圖時繼續滑動會回到第一張圖;

(4)圖片要可以自動滾動;

(5)圖片下方須要有顯示第幾張圖的指示(小圓點)。

 

7. 接下來咱們朝着目標繼續努力。首先是圖片的變化。觀察上述Adapter的實現方法,能夠發現getItem()方法每次返回的都是一個Fragment的實例,須要顯示多少個Fragment這個方法就會執行多少遍。但咱們發現每次建立新的Fragment都沒有區別,直接new一個了事,所以咱們須要改寫這個建立新Fragment實例的方法,以實現每次新建的Fragment實例都不同。在咱們的Fragment類中補充以下內容:

    private int mIndex;
    
    public static PictureSlideFragment newInstance(int index) {
        PictureSlideFragment f = new PictureSlideFragment();
        
        Bundle args = new Bundle();
        args.putInt("index", index);
        f.setArguments(args);
        
        return f;
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        mIndex = getArguments() != null ? getArguments().getInt("index") : 1;

    }

這個叫作newInstance的方法主要功能也是建立一個Fragment實例,和直接new的區別是傳遞進來一個index參數,這個參數在onCreate()方法中被得到。而後咱們將Adapter的getItem()改寫爲以下:

        @Override
        public Fragment getItem(int arg0) {
            // TODO Auto-generated method stub
            return PictureSlideFragment.newInstance(arg0);
        }

每次getItem都將Item的序號傳遞到新建的Fragment,而後再Fragment中根據須要設定不一樣的內容。真正實現的時候,能夠在Fragment中加入從網絡獲取圖片的操做。

 

8. 圖片的點擊響應。這個比較簡單,在Fragment中得到ImageView控件,而後設置onClick監聽器便可。就不給出代碼了。

9. 圖片的循環滾動。通常的ViewPager不能實現內容的循環滾動,即第一張向左滑或者最後一張向右滑都會到頂,顯示到頂的效果。若是要從ViewPager自身入手加入這功能須要對這個控件進行改寫,比較麻煩,這裏我從stackoverflow上找到了一種比較聰明的辦法。

  要實現幾張圖的循環滾動,其實只須要知足視覺效果就能夠了。好比有三張圖A,B,C,要實現A->B->C->A->B......以及C->B->A->C->B...這樣的循環,實際上能夠這樣實現:

  提供5張圖,分別是C'  A  B  C  A',其中C'和C,A'和A徹底相同,當滑到C'時,自動切換到C,當滑到A'時,自動切換到A,而且這個切換過程沒有動畫,因而,使用者體驗出來的感受就是A B C三張圖在循環滾動了。

  因而咱們爲ViewPager添加setOnPageChangeListener方法:

        mPager.setOnPageChangeListener(new OnPageChangeListener() {
            
            @Override
            public void onPageSelected(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 onPageScrollStateChanged(int state) {
                // 當到第一張時切換到倒數第二張,當到最後一張時切換到第二張
                 if (state == ViewPager.SCROLL_STATE_IDLE) {
                     int curr = mPager.getCurrentItem();
                     int lastReal = mPager.getAdapter().getCount() - 2;
                     if (curr == 0) {
                         mPager.setCurrentItem(lastReal, false);
                     } else if (curr > lastReal) {
                         mPager.setCurrentItem(1, false);
                     }
                 }
            }
        });

覆寫的onPageScrollStateChanged方法在滑動內容改變時調用,在其中實現C'和C,A'和A的切換。

 

10. 圖片的自動滾動,這裏我使用了timer啓動線程來實現,定時器線程每隔5秒發送消息,UI線程捕獲消息並調用ViewPager.setCurrentItem(currentItem+1, true)方法,滾動到下一張圖片。代碼就不贅述了。這裏有個體驗細節,就是當使用者用手指滑動時,定時器須要取消,防止自動滑動和手指滑動發生衝突。這個我在Fragment的ImageView的onTouchListener中實現:

        mMainImage.setOnTouchListener(new OnTouchListener() {
            
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    ((MainActivity)getActivity()).getTimer().cancel();
                } else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
                    ((MainActivity)getActivity()).startSwitchImage();
                }

                return false;
            }
        });

 

 11. 圖片序號的指示,也就是圖片下方的幾個小圓點,這個實現比較簡單,首先在Activity的佈局文件中添加幾個圖片,由於這幾個小圓點自己不能隨ViewPager移動,所以不能放在Fragment佈局中。切換內容也就是切換顯示不一樣顏色小圓點的位置,這個方法一樣能夠在onPageScrollStateChanged方法中調用。注意一些細節,由於以前爲了實現循環滾動而多用了兩個Fragment,而顯示的小圓點數量不能增長,所以須要調整好對應的序號。代碼也再也不贅述了。

 

  最終的效果以下圖所示,美食有木有。總結一下,整個過程並不複雜,就是一些細節須要仔細推敲。雖然作法可能有非主流的地方,但實現的效果跟別人的幾乎徹底一致,這樣就行啦~

  另外,這樣的實現方法也不是徹底沒有值得改進的地方,好比圖片自動滾動的延時還不能自定義。ViewPager沒有現成的方法用來自改變自動滾動延時,若是須要自定義,就要本身改寫這個控件啦,有興趣的能夠研究一下~

相關文章
相關標籤/搜索