手记

Android零基础入门第54节:视图切换组件ViewSwitcher

 前面三期学习了ProgressBar系列组件,那本期开始一起来学习ViewAnimator组件。

                                            

一、ViewAnimator组件概述

    ViewAnimator是一个基类,它继承了 FrameLayout,因此它表现出FrameLayout的特征,可以将多个View组件叠在一起。 ViewAnimator额外增加的功能正如它的名字所暗示的一样,ViewAnimator可以在View切换时表现出动画效果。

    ViewAnimator及其子类也是一组非常重要的UI组件,这种组件的主要功能是增加动画效果,从而使界面更加炫。使用ViewAnimator 时可以指定如下常见XML属性。

·         android:animateFirstView:设置ViewAnimator显示第一个View组件时是否使用动画。

·         android:inAnimation:设置ViewAnimator显示组件时所使用的动画。

·         android:outAnimation:设置ViewAnimator隐藏组件时所使用的动画。

    在实际项目中往往会使用ViewAnimator的几个子类。

二、ViewSwitcher使用

    ViewSwitcher代表了视图切换组件,它本身继承了 FrameLayout,因此可以将多个View 层叠在一起,每次只显示一个组件。当程序控制从一个View切换到另一个View时, ViewSwitcher支持指定动画效果。

    为了给ViewSwitcher添加多个组件,一般通过调用ViewSwitcher的setFactory (ViewSwitcherViewFactory)方法为之设置 ViewFactory,并由该 ViewFactory 为之创建 View 即可。 

    接下来通过一个简单的示例程序来学习ViewSwitcher的使用,主要是实现Android 5.0的Launcher界面的分屏、左右滚动效果。

    继续使用WidgetSample工程的advancedviewsample模块,在app/main/res/layout/目录下创建viewswitcher_layout.xml文件,在其中填充如下代码片段:

[代码]xml代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

<?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">

    <!-- 定义一个ViewSwitcher组件 -->

    <ViewSwitcher

        android:id="@+id/viewSwitcher"

        android:layout_width="match_parent"

        android:layout_height="match_parent" />

 

    <!-- 定义滚动到上一屏的按钮 -->

    <Button

        android:id="@+id/prev_btn"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentBottom="true"

        android:layout_alignParentLeft="true"

        android:text="&lt;" />

    <!-- 定义滚动到下一屏的按钮 -->

    <Button

        android:id="@+id/next_btn"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentBottom="true"

        android:layout_alignParentRight="true"

        android:text="&gt;" />

</RelativeLayout>

    上面的界面布局文件中只是定义了一个ViewSwitcher组件和两个按钮,这两个按钮分别用于控制该ViewSwitcher显示上一屏、下一屏的程序列表。

    Launcher界面由GridView完成,创建布局文件slide_gridview.xml,代码如下:

[代码]xml代码:

?

1

2

3

4

5

6

<?xml version="1.0" encoding="utf-8"?>

<GridView xmlns:android="http://schemas.android.com/apk/res/android"

          android:layout_width="match_parent"

          android:numColumns="4"

          android:layout_height="match_parent">

</GridView>

    创建GridView中每个Item的布局文件slide_gridview_item.xml,代码如下:

[代码]xml代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

<?xml version="1.0" encoding="utf-8"?>

<!-- 定义一个垂直的LinearLayout,该容器中放置一个ImageView和一个TextView -->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

              android:layout_width="match_parent"

              android:layout_height="match_parent"

              android:gravity="center"

              android:orientation="vertical"

              android:padding="10dp">

 

    <ImageView

        android:id="@+id/icon_img"

        android:layout_width="48dp"

        android:layout_height="48dp" />

 

    <TextView

        android:id="@+id/name_tv"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:gravity="center" />

</LinearLayout>

    为了方便操作,将GridView内使用的内容定义为实体类ViewSwitcherItemData,代码如下:

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

package com.jinyu.cqkxzsxy.android.advancedviewsample.entity;

 

/**

 * @创建者 鑫鱻

 * @描述 Android零基础入门到精通系列教程,欢迎关注微信公众号ShareExpert

 */

public class ViewSwitcherItemData   {

    private String name; // 应用程序名称

    private int icon;  // 应用程序图标

 

    public ViewSwitcherItemData(String name, int icon) {

        this.name   = name;

        this.icon   = icon;

    }

 

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name   = name;

    }

 

    public int getIcon() {

        return icon;

    }

 

    public void setIcon(int icon) {

        this.icon   = icon;

    }

}

    接下来创建GridView的适配器ViewSwitcherBaseAdapter,继承BaseAdapter类,代码如下:

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

package com.jinyu.cqkxzsxy.android.advancedviewsample.adapter;

 

import android.content.Context;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.ImageView;

import android.widget.TextView;

 

import com.jinyu.cqkxzsxy.android.advancedviewsample.R;

import com.jinyu.cqkxzsxy.android.advancedviewsample.ViewSwitcherActivity;

import com.jinyu.cqkxzsxy.android.advancedviewsample.entity.ViewSwitcherItemData;

 

import java.util.List;

 

/**

 * @创建者 鑫鱻

 * @描述 Android零基础入门到精通系列教程,欢迎关注微信公众号ShareExpert

 */

public class ViewSwitcherBaseAdapter   extends BaseAdapter   {

    private Context mContext = null;

    private List<viewswitcheritemdata>   mItemDatas = null;

 

    public ViewSwitcherBaseAdapter(Context context,   List<viewswitcheritemdata> itemDatas) {

        this.mContext   = context;

        this.mItemDatas   = itemDatas;

    }

 

    @Override

    public int getCount() {

        //   如果已经到了最后一屏,且应用程序的数量不能整除NUMBER_PER_SCREEN

        if (ViewSwitcherActivity.screenNo ==   ViewSwitcherActivity.screenCount - 1

                &&   mItemDatas.size() % ViewSwitcherActivity.NUMBER_PER_SCREEN != 0) {

            //   最后一屏显示的程序数为应用程序的数量对NUMBER_PER_SCREEN求余

            return mItemDatas.size() %   ViewSwitcherActivity.NUMBER_PER_SCREEN;

        }

        //   否则每屏显示的程序数量为NUMBER_PER_SCREEN

        return ViewSwitcherActivity.NUMBER_PER_SCREEN;

    }

 

    @Override

    public ViewSwitcherItemData getItem(int position) {

        //   根据screenNo计算第position个列表项的数据

        return mItemDatas.get(

                ViewSwitcherActivity.screenNo   * ViewSwitcherActivity.NUMBER_PER_SCREEN + position);

    }

 

    @Override

    public long getItemId(int position) {

        return position;

    }

 

    @Override

    public View getView(int position, View convertView, ViewGroup   parent) {

        ViewHolder   holder = null;

        if (null == convertView) {

            //   加载R.layout.item布局文件

            convertView   = LayoutInflater.from(mContext).inflate(R.layout.slide_gridview_item, null);

            holder   = new ViewHolder();

            holder.iconImg   = (ImageView)convertView.findViewById(R.id.icon_img);

            holder.nameTv   = (TextView)convertView.findViewById(R.id.name_tv);

            convertView.setTag(holder);

        }   else {

            holder   = (ViewHolder) convertView.getTag();

        }

 

        holder.iconImg.setImageResource(getItem(position).getIcon());

        holder.nameTv.setText(getItem(position).getName());

        return convertView;

    }

 

    private class ViewHolder{

        ImageView   iconImg;

        TextView   nameTv;

    }

}

</viewswitcheritemdata></viewswitcheritemdata>

    使用扩展BaseAdapter的方式为GridView提供Adapter,关键就是根据用户单击的按钮来动态计算该BaseAdapter应该显示哪些程序列表。

    使用Activity类的screenNo保存当前正在显示第几屏的程序列表,BaseAdapter会根据screenNo 动态计算该Adapter总共包含多少个列表项(如getCount()方法所示),会根据screenNo计算每个列表项的数据(如getltem(int position)方法所示)。

    新建ViewSwitcherActivity.java文件,加载上面新建的布局文件,具体代码如下:

[代码]java代码:

?

001

002

003

004

005

006

007

008

009

010

011

012

013

014

015

016

017

018

019

020

021

022

023

024

025

026

027

028

029

030

031

032

033

034

035

036

037

038

039

040

041

042

043

044

045

046

047

048

049

050

051

052

053

054

055

056

057

058

059

060

061

062

063

064

065

066

067

068

069

070

071

072

073

074

075

076

077

078

079

080

081

082

083

084

085

086

087

088

089

090

091

092

093

094

095

096

097

098

099

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

package com.jinyu.cqkxzsxy.android.advancedviewsample;

 

import android.os.Bundle;

import android.support.v7.app.AppCompatActivity;

import android.view.View;

import android.widget.Button;

import android.widget.GridView;

import android.widget.ViewSwitcher;

 

import com.jinyu.cqkxzsxy.android.advancedviewsample.adapter.ViewSwitcherBaseAdapter;

import com.jinyu.cqkxzsxy.android.advancedviewsample.entity.ViewSwitcherItemData;

 

import java.util.ArrayList;

import java.util.List;

 

/**

 * @创建者 鑫鱻

 * @描述 Android零基础入门到精通系列教程,欢迎关注微信公众号ShareExpert

 */

public class ViewSwitcherActivity   extends AppCompatActivity   implements View.OnClickListener   {

    // 定义一个常量,用于显示每屏显示的应用程序数

    public static final int NUMBER_PER_SCREEN = 12;

    // 记录当前正在显示第几屏的程序

    public static int screenNo   = -1;

    // 保存程序所占的总屏数

    public static int screenCount;

 

    private ViewSwitcher mViewSwitcher = null;

    private Button mPrevBtn = null;

    private Button mNextBtn = null;

    private ViewSwitcherBaseAdapter mAdapter = null;

    // 保存系统所有应用程序的List集合

    private List<viewswitcheritemdata>   mItemDatas = new ArrayList<viewswitcheritemdata>();

 

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.viewswitcher_layout);

 

        //   获取界面组件

        mViewSwitcher   = (ViewSwitcher) findViewById(R.id.viewSwitcher);

        mPrevBtn   = (Button) findViewById(R.id.prev_btn);

        mNextBtn   = (Button) findViewById(R.id.next_btn);

 

        mViewSwitcher.setFactory(new ViewSwitcher.ViewFactory() {

            //   实际上就是返回一个GridView组件

            @Override

            public View makeView() {

                //   加载R.layout.slide_gridview组件,实际上就是一个GridView组件

                return ViewSwitcherActivity.this.getLayoutInflater()

                        .inflate(R.layout.slide_gridview,   null);

            }

        });

 

        //   创建一个包含40个元素的List集合,用于模拟包含40个应用程序

        for (int i = 0; i < 40; i++) {

            ViewSwitcherItemData   item =

                    new ViewSwitcherItemData("item" + i, R.mipmap.ic_launcher);

            mItemDatas.add(item);

        }

 

        //   计算应用程序所占的总屏数

        //   如果应用程序的数量能整除NUMBER_PER_SCREEN,除法的结果就是总屏数

        //   如果不能整除,总屏数应该是除法的结果再加1

        screenCount   = mItemDatas.size() % NUMBER_PER_SCREEN == 0 ?

                mItemDatas.size()   / NUMBER_PER_SCREEN :

                mItemDatas.size()   / NUMBER_PER_SCREEN + 1;

 

        mAdapter   = new ViewSwitcherBaseAdapter(this,   mItemDatas);

 

        mPrevBtn.setOnClickListener(this);

        mNextBtn.setOnClickListener(this);

 

        //   页面加载时先显示第一屏

        next();

    }

 

    @Override

    public void onClick(View view) {

        switch (view.getId()){

            case R.id.prev_btn:

                prev();

                break;

            case R.id.next_btn:

                next();

                break;

            default:

                break;

        }

    }

 

    private void next() {

        if (screenNo < screenCount - 1) {

            screenNo++;

            //   为ViewSwitcher的组件显示过程设置动画

            mViewSwitcher.setInAnimation(this,   R.anim.slide_in_right);

            //   为ViewSwitcher的组件隐藏过程设置动画

            mViewSwitcher.setOutAnimation(this,   R.anim.slide_out_left);

            //   控制下一屏将要显示的GridView对应的Adapter

            ((GridView)   mViewSwitcher.getNextView()).setAdapter(mAdapter);

            //   单击右边按钮,显示下一屏

            //   学习手势检测后,也可通过手势检测实现显示下一屏

            mViewSwitcher.showNext();

        }

    }

 

    private void prev() {

        if (screenNo > 0) {

            screenNo--;

            //   为ViewSwitcher的组件显示过程设置动画

            mViewSwitcher.setInAnimation(this,   android.R.anim.slide_in_left);

            //   为ViewSwitcher的组件隐藏过程设置动画

            mViewSwitcher.setOutAnimation(this,   android.R.anim.slide_out_right);

            //   控制下一屏将要显示的GridView对应的 Adapter

            ((GridView)   mViewSwitcher.getNextView()).setAdapter(mAdapter);

            //   单击左边按钮,显示上一屏,当然可以采用手势

            //   学习手势检测后,也可通过手势检测实现显示上一屏

            mViewSwitcher.showPrevious();

        }

    }

}

</viewswitcheritemdata></viewswitcheritemdata>

    重点在于为ViewSwitcher设置ViewFactory对象,并且当用户单击“<”和“>”两个按钮时控制ViewSwitcher显示“上一屏”和“下一屏”的应用程序。 

    当用户单击按钮时,程序的事件处理方法将会控制ViewSwitcher调用showNext() 方法显示下一屏的程序列表。而且此时screenNo被加1,因而Adapter将会动态计算下一屏的程序列表,再将该Adapter传给ViewSwitcher接下来要显示的GridView。

    运行程序,点击“<”和“>”两个按钮时可以看到界面切换效果。

    为了实现ViewSwitcher切换View时的动画效果,程序的事件处理方法中调用了 ViewSwitcher的setInAnimation()、setOutAnimation()方法来设置动画效果。本程序由于 Android系统只提供的两个slide_in_left、slide_out_right动画资源,需要自行提供slide_in_right、slide_out_left动画资源,详细会在Android高级部分进行讲解。

    其中R.anim.slide_in_right动画资源对应的代码如下:

[代码]xml代码:

?

1

2

3

4

5

6

7

8

9

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 设置从右边拖进来的动画

    android:duration指定动画持续时间  -->

    <translate

        android:fromXDelta="100%p"

        android:toXDelta="0"

        android:duration="@android:integer/config_mediumAnimTime" />

</set>

    R.anim.slide_out_left动画资源对应的代码如下:

[代码]xml代码:

?

1

2

3

4

5

6

7

8

9

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 设置从左边拖出去的动画

    android:duration指定动画持续时间 -->

    <translate

        android:fromXDelta="0"

        android:toXDelta="-100%p"

        android:duration="@android:integer/config_mediumAnimTime" />

</set>

    至此,关于ViewSwitcher视图切换组件学习完毕,如果还有不清楚的地方建议回头再多做练习。

    今天就先到这里,如果有问题欢迎留言一起探讨,也欢迎加入Android零基础入门技术讨论微信群,共同成长!

原文链接:http://www.apkbus.com/blog-205190-72597.html

0人推荐
随时随地看视频
慕课网APP