【android_温故知新】第 6 组 UI 组件:ViewAnimator 及其子类

来源:互联网 发布:中文域名转码查询 编辑:程序博客网 时间:2024/05/22 15:51

  • 概述
    • ViewAnimator 支持的常用 XML 属性
  • ViewSwitcher 的功能与用法
    • 实例仿 Android 系统 Launcher 界面
  • 图像切换器 ImageSwitcher 的功能与用法
    • 实例支持动画的图片浏览器
  • 文本切换器 TextSwitcher 的功能与用法
    • 实例TextSwitcher
  • ViewFlipper 的功能与用法
    • 实例自动播放的图片库

概述

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

ViewAnimator 支持的常用 XML 属性

XML 属性 说 明 android:animateFirstView 设置 ViewAnimator 显示第一个 View 组件时是否使用动画 android:inAnimation 设置 ViewAnimator 显示组件时使用的动画 android:outAnimation 设置 ViewAnimator 隐藏组件时使用的动画

ViewSwitcher 的功能与用法

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

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

实例:仿 Android 系统 Launcher 界面

<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/button_prev"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_alignParentLeft="true"        android:onClick="prev"        android:text="&lt;" />    <!-- 定义滚动到下一屏的按钮 -->    <Button        android:id="@+id/button_next"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_alignParentRight="true"        android:onClick="next"        android:text="&gt;" /></RelativeLayout>
public class MainActivity extends Activity {    // 定义一个常量,用于显示每屏显示的应用程序数    public static final int NUMBER_PER_SCREEN = 12;    // 代表应用程序的内部类,    public static class DataItem {        // 应用程序名称        public String dataName;        // 应用程序图标        public Drawable drawable;    }    // 保存系统所有应用程序的List集合    private ArrayList<DataItem> items = new ArrayList<DataItem>();    // 记录当前正在显示第几屏的程序    private int screenNo = -1;    // 保存程序所占的总屏数    private int screenCount;    ViewSwitcher switcher;    // 创建LayoutInflater对象    LayoutInflater inflater;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        inflater = LayoutInflater.from(MainActivity.this);        // 创建一个包含40个元素的List集合,用于模拟包含40个应用程序        for (int i = 0; i < 40; i++) {            String label = "" + i;            Drawable drawable = getResources().getDrawable(                    R.drawable.ic_launcher);            DataItem item = new DataItem();            item.dataName = label;            item.drawable = drawable;            items.add(item);        }        // 计算应用程序所占的总屏数        // 如果应用程序的数量能整除NUMBER_PER_SCREEN,除法的结果就是总屏数        // 如果不能整除,总屏数应该是除法的结果再加1        screenCount = items.size() % NUMBER_PER_SCREEN == 0 ?                items.size() / NUMBER_PER_SCREEN :                items.size() / NUMBER_PER_SCREEN + 1;        switcher = (ViewSwitcher) findViewById(R.id.viewSwitcher);        switcher.setFactory(new ViewSwitcher.ViewFactory() {            // 实际上就是返回一个GridView组件            @Override            public View makeView() {                // 加载R.layout.slidelistview组件,实际上就是一个GridView组件                return inflater.inflate(R.layout.slidelistview, null);            }        });        // 页面加载时先显示第一屏        next(null);    }    public void next(View v) {        if (screenNo < screenCount - 1) {            screenNo++;            // 为ViewSwitcher的组件显示过程设置动画            switcher.setInAnimation(this, R.anim.slide_in_right);            // 为ViewSwitcher的组件隐藏过程设置动画            switcher.setOutAnimation(this, R.anim.slide_out_left);            // 控制下一屏将要显示的GridView对应的Adapter            ((GridView) switcher.getNextView()).setAdapter(adapter);            // 单击右边按钮,显示下一屏            // 学习手势检测后,也可通过手势检测实现显示下一屏            switcher.showNext();  // ①        }    }    public void prev(View v) {        if (screenNo > 0) {            screenNo--;            // 为ViewSwitcher的组件显示过程设置动画            switcher.setInAnimation(this, android.R.anim.slide_in_left);            // 为ViewSwitcher的组件隐藏过程设置动画            switcher.setOutAnimation(this, android.R.anim.slide_out_right);            // 控制下一屏将要显示的GridView对应的 Adapter            ((GridView) switcher.getNextView()).setAdapter(adapter);            // 单击左边按钮,显示上一屏,当然可以采用手势            // 学习手势检测后,也可通过手势检测实现显示上一屏            switcher.showPrevious();  //②        }    }    // 该BaseAdapter负责为每屏显示的GridView提供列表项    private BaseAdapter adapter = new BaseAdapter() {        @Override        public int getCount() {            // 如果已经到了最后一屏,且应用程序的数量不能整除NUMBER_PER_SCREEN            if (screenNo == screenCount - 1                    && items.size() % NUMBER_PER_SCREEN != 0) {                // 最后一屏显示的程序数为应用程序的数量对NUMBER_PER_SCREEN求余                return items.size() % NUMBER_PER_SCREEN;            }            // 否则每屏显示的程序数量为NUMBER_PER_SCREEN            return NUMBER_PER_SCREEN;        }        @Override        public DataItem getItem(int position) {            // 根据screenNo计算第position个列表项的数据            return items.get(screenNo * NUMBER_PER_SCREEN + position);        }        @Override        public long getItemId(int position) {            return position;        }        @Override        public View getView(int position                , View convertView, ViewGroup parent) {            View view = convertView;            if (convertView == null) {                // 加载R.layout.labelicon布局文件                view = inflater.inflate(R.layout.labelicon, null);            }            // 获取R.layout.labelicon布局文件中的ImageView组件,并为之设置图标            ImageView imageView = (ImageView)                    view.findViewById(R.id.imageview);            imageView.setImageDrawable(getItem(position).drawable);            // 获取R.layout.labelicon布局文件中的TextView组件,并为之设置文本            TextView textView = (TextView)                    view.findViewById(R.id.textview);            textView.setText(getItem(position).dataName);            return view;        }    };}

上面的程序使用 screenNo 保存当前正在显示第几屏的程序列表。该程序的关键在于 BaseAdapter 对象。这个 BaseAdapter 会根据 screenNo 动态计算该 Adapter 总共包含多少个列表项(如 getCount() 方法所示)。会根据 screenNo 计算每个列表项的数据(如 getItem(int position) 方法所示 )。

BaseAdapter 的 getView() 只是简单加载了 R.layout.labelicon 布局文件,并使用当前列表项的图片数据填充 R.layout.labelicon 布局文件中的 ImageView,使用当前列表项的文本数据填充 R.layout.labelicon 布局文件中的 TextView。下面是 R.layout.labelicon 布局文件的代码。

<?xml version="1.0" encoding="utf-8"?><!-- 定义一个垂直的LinearLayout,该容器中放置一个ImageView和一个TextView --><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center">    <ImageView        android:id="@+id/imageview"        android:layout_width="wrap_content"        android:layout_height="wrap_content"         />    <TextView        android:id="@+id/textview"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:gravity="center"         /> </LinearLayout>

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

为了实现 ViewSwitcher 切换 View 时的动画效果。程序的事件处理方法中调用了 ViewSwitcher 的 setInAnimation()、setOutAnimation() 方法来设置动画效果。本程序不仅利用了 Android 系统提供的两个动画资源,还自行提供了动画资源。
其中 R.anim.slide_in_right 动画资源对应的代码如下。

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

程序清单:slide_out_left.xml

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

图像切换器 ( ImageSwitcher ) 的功能与用法

ImageView 继承了 ViewSwitcher,因此它具有与 ViewSwitcher 相同的特征:可以在切换 View 组件时使用动画效果。ImageView 继承了 ViewSwitcher,并重写了 ViewSwitcher 的 showNext() 、showPrevious() 方法,因此 ImageSwitcher 使用起来更加简单。使用 ImageSwitcher 只要如下两步即可。

1. 为 ImageSwitcher 提供一个 ViewFactory,该 ViewFactory 生成的 View 组件必须是 ImageView。
2. 需要切换图片时,只要调用 ImageSwitcher 的 setImageDrawable(Drawable drawable)、setImageResource(int resid) 和 setImageURI(Uri uri) 方法更换图片即可。

实例:支持动画的图片浏览器

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center_horizontal">    <!-- 定义一个GridView组件 -->    <GridView        android:id="@+id/grid01"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:horizontalSpacing="2dp"        android:verticalSpacing="2dp"        android:numColumns="4"        android:gravity="center"/>    <!-- 定义一个ImageSwitcher组件 -->    <ImageSwitcher android:id="@+id/switcher"        android:layout_width="300dp"        android:layout_height="300dp"        android:layout_gravity="center_horizontal"        android:inAnimation="@android:anim/fade_in"        android:outAnimation="@android:anim/fade_out"/></LinearLayout>

上面布局文件中的代码定义了一个 ImageSwitcher,并通过 android:inAnimation 和 android:outAnimation 指定了图片切换时的动画效果。

接下来 Activity 代码需要为该 ImageSwitcher 设置 ViewFactory,并让该 ViewFactory 的 makeView() 方法返回 ImageView 。下面是该 Activity 的代码。

public class MainActivity extends Activity {    int[] imageIds = new int[]            {                    R.drawable.bomb5, R.drawable.bomb6, R.drawable.bomb7                    , R.drawable.bomb8, R.drawable.bomb9, R.drawable.bomb10                    , R.drawable.bomb11, R.drawable.bomb12, R.drawable.bomb13                    , R.drawable.bomb14, R.drawable.bomb15, R.drawable.bomb16            };    ImageSwitcher switcher;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        // 创建一个List对象,List对象的元素是Map        List<Map<String, Object>> listItems =                new ArrayList<Map<String, Object>>();        for (int i = 0; i < imageIds.length; i++) {            Map<String, Object> listItem = new HashMap<String, Object>();            listItem.put("image", imageIds[i]);            listItems.add(listItem);        }        // 获取显示图片的ImageSwitcher        switcher = (ImageSwitcher)                findViewById(R.id.switcher);        // 为ImageSwitcher设置图片切换的动画效果        switcher.setFactory(new ViewFactory() {            @Override            public View makeView() {                // 创建ImageView对象                ImageView imageView = new ImageView(MainActivity.this);                imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);                imageView.setLayoutParams(new ImageSwitcher.LayoutParams(                        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));                // 返回ImageView对象                return imageView;            }        });        // 创建一个SimpleAdapter        SimpleAdapter simpleAdapter = new SimpleAdapter(this,                listItems                // 使用/layout/cell.xml文件作为界面布局                , R.layout.cell, new String[]{"image"},                new int[]{R.id.image1});        GridView grid = (GridView) findViewById(R.id.grid01);        // 为GridView设置Adapter        grid.setAdapter(simpleAdapter);        // 添加列表项被选中的监听器        grid.setOnItemSelectedListener(new OnItemSelectedListener() {            @Override            public void onItemSelected(AdapterView<?> parent, View view,                                       int position, long id) {                // 显示当前被选中的图片                switcher.setImageResource(imageIds[position]);            }            @Override            public void onNothingSelected(AdapterView<?> parent) {            }        });        // 添加列表项被单击的监听器        grid.setOnItemClickListener(new OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view,                                    int position, long id) {                // 显示被单击的图片                switcher.setImageResource(imageIds[position]);            }        });    }}

上面的代码中重写了 ViewFactory 的 makeView() 方法,该方法返回一个 ImageView 对象,这样该 ImageSwitcher 即可正常工作。该 Activity 还为 GridView 绑定了事件监听器,当用户单击 GridView 或选中 GridView 的指定单元格时,ImageSwitcher 切换为显示对应的图片。

文本切换器 (TextSwitcher) 的功能与用法

TextSwitcher 继承了 ViewSwitcher,因此它具有与 ViewSwitcher 相同的特征:可以在切换 View 组件时使用动画效果。与 ImageSwitcher 相似的是,使用 TextSwitcher 也需要设置一个 ViewFactory。与 ImageSwitcher 相似的是,使用 TextSwitcher 也需要设置一个 ViewFactory。与 ImageSwitcher 不同的是,TextSwitcher 所需的 ViewFactory 的 makeView() 方法必须返回一个 TextView 组件。

实例:TextSwitcher

<?xml version="1.0" encoding="utf-8" ?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <!-- 定义一个TextSwitcher,并指定了文本切换时的动画效果 -->    <TextSwitcher        android:id="@+id/textSwitcher"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:inAnimation="@android:anim/slide_in_left"        android:outAnimation="@android:anim/slide_out_right"        android:onClick="next"/></LinearLayout>
public class MainActivity extends Activity {    TextSwitcher textSwitcher;    String[] strs = new String[]            {                    "疯狂Java讲义",                    "轻量级Java EE企业应用实战",                    "疯狂Android讲义",                    "疯狂Ajax讲义"            };    int curStr;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        textSwitcher = (TextSwitcher) findViewById(R.id.textSwitcher);        textSwitcher.setFactory(new ViewSwitcher.ViewFactory() {            public View makeView() {                TextView tv = new TextView(MainActivity.this);                tv.setTextSize(40);                tv.setTextColor(Color.MAGENTA);                return tv;            }        });        // 调用next方法显示下一个字符串        next(null);    }    // 事件处理函数,控制显示下一个字符串    public void next(View source) {        textSwitcher.setText(strs[curStr++ % strs.length]);  // ①    }}

上面的代码重写了 ViewFactory 的 makeView() 方法,该方法返回了一个 TextView,这样即可让 TextSwitcher 正常工作。当程序要切换 TextSwitcher 显示文本时,调用 TextSwitcher 的 setText() 方法修改文本即可 —— 如上面的 ①号代码所示。

ViewFlipper 的功能与用法

ViewFlipper 组件继承了 ViewAnimator,它可调用 addView(View v) 添加多个组件,一旦向 ViewFlipper 中添加了多个组件之后,ViewFlipper 可使用动画控制多个组件之间的切换效果。

ViewFlipper 与前面介绍的 AdapterViewFlipper 有较大的相似性,他们可以控制组件切换的动画效果。它们的区别是:ViewFlipper 需要开发者通过 addView(View v) 添加多个 View,而 AdapterViewFlipper 则只要传入一个 Adapter,Adapter 将会负责提供多个 View。因此 ViewFlipper 可以指定与 AdapterViewFlipper 相同的 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">    <ViewFlipper        android:id="@+id/details"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:flipInterval="1000">        <ImageView            android:src="@drawable/java"            android:layout_width="match_parent"            android:layout_height="wrap_content">        </ImageView>        <ImageView            android:src="@drawable/android"            android:layout_width="match_parent"            android:layout_height="wrap_content">        </ImageView>        <ImageView            android:src="@drawable/javaee"            android:layout_width="match_parent"            android:layout_height="wrap_content">        </ImageView>    </ViewFlipper>    <Button        android:text="&lt;"        android:onClick="prev"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_alignParentLeft="true"/>    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_centerInParent="true"        android:onClick="auto"        android:text="自动播放"/>    <Button        android:text="&gt;"        android:onClick="next"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_alignParentRight="true"/></RelativeLayout>

上面的布局文件定义了一个 ViewFlipper,并在该 ViewFlipper 中定义了三个 ImageView,这意味着该 ViewFlipper 包含了三个子组件。接下来再 Activity 代码中即可调用 ViewFlipper 的 showPrevious()、showNext() 等方法控制 ViewFlipper 显示上一个、下一个子组件。为了控制组件切换时的动画效果,还需要调用 ViewFlipper 的 setInAnimation()、setOutAnimation() 方法设置动画效果。

public class MainActivity extends Activity {    private ViewFlipper viewFlipper;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        viewFlipper = (ViewFlipper) findViewById(R.id.details);    }    public void prev(View source) {        viewFlipper.setInAnimation(this, R.anim.slide_in_right);        viewFlipper.setOutAnimation(this, R.anim.slide_out_left);        // 显示上一个组件        viewFlipper.showPrevious();        // 停止自动播放        viewFlipper.stopFlipping();    }    public void next(View source) {        viewFlipper.setInAnimation(this, android.R.anim.slide_in_left);        viewFlipper.setOutAnimation(this, android.R.anim.slide_out_right);        // 显示下一个组件        viewFlipper.showNext();        // 停止自动播放        viewFlipper.stopFlipping();    }    public void auto(View source) {        viewFlipper.setInAnimation(this, android.R.anim.slide_in_left);        viewFlipper.setOutAnimation(this, android.R.anim.slide_out_right);        // 开始自动播放        viewFlipper.startFlipping();    }}
0 0