1. 程式人生 > >Android中啟動頁ViewPager和ViewFlipper帶指示器

Android中啟動頁ViewPager和ViewFlipper帶指示器

首先我們來分析一下,想要實現啟動頁的功能,大家第一個想到的就是使用ViewPager,使用ViewPager確實是一種比較好的方式,而且思路也是比較清晰的。今天我們就一起來學習一下,使用ViewPager和ViewFlipper實現啟動頁帶小點功能。
先展示一下圖片,看看是不是你想要的效果。
這裡寫圖片描述
這裡寫圖片描述

1、ViewPager和ViewFlipper的區別

ViewFlipper繼承ViewAnimator,切換view的時候是有動畫效果的,適合做ppt,多介面的程式歡迎引導介面,算是個輕量級的元件,適合展示靜態資料,少量資料。

ViewPager繼承ViewGroup。看官網描述,這貨和Fragment是好搭檔,Fragment有自己的生命週期。也就是說ViewPager更適用複雜的檢視切換,而且Viewpager有自己的adapter,這也讓其適應複雜物件,實現資料的動態載入。

2、使用ViewPager來展示mipmap中或者網路中的圖片(Volley)

首先,我們來理一下有幾個注意點。
①先在佈局檔案中,畫出簡單的佈局。
②滑動ViewPager時候,底部的小點也會跟著變化。
③點選小點時,ViewPager也會變化。
好了,現在我們來開始寫程式碼,程式碼中的註釋比較詳細,大家自己看。
1、佈局檔案中,畫出佈局。
layout中,activity_view_pager_demo.xml檔案

<?xml version="1.0" encoding="utf-8"?>
<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" tools:context="com.llay.admin.mydemo.ViewPagerDemoActivity">
<android.support.v4.view.ViewPager android:id
="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent">
</android.support.v4.view.ViewPager> <LinearLayout android:id="@+id/ll" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="20dp" android:orientation="horizontal"> <ImageView android:id="@+id/iv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_margin="5dp" android:background="@drawable/point_selector" android:clickable="true" android:padding="5dp" /> <ImageView android:id="@+id/iv2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_margin="5dp" android:background="@drawable/point_selector" android:clickable="true" android:padding="5dp" /> <ImageView android:id="@+id/iv3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_margin="5dp" android:background="@drawable/point_selector" android:clickable="true" android:padding="5dp" /> <ImageView android:id="@+id/iv4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_margin="5dp" android:background="@drawable/point_selector" android:clickable="true" android:padding="5dp" /> </LinearLayout> </RelativeLayout>

解釋:程式碼中使用相對佈局,這樣,下面的指示器就可以顯示在ViewPager上面,這樣便於效果的實現。我這裡下面的指示器是固定寫的,根據圖片的多少進行新增和刪除。
最後一個layout檔案單獨寫的:
activity_view_pager4.xm

public class ViewPagerDemoActivity extends Activity implements ViewPager.OnPageChangeListener, View.OnClickListener {
    //設定ViewPager和view檢視
    private ViewPager viewPager;
    private int[] imageId = {R.mipmap.launcher_b, R.mipmap.launcher_c, R.mipmap.launcher_b};
    private List<View> viewList;
    private List<ImageUrlBean> imageList;
    private View lastView;
    //設定小圓點
    private ImageView[] points;//存放小圓圈陣列
    private int currentIndex = 0;//當前頁面,預設首頁
    //使用Volley載入網路圖片
    private RequestQueue mQueue;
    private ImageLoader mImageLoader;
    ImageLoader.ImageListener imageListener;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_view_pager_demo);
        mQueue = Volley.newRequestQueue(this);
//        initViewPage();
        initNetView();
        initPoints();
    }

    //這裡是載入mipmap中圖片的方式,初始化ViewPager及其圖片資源
    private void initViewPage() {
        viewPager = (ViewPager) findViewById(R.id.view_pager);
        viewList = new ArrayList<>();
        //新增對應的view進入集合(資料來源)
        for (int i = 0; i < imageId.length; i++) {
            ImageView imageView = new ImageView(this);
            imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);//設定縮放樣式
            imageView.setImageResource(imageId[i]);
            viewList.add(imageView);
        }
        //另外增加最後一個能點選進入應用的檢視
        lastView = View.inflate(this, R.layout.activity_view_pager4, null);
        Button button = (Button) lastView.findViewById(R.id.startbutton);
        viewList.add(lastView);
        //設定最後一個檢視上的點選事件
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(ViewPagerDemoActivity.this, "應用開始!", Toast.LENGTH_SHORT).show();
            }
        });
        //設定viewpager的介面卡和資料來源
        ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(viewList);
        viewPager.setAdapter(viewPagerAdapter);
        viewPager.setOnPageChangeListener(this);
    }


//這裡是載入網路圖片的方式,初始化ViewPager控制元件及其圖片資源
    private void initNetView() {
        viewPager = (ViewPager) findViewById(R.id.view_pager);
        ImageUrlBean imageUrlBean1 = new ImageUrlBean("http://www.qq6300.com/uploads/allimg/130131/1-1301311G339A9.jpg");
        ImageUrlBean imageUrlBean2 = new ImageUrlBean("http://img4.duitang.com/uploads/item/201412/13/20141213114411_QEshv.jpeg");
        ImageUrlBean imageUrlBean3 = new ImageUrlBean("http://pic27.nipic.com/20130329/10041959_102531181000_2.jpg");
        imageList = new ArrayList<>();
        imageList.add(imageUrlBean1);
        imageList.add(imageUrlBean2);
        imageList.add(imageUrlBean3);
        //新增對應的view進入集合(資料來源)
        viewList = new ArrayList<>();
        for (int i = 0; i < imageList.size(); i++) {
            ImageView imageView = new ImageView(this);
            imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);//設定縮放樣式
            mImageLoader = new ImageLoader(mQueue, new ImageLoader.ImageCache() {
                @Override
                public Bitmap getBitmap(String s) {
                    return null;
                }

                @Override
                public void putBitmap(String s, Bitmap bitmap) {

                }
            });
            imageListener = ImageLoader.getImageListener(imageView, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
            mImageLoader.get(imageList.get(i).getImageUrl(), imageListener);
            viewList.add(imageView);
        }
        //另外增加最後一個能點選進入應用的檢視
        lastView = View.inflate(this, R.layout.activity_view_pager4, null);
        Button button = (Button) lastView.findViewById(R.id.startbutton);
        viewList.add(lastView);
        //設定最後一個檢視上的點選事件
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(ViewPagerDemoActivity.this, "應用開始!", Toast.LENGTH_SHORT).show();
            }
        });
        //設定viewpager的介面卡和資料來源
        ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(viewList);
        viewPager.setAdapter(viewPagerAdapter);
        viewPager.setOnPageChangeListener(this);
    }

    //初始化下標點
    private void initPoints() {
        LinearLayout linearLayout = (LinearLayout) findViewById(R.id.ll);
        points = new ImageView[4];
        //初始化佈局中的小圓點ImageView控制元件
        for (int i = 0; i < points.length; i++) {
            points[i] = (ImageView) linearLayout.getChildAt(i);//遍歷LinearLayout下的所有ImageView子節點
            points[i].setEnabled(true);//設定當前狀態為允許點選(可點,灰色)
            points[i].setOnClickListener(this);//設定點選監聽
            //額外設定一個識別符號,以便點選小圓點時跳轉對應頁面
            points[i].setTag(i);//識別符號與圓點順序一致
        }
        currentIndex = 0;
        points[currentIndex].setEnabled(false);//設定首頁為當前頁(不可點,黑色)
    }


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


    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        //當前頁卡被選擇時,position為當前頁數
        points[position].setEnabled(false);//不可點選
        points[currentIndex].setEnabled(true);//恢復之前頁面狀態
        currentIndex = position;
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }
}

解釋:這裡有幾個地方需要注意的,
1、這裡新增資料來源的方式,有兩種方式:mipmap檔案中和網路上的圖片地址,我想,大家使用啟動頁功能的時候,一定是想要動態的從網路上獲取吧,這樣才能夠獲得最新的資料。
2、使用載入網路圖片功能,作者使用的是Volley框架,別問我為啥選這個啊,因為其他還沒用過,哈哈。
3、好了,這裡我們遇到了文章開頭時遇到的問題,當滑動ViewPager時,指示器也要跟著滑動,這裡我們繼承ViewPager.OnPageChangeListener,實現一些常用的方法,程式碼中都有註釋,請自行檢視。
4、還有一個是點選指示器的時候,ViewPager也跟著一起滑動。這裡我們繼承View.OnClickListener方法,這個方法就是點選事件,viewPager.setCurrentItem((int) v.getTag());便可以跳轉到所點選的介面,然後指示器在跳到指定介面之後,也會有相應的顏色變化。

3、ViewPager的介面卡程式碼
ViewPagerAdapter.javpublic class ViewPagerAdapter extends PagerAdapter {
private List list;

public ViewPagerAdapter(List list) {
    this.list = list;
}


//獲取要滑動的控制元件的數量,在這裡我們以滑動的廣告欄為例,那麼這裡就應該是展示的廣告圖片的ImageView數量
@Override
public int getCount() {
    return list.size();
}

//來判斷顯示的是否是同一張圖片,這裡我們將兩個引數相比較返回即可
@Override
public boolean isViewFromObject(View view, Object object) {
    return view == object;//官方demo給出的建議寫法
}

//當要顯示的圖片可以進行快取的時候,會呼叫這個方法進行顯示圖片的初始化,我們將要顯示的ImageView加入到ViewGroup中,然後作為返回值返回即可
@Override
public Object instantiateItem(ViewGroup container, int position) {
    container.addView(list.get(position));
    return list.get(position);
}

//PagerAdapter只快取三張要顯示的圖片,如果滑動的圖片超出了快取的範圍,就會呼叫這個方法,將圖片銷燬
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView(list.get(position));
}

}示器的佈局。
現在,我們來實現一下指示器的圓點,之前我一直以為,指示器的圓點就是讓UI畫出來的,原來還可以通過這種方式來實現。直接上程式碼。
未點選的圓點。
drawable檔案中。v_point_up.xml檔案

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">

    <corners android:radius="0.5dp" />

    <solid android:color="#AAFFFFFF" />

</shape>

點選的圓點。
drawable檔案中。v_point_down.xml檔案

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">

    <corners android:radius="0.5dp" />

    <solid android:color="#55000000" />

</shape>

主佈局檔案中的point_selector.xml檔案,這個檔案的功能是在選擇指示器之後,可以讓指示器的顏色用程式碼改變。
drawbale檔案中。point_selector.xml檔案

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/v_point_up" android:state_enabled="true"></item>

    <item android:drawable="@drawable/v_point_down" android:state_enabled="false"></item>

</selector>

解釋:請注意這裡是android:state_enabled屬性,表示狀態是否可以點選。

2、使用ViewFlipper來展示mipmap中的圖片

這裡我沒有用ViewFlipper來展示網路圖片
1、佈局檔案:
同上ViewPager中的主佈局檔案和第四個佈局檔案,還有指示器的佈局檔案。
2、ViewFlipperActivity.java檔案

public class ViewFlipperActivity extends Activity implements GestureDetector.OnGestureListener, View.OnClickListener {
    //設定ViewFlipper和view檢視
    private ViewFlipper viewFlipper;
    private int[] imageId = {R.mipmap.launcher_b, R.mipmap.launcher_c, R.mipmap.launcher_b};
    View lastView;
    //設定小圓點
    private ImageView[] points;//存放小圓圈陣列
    private int currentIndex = 0;//當前頁面,預設首頁
    //設定手勢
    GestureDetector gestureDetector;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_view_flipper);
        gestureDetector = new GestureDetector(ViewFlipperActivity.this);
        initViewFlipper();
        initPoints();
    }

    //初始化ViewFlipper
    private void initViewFlipper() {
        viewFlipper = (ViewFlipper) findViewById(R.id.viewflipper);
        //新增對應的view進入集合(資料來源)
        for (int i = 0; i < imageId.length; i++) {
            ImageView imageView = new ImageView(this);
            imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);//設定縮放樣式
            imageView.setImageResource(imageId[i]);
            viewFlipper.addView(imageView);
        }
        //另外增加最後一個能點選進入應用的檢視
        lastView = View.inflate(this, R.layout.activity_view_pager4, null);
        Button button = (Button) lastView.findViewById(R.id.startbutton);
        viewFlipper.addView(lastView);
        //設定最後一個檢視上的點選事件
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(ViewFlipperActivity.this, "應用開始!", Toast.LENGTH_SHORT).show();
            }
        });
    }

    //初始化下標點
    private void initPoints() {
        LinearLayout linearLayout = (LinearLayout) findViewById(R.id.ll);
        points = new ImageView[4];
        //初始化佈局中的小圓點ImageView控制元件
        for (int i = 0; i < points.length; i++) {
            points[i] = (ImageView) linearLayout.getChildAt(i);//遍歷LinearLayout下的所有ImageView子節點
            points[i].setEnabled(true);//設定當前狀態為允許點選(可點,灰色)
            points[i].setOnClickListener(this);//設定點選監聽
            //額外設定一個識別符號,以便點選小圓點時跳轉對應頁面
            points[i].setTag(i);//識別符號與圓點順序一致
        }
        currentIndex = 0;
        points[currentIndex].setEnabled(false);//設定首頁為當前頁(不可點,黑色)
    }


    @Override
    public void onClick(View v) {
        //點選小點,改變小點的狀態,並且改變viewFlipper中子view的顯示
        viewFlipper.setDisplayedChild((int) v.getTag());
        points[(int) v.getTag()].setEnabled(false);
        points[currentIndex].setEnabled(true);
        currentIndex = (int) v.getTag();
    }


    //使用者輕觸觸控式螢幕,由1個MotionEvent ACTION_DOWN觸發
    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }

    //使用者輕觸觸控式螢幕,尚未鬆開或拖動,由一個1個MotionEvent ACTION_DOWN觸發
    //注意和onDown()的區別,強調的是沒有鬆開或者拖動的狀態
    @Override
    public void onShowPress(MotionEvent e) {

    }

    //使用者(輕觸觸控式螢幕後)鬆開,由一個1個MotionEvent ACTION_UP觸發
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    //使用者按下觸控式螢幕,並拖動,由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE觸發
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

    //使用者長按觸控式螢幕,由多個MotionEvent ACTION_DOWN觸發
    @Override
    public void onLongPress(MotionEvent e) {

    }

    //使用者按下觸控式螢幕、快速移動後鬆開,由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE,1個ACTION_UP觸發
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        if (e2.getX() - e1.getX() > 120) {
            //為了避免能夠一直向右滑動
            if (viewFlipper.getDisplayedChild() != 0) {
                //向右滑動,設定滑動動畫
                viewFlipper.setInAnimation(AnimationUtils.loadAnimation(ViewFlipperActivity.this,
                        R.anim.push_right_in));
                viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(ViewFlipperActivity.this,
                        R.anim.push_right_out));
                //這個要判斷,不然就會跳到第一個
                viewFlipper.showPrevious();
                //當前頁卡被選擇時,viewFlipper.getDisplayedChild()為當前頁數
                points[viewFlipper.getDisplayedChild()].setEnabled(false);//不可點選
                points[currentIndex].setEnabled(true);//恢復之前頁面狀態
                currentIndex = viewFlipper.getDisplayedChild();
                return true;
            }
        } else if (e2.getX() - e1.getX() < 120) {
            //為了避免能夠一直向左滑動
            if (viewFlipper.getDisplayedChild() != viewFlipper.getChildCount() - 1) {
                //向左滑動,設定滑動動畫
                viewFlipper.setInAnimation(AnimationUtils.loadAnimation(ViewFlipperActivity.this,
                        R.anim.push_left_in));
                viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(ViewFlipperActivity.this,
                        R.anim.push_left_out));
                //這個要判斷,不然就會跳到最後一個
                viewFlipper.showNext();
                //當前頁卡被選擇時,viewFlipper.getDisplayedChild()為當前頁數
                points[viewFlipper.getDisplayedChild()].setEnabled(false);//不可點選
                points[currentIndex].setEnabled(true);//恢復之前頁面狀態
                currentIndex = viewFlipper.getDisplayedChild();
                return true;
            }
        }
        return false;
    }


    //使用者輕觸觸控式螢幕,由1個MotionEvent ACTION_DOWN觸發
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return this.gestureDetector.onTouchEvent(event);
    }

}

解釋:這裡我用ViewFlipper實現這個啟動頁的功能,一開始以為應該會比ViewPager實現容易,但是自己後來弄了一下,感覺自己還是不怎麼能弄出來。我來講一下有幾處要注意的。
1、使用ViewFlipper來實現啟動頁功能,需要使用手勢。讓類繼承GestureDetector.OnGestureListener介面,實現一些必要的方法。主要是onFling()方法。
2、為了讓ViewFlipper不能一直的滑動下去。需要判斷是不是第一個和最後一個,使用 if (viewFlipper.getDisplayedChild() != 0)判斷是不是第一個,使用if (viewFlipper.getDisplayedChild() != viewFlipper.getChildCount() - 1)判斷是不是最後一個。
3、在滑動了ViewFlipper之後,我們也要考慮和ViewPager相同的兩個問題。ViewFlipper滑動帶動指示器,指示器點選帶動ViewFlpper。
使用

//當前頁卡被選擇時,viewFlipper.getDisplayedChild()為當前頁數
                points[viewFlipper.getDisplayedChild()].setEnabled(false);//不可點選
                points[currentIndex].setEnabled(true);//恢復之前頁面狀態
                currentIndex = viewFlipper.getDisplayedChild();

來使ViewFlipper滑動,帶動指示器的滑動。
使用

//點選小點,改變小點的狀態,並且改變viewFlipper中子view的顯示
        viewFlipper.setDisplayedChild((int) v.getTag());
        points[(int) v.getTag()].setEnabled(false);
        points[currentIndex].setEnabled(true);
        currentIndex = (int) v.getTag();

來點選指示器,帶動ViewFlipper的跳轉。

注意:可能是方法不同的原因,在ViewPager中,setCurrentItem(int item)方法就可以直接呼叫第幾個介面,然後再觸發onPageSelected(int position)方法,使得指示器按鈕變化。而在ViewFlipper中,setDisplayedChild(int childid)方法只能呼叫第幾個介面,不能觸發onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)方法,onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)方法只能通過滑動來獲得。

4、需要注意的是,使用手勢的時候,一定要實現這個方法,不然手勢不能生效。原因,查了好多,都是說未知。

//使用者輕觸觸控式螢幕,由1個MotionEvent ACTION_DOWN觸發
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return this.gestureDetector.onTouchEvent(event);
    }