Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android界面開發:ViewPager的詳解,並用於仿微博滑動實例和圖片滾動實例

android界面開發:ViewPager的詳解,並用於仿微博滑動實例和圖片滾動實例

編輯:關於Android編程

1.ViewPager簡單使用

ViewPager是android擴展包android.support.v4 裡的一個繼承與ViewGroup組件,通過布局管理器可以實現左右滑動來顯示不同的View。而這個View由PagerAdapter產生,用法類似於ListView和listView的Adapter。

下面是一個簡單例子(布局文件):

    

        
        
    

PagerTabStrip是ViewPager切換的標題欄,不需要可以不寫。現在示例中暫時寫上看效果。
前面說了像listview一樣,我們還需要一個adapter。ok,那麼我們來看看PagerAdapter怎麼寫。

public class MyPagerAdapter extends PagerAdapter{


        private Context context;
        private int[] imgid = new int[]{
                R.drawable.h_1,
                R.drawable.h_2,
                R.drawable.h_3,
                R.drawable.h_4
            };

        public MyPagerAdapter(Context context) {
            this.context = context;
        }

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

        @Override
        public boolean isViewFromObject(View arg0, Object arg1) {
            // 判斷是否由對象產生頁面
            return arg0==arg1;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            //初始化postiton位置的界面
            ImageView imageView = new ImageView(context);
            imageView.setImageResource(imgid[position]);
            container.addView(imageView);
            return imageView;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            // 生命周期中的資源回收,系統消耗position時會調用
            container.removeView((View)object);

            Drawable draw = ((ImageView)object).getDrawable();
            if(draw!=null){
                //解除Drawable 對view 的引用
                draw.setCallback(null);
            }
        }
    }

可以看到我們只需要繼承與PagerAdapter並實現和重寫上面幾個必要的方法即可。代碼中有注釋,不一一解釋了。
activity中呢,很簡單,給ViewPager set一下我們的PagerAdapter就行了。

public class MainActivity extends Activity {

    private ViewPager viewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewPager = (ViewPager) findViewById(R.id.pager);
        viewPager.setAdapter(new MyPagerAdapter(this));
    }
}

來看看效果。
基本的demo

這樣滑動切換界面就實現了,裡面的ImageView可以替換成任何View.

2.PagerTabStrip使用

大家可以看到PagerTabStrip是一個黑色的條,跟隨滾動,這個可以去掉,也可以定義成我們想要的樣子。
首先我們可以直接在PagerAdapter中設置要顯示的標題,只要再重寫一個PagerAdapter的方法:

public CharSequence getPageTitle(int position) {
            // TODO Auto-generated method stub
            return titls[position];
        }

PagerTabStrip的樣式也是可以定義的,下面給出一些常用的方法,根據需要定義。

        //設置下劃線的顏色,有兩種方法,使用其中一種即可
        pagerTabStrip.setTabIndicatorColor(Color.RED);//拉姆紅
        pagerTabStrip.setTabIndicatorColorResource(R.color.blue);//雷姆藍(自定義的color資源)
        //設置背景顏色
        pagerTabStrip.setBackgroundColor(Color.CYAN);

ps:若出現初始加載時不顯示標簽文字,滑動後卻顯示。可以嘗試換android_support_v4包。(換成實例源碼中的可以,可能是某些版本的v4包有bug)

3.類似微博的頭部滑動效果

其實PagerTabStrip並沒什麼卵用,實際項目很少用到,因為它不符合中國的審美觀。我們看到的大多數app的標題欄都是全部顯示出來的。就像這樣。

動畫滾動

那麼這效果怎麼實現呢,這就需要自定義標題欄。

圖示

我的標題欄應該像這樣的,我們讓左邊的那塊東西隨著當前item不一樣,進行滑動就行了。
布局應該是這樣的。



    

        
        
        
        
    
    
    
    


我們使用了相對布局,對標題使用線性布局,而滑塊使用imageView蓋上上面。這比較簡單,下面就是滑塊的動畫實現了。

    /**
     * 滑塊動畫
     * @param fromIndex 當前標簽
     * @param toIndex 目標標簽
     */
    public void startAnimation(int fromIndex,int toIndex){
        int bitmapWidth = cursor.getWidth();
        int tileWidth = tvTile[0].getWidth();
        int offset = (tileWidth - bitmapWidth)/2;
        Animation animation = new TranslateAnimation(fromIndex*tileWidth+offset, toIndex*tileWidth+offset, 0,0);
        animation.setFillAfter(true);
        animation.setDuration(200);
        cursor.startAnimation(animation);/*
    }

上面是動畫的方法,具體計算位置的方法是:1.先計算出滑塊和標簽兩邊的offset.2.移動時就是index*tileWidth+offset 可以計算出目標位置。看圖理解:

圖示2

動畫完成了,那麼就需要監聽viewPager的itemchange事件了。
如下:

viewPager.setOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageSelected(int pos) {
                startAnimation(currentPage, pos);
                currentPage = pos;
            }

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

            }

            @Override
            public void onPageScrollStateChanged(int arg0) {
                // TODO Auto-generated method stub

            }
        });
    }

主要是實現了onPageSelected(int pos)方法。進行啟動動畫。
還差點什麼嗎?有,就是標題欄點擊時能切換頁面了。這是簡單,給每個標題view添加點擊監聽器即可。

    for (int i = 0; i < tvTile.length; i++) {
            tvTile[i].setTag(i);
            tvTile[i].setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    int item = (Integer) v.getTag();
                    viewPager.setCurrentItem(item);
                }
            });
        }

做到這裡其實還有一個bug,那就是初始狀態沒寫。我發現在oncreate,onresume等獲取控件的大小都是0的。因此初始化時,需要重寫如下方法才能正確獲取大小:

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);

        bitmapWidth = cursor.getWidth();
        tileWidth = tvTile[0].getWidth();
        offset = (tileWidth - bitmapWidth)/2;
        startAnimation(0, 0);
    }

自定義的標題導航欄就到此為止了。

4.viewpager應用:實現輪播圖片功能 ,寫成自定義view

實現原理和上面類似,只是相當於將標題換成了小圓點而已,再增加自動輪播。

1.畫小圓點(可不畫,用圖片代替)

在res文件夾下新建文件夾drawable.並新建如下文件
白色小圓點(可用圖片代替)
route_point_draw.xml



    
    
    

白色半透明小圓點(可用圖片代替)
route_point_draw_b.xml



    
    
    

小圓點selector
route_point.xml


    
    

2.布局文件

slide_view.xml



     
    
        
         
          
           
    

這樣我們的界面就有了。
剩的就是自動輪播了。
pagerAdapter的實現和上面一樣,這部分就不重復了。

3.輪播邏輯

ublic class SlideShowView extends FrameLayout implements OnPageChangeListener{

    private int SLIDE_PIC_NUM = 4;
    private long SLIDE_TIME = 500;

    private int[] pic_id;
    private List dotViews;

    private ViewPager viewPager;
    private int currentPager;
    private boolean isAutoPlay = false;
    private ScheduledExecutorService scheduledExe;
    private Handler hander = new Handler(){
        public void handleMessage(android.os.Message msg) {
            viewPager.setCurrentItem(currentPager);
        };
    };
    /**
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    public SlideShowView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
        initview(context);
        startPlay();
    }
    public SlideShowView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }
    public SlideShowView(Context context) {
        this(context,null);
    }

    /**
     * 4個點
     * @param reid
     */
    public void setImageIds(int ... reid){
        pic_id = reid;
        viewPager.invalidate();
    }
    private void init(){
        dotViews = new ArrayList();
        pic_id = new int[]{
                R.drawable.h_1,
                R.drawable.h_2,
                R.drawable.h_3,
                R.drawable.h_4
        };

    }
    private void initview(Context context){
        LayoutInflater.from(context).inflate(R.layout.slide_view,this,true);
        for (int i = 0; i < pic_id.length; i++) {
            /*ImageView view = new ImageView(context);
            view.setImageResource(pic_id[i]);
            images.add(view);*/
        }
        dotViews.add(findViewById(R.id.t_1));
        dotViews.add(findViewById(R.id.t_2));
        dotViews.add(findViewById(R.id.t_3));
        dotViews.add(findViewById(R.id.t_4));

        for (View dotview : dotViews) {
            dotview.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    switch (v.getId()) {
                    case R.id.t_1:
                        currentPager = 0;
                        break;
                    case R.id.t_2:
                        currentPager = 1;
                        break;
                    case R.id.t_3:
                        currentPager = 2;
                        break;
                    case R.id.t_4:
                        currentPager = 3;
                        break;
                    default:
                        break;
                    }
                    viewPager.setCurrentItem(currentPager);
                }
            });
        }

        viewPager = (ViewPager) findViewById(R.id.slipe_pager);
        viewPager.setAdapter(new MypagerAdapter());
        viewPager.setOnPageChangeListener(this);
    }


    @Override
    public void onPageScrolled(int position, float positionOffset,
            int positionOffsetPixels) {
        // TODO Auto-generated method stub

    }
    @Override
    public void onPageSelected(int position) {
        currentPager = position;
        for (int i = 0; i < dotViews.size(); i++) {
            if(position==i){
                dotViews.get(i).setSelected(true);
            }else{
                dotViews.get(i).setSelected(false);
            }
        }
    }
    @Override
    public void onPageScrollStateChanged(int state) {
        switch (state) {
        case ViewPager.SCROLL_STATE_DRAGGING://手勢滑動
            isAutoPlay = false;
            break;
        case ViewPager.SCROLL_STATE_SETTLING://界面切換
            isAutoPlay = true;
            break;
        case ViewPager.SCROLL_STATE_IDLE://切換結束
            //最後一張右滑動到第一張
            if(viewPager.getCurrentItem() == viewPager.getAdapter().getCount()-1 && !isAutoPlay){
                viewPager.setCurrentItem(0);
            }
            if(viewPager.getCurrentItem() == 0 && !isAutoPlay){
                viewPager.setCurrentItem(viewPager.getAdapter().getCount()-1);
            }
            break;
        default:
            break;
        }
    }
    public void startPlay(){
        scheduledExe = Executors.newSingleThreadScheduledExecutor();
        scheduledExe.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                // 輪播任務
                synchronized (SlideShowView.this) {
                    currentPager = (currentPager+1)%pic_id.length;
                    hander.obtainMessage().sendToTarget();
                }

            }
        }, 1, 4,TimeUnit.SECONDS);
    }
    public void stopPlay(){
        scheduledExe.shutdown();
    }
}

最終效果

圖片滾動

這裡的核心是使用了單一線程池循環發送handler信息,讓viewPager循環播放圖片。而小圓點的狀態變化是通過selected狀態實現,對於小圓點selector 的xml文件

4.自定義的SlideShowView使用

   

這裡的輪播時間,圖片數量,來源都寫死了,要想修改直接將源碼修改即可。還有就是點擊圖片跳轉的功能,只需給每個item加入點擊事件即可,仿照上面自定義標題實現的點擊。

附:跟隨的滑動

有些軟件滑動方式的有點不同,它的標題滑塊是跟隨著手指滑動而滑動的,就像下圖一樣。

跟隨的滑動

思路:
既然要跟隨頁面滑動而滑動,那麼就需要監聽滑動事件,並計算出相應的距離。頁面滑動一頁,而導航欄的標題滑動一小格。假設是4個標簽卡,那麼就是4:1。
下面來實現一下,大體和上面的標題滑動差不多,我們之間復制進行修改。把動畫部分去掉。

實現方法

            /*pos是當前頁面的標號,percent是當前頁面滑動的百分比,px是當前頁面滑動的像素*/
            @Override
            public void onPageScrolled(int pos, float percent, int px) {
                if(scrolling){
                    float w = pos*tileWidth+offset+percent*tileWidth;//計算滑塊的x坐標
                    cursor.setX(w);//設置滑塊的x坐標
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                // TODO Auto-generated method stub
                switch (state) {
                case ViewPager.SCROLL_STATE_DRAGGING://手勢滑動
                    scrolling = true;
                    break;
                case ViewPager.SCROLL_STATE_SETTLING://界面切換

                    break;
                case ViewPager.SCROLL_STATE_IDLE://切換結束
                    scrolling = false;
                    break;
                default:
                    break;
                }
            }

實現OnPageChangeListener中的onPageScrolled方法即可。
初始化就是cursor.setX(offset);具體查看源碼。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved