1. 程式人生 > >android介面開發:ViewPager的詳解,並用於仿微博滑動例項和圖片滾動例項

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

1.ViewPager簡單使用

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

下面是一個簡單例子(佈局檔案):


    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height
="match_parent" android:layout_alignParentTop="true">
<android.support.v4.view.PagerTabStrip android:id="@+id/ptab" android:layout_width="wrap_content" android:gravity="center" android:layout_height="50dp" > </android.support.v4.view.PagerTabStrip
>
</android.support.v4.view.ViewPager>

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不一樣,進行滑動就行了。
佈局應該是這樣的。

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

    <LinearLayout 
        android:id="@+id/tile_ll"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:orientation="horizontal"
        android:background="@color/blue">

        <TextView 
            android:id="@+id/title1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:layout_gravity="center"
            android:gravity="center"
            android:text="標題1"/>
        <TextView 
            android:id="@+id/title2"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:layout_gravity="center"
            android:gravity="center"
            android:text="標題2"/>
        <TextView 
             android:id="@+id/title3"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:layout_gravity="center"
            android:gravity="center"
            android:text="標題3"/>
        <TextView 
            android:id="@+id/title4"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:layout_gravity="center"
            android:gravity="center"
            android:text="標題4"/>
    </LinearLayout>
    <ImageView

        android:id="@+id/cursor"
        android:layout_marginTop="33dp"
        android:layout_width="wrap_content" 
        android:layout_height="3dp" 
        android:src="@drawable/tile_line"/>
    <android.support.v4.view.ViewPager
        android:layout_below="@id/tile_ll"
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </android.support.v4.view.ViewPager>

</RelativeLayout>

我們使用了相對佈局,對標題使用線性佈局,而滑塊使用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

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
    android:useLevel="false"
    android:shape="oval">
    <solid android:color="#FFFFFF"/>
    <stroke android:width="1dp"
        android:color="@android:color/white"/>
    <size android:width="7dp"
        android:height="7dp"/>
</shape>

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

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
    android:useLevel="false"
    android:shape="oval">
    <solid android:color="#55FFFFFF"/>
    <stroke android:width="1dp"
        android:color="@android:color/white"/>
    <size android:width="7dp"
        android:height="7dp"/>
</shape>

小圓點selector
route_point.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:drawable="@drawable/route_point_draw" android:state_selected="true"/>
    <item android:drawable="@drawable/route_point_draw_b"/>

</selector>

2.佈局檔案

slide_view.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black" >
     <android.support.v4.view.ViewPager
        android:id="@+id/slipe_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    <LinearLayout android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:layout_alignParentBottom="true"
        android:gravity="center_horizontal"
        android:orientation="horizontal">
        <View android:id="@+id/t_1"
           android:layout_width="8dp"
        android:layout_height="8dp"
        android:background="@drawable/route_point" />
         <View android:id="@+id/t_2"
           android:layout_width="8dp"
        android:layout_height="8dp"
        android:layout_marginLeft="5dp"
        android:background="@drawable/route_point" />
          <View android:id="@+id/t_3"
           android:layout_width="8dp"
        android:layout_height="8dp"
        android:layout_marginLeft="5dp"
        android:background="@drawable/route_point" />
           <View android:id="@+id/t_4"
           android:layout_width="8dp"
        android:layout_height="8dp"
        android:layout_marginLeft="5dp"
        android:background="@drawable/route_point" />
    </LinearLayout>

</RelativeLayout>

這樣我們的介面就有了。
剩的就是自動輪播了。
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<View> 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<View>();
        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使用

   <com.yufem.view.SlideShowView
         android:layout_width="match_parent"
         android:layout_height="400dp"
          />

這裡的輪播時間,圖片數量,來源都寫死了,要想修改直接將原始碼修改即可。還有就是點選圖片跳轉的功能,只需給每個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);具體檢視原始碼。

2016/10/22 11:47:11

相關推薦

android介面開發ViewPager用於仿滑動例項圖片滾動例項

1.ViewPager簡單使用 ViewPager是android擴充套件包android.support.v4 裡的一個繼承與ViewGroup元件,通過佈局管理器可以實現左右滑動來顯示不同的View。而這個View由PagerAdapter產生,用法類似於

Dubbo(概念篇)Dubbo 架構演變及優缺點

架構演變 單一應用框架(ORM) 當網站流量很小時,只需一個應用,將所有功能如下單支付等都部署在一起,以減少部署節點和成本。 缺點:單一的系統架構,使得在開發過程中,佔用的資源越來越多,而且隨著流量的增加越來越難以維護。 垂直應用框架(MVC) 垂直應用架構解決了單一應用架

關於Android Service真正的完全你需要知道的一切

  Service全部內容基本會在本篇涉及到,我們將圍繞以下主要知識點進行分析: Service簡單概述 Service在清單檔案中的宣告 Service啟動服務實現方式及其詳解 Service繫結服務的三種實現方式 關於啟動服務與繫結服務間的轉換問題 前臺服

Android框架ButterKnife的使用butterknife8.x.x版本的使用方法

butterknife是由Android大神JakeWharton所開發,專案地址 https://github.com/JakeWharton/butterknife/1這裡說一下8.1.0版本的使用,這個版本和以前的老版本使用方法修改了一下,不過也是比較簡單的。 首先我

Android 註解開發 ButterKnife使用及教程

**俗話說:“不會偷懶的程式設計師不是好的程式設計師!”。作為一名Android開發,是不是經常厭煩了大量的findViewById以及setOnClickListener程式碼,而ButterKnife是一個專注於Android系統的View注入框架,讓你從此

關於Android Service真正的完全你需要知道的一切

  Service全部內容基本會在本篇涉及到,我們將圍繞以下主要知識點進行分析: Service簡單概述 Service在清單檔案中的宣告 Service啟動服務實現方式及其詳解 Service繫結服務的三種實現方式 關於啟動服務與繫結服務間的轉換問題

Android 介面回撥機制

       在使用介面回撥的時候發現了一個經常犯的錯誤,就是回撥函式裡面的實現有可能是用多執行緒或者是非同步任務去做的,這就會導致我們期望函式回撥完畢去返回一個主函式的結果,實際發現是行不通的,因為

Android 6.0 許可權申請以及許可權申請框架MPermissions的簡單使用

1.首先先來個框架地址:https://github.com/hongyangAndroid/MPermissions/2.真的很好用:1.in Activity:public class MainActivity extends AppCompatActivity {

Android 應用開發】BluetoothDevice

一. BluetoothDevice簡介1. 繼承關係public static Class BluetoothDevice extends Object implement Parcelable該類實

店鋪淘客無貨源模式流程解析做店鋪淘客模式需掌握的技巧

現在店鋪淘客是當下電商最火的運營模式,同樣都是做電商有的月入幾萬,有的月入一兩千,差距很明顯。主要還是運營的模式不對,路如果選對了方法相信你也是月入萬元戶。店鋪淘客門檻低、免費註冊,人人都可以開店。在10年那時有誰聽說誰誰誰有店鋪,給你的感覺就是高大上,經過這幾

信伺服器IP地址判斷該地址是否來自

如果公眾號基於訊息接收安全上的考慮,需要獲知微信伺服器的IP地址列表,以便識別出哪些訊息是微信官方推送給你的,哪些訊息可能是他人偽造的,可以通過該介面獲得微信伺服器IP地址列表。 介面呼叫請求說明 引數說明 引數 是否必須 說明 access_token 是 公

vue之better-scroll實現輪播圖頁面滾動

(該方法只針對移動端使用效果較好,PC端不推薦,使用的版本是[email protected],其他版本會出錯) 1.安裝better-scroll 在根目錄中package.json的dependencies中新增: "better-scr

Android中的介面回撥回撥機制以ActivityAdapter傳遞資料為例。

首先解決啥是回撥: 我覺得這個例子比較好:某天,我打電話向你請教問題,當然是個難題,你一時想不出解決方法,我又不能拿著電話在那裡傻等,於是我們約定:等你想出辦法後打手機通知我,這樣,我就掛掉電話辦其它事情去了。過了XX分鐘,我的手機響了,你興高采烈的說問題已經搞定,應該

Android ViewPager使用載入幾個簡單佈局案例+程式碼

MainActivity程式碼如下:package com.example.viewpage; import android.support.v4.view.ViewPager; import and

Android 樣式開發Drawable分類資源彙總(一)

Drawable Resources 解釋為:可繪製物件資源。是指可在螢幕上繪製的圖形,以及可以使用 getDrawable(int) 等 API 檢索或者應用到具有 android:drawable

android 開發 View _14 MotionEvent事件處理與實踐自定義滑動條View

MotionEvent MotionEvent物件是與使用者觸控相關的時間序列,該序列從使用者首次觸控式螢幕幕開始,經歷手指在螢幕表面的任何移動,直到手指離開螢幕時結束。手指的初次觸控(ACTION_DOWN操作),滑動(ACTION_MOVE操作)和擡起(ACTION

AndroidAndroid開發之常用的loading等待效果實現仿等待動畫。兩種實現方式

長期維護的Android專案,裡面包括常用功能實現,以及知識點詳解, 當然還有Java中的知識點。 具體請看github:https://github.com/QQ986945193/DavidAndroidProjectTools 首先大家都知道,當我

layer-listAndroid中layer-list使用

layout nbsp 分享 sel 效果圖 技術分享 ner select ati 使用layer-list可以將多個drawable按照順序層疊在一起顯示,默認情況下,所有的item中的drawable都會自動根據它附上view的大小而進行縮放, layer-list

android開發在Macbook環境android studio 配置git環境

第一步:對專案啟用git管理 這步是將專案納入git管理之下,點選android studio選單欄的VCS後,選擇Enable Version Control Integration. 在彈出的框裡選擇Git 然後可以發現在快捷工具圖示裡面多了兩個版本控制的按鈕,並且

如何安裝Nexus Repository Manager OSS 3.x如何搭建管理Maven私服win10、win7通用安裝錯誤解決方案。

        今天搭建一個Maven私服花了不少功夫,查閱了很多安裝的帖子以及百度了很多錯誤解決方案,然後將所有的帖子精華部分,附上我的經驗來帶給大家一個特別詳細的安裝方案,所以該文章大部分可以說是總結別人帖子。話不多說,開始安裝: 1.下載 &nb