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

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

下面通过实例来介绍ViewFactory的用法。

  实例:仿Android系统Launcher界面。

       Android4.2界面已经实现了分屏、左右滚动,本实例就是通过ViewSwitcher来实现Android 4.2的分屏、左右滚动效果。

为了实现该效果,程序主界面考虑使用ViewSwitcher来组合多个GridView,每个GridView代表一个屏幕的应用程序,GridView中每个单元格显示一个应用程序的图标好程序名。

该程序的主界面布局文件如下。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<!-- 定义一个ViewSwitcher组件 -->
<ViewSwitcher android:id="@+id/viewSwitcher"
android:layout_width="fill_parent"
android:layout_height="fill_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>

上面的布局文件中只是定义了一个ViewSwitcher组件和两个按钮,这两个按钮分别用于控制该ViewSwitcher显示上一屏、下一屏的程序列表。
        该实例的重点在于为该ViewSwitcher设置ViewFactory对象,并且当用户单击“<”和“>”两个按钮时控制ViewSwitcher显示“上一屏”和“下一屏” 的应用程序。

该程序会考虑使用扩展BaseAdapter的方式为GridView提供Adapter,而本实例的关键就是根据用户单击的按钮来动态来动态计算该BaseAdapter应该显示哪些程序列表。该程序的Activity代码如下。

package org.crazyit.helloworld;

import java.util.ArrayList;

import android.os.Bundle;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import android.widget.ViewSwitcher.ViewFactory; public class ViewAnimatorTest 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
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_animator_test);
inflater=LayoutInflater.from(ViewAnimatorTest.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 ViewFactory(){
//实际上就是返回一个GridView组件
@Override
public View makeView() {
// TODO Auto-generated method stub
//加载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,R.anim.slide_in_left);
//为ViewSwitcher的组件隐藏过程设置动画
switcher.setOutAnimation(this,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() {
// TODO Auto-generated method stub
//如果已经到了最后一屏,且应用程序的数量不能整除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 Object getItem(int position) {
// TODO Auto-generated method stub
//根据screenNo计算第position个列表项的数据
return items.get(screenNo*NUMBER_PER_SCREEN+
position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
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(((DataItem)getItem(position)).drawable);
//获取R.layout.labelicon布局文件中的TextView组件,并为之设置文本
TextView textView=(TextView)view.findViewById(R.id.textview);
textView.setText(((DataItem)getItem(position)).dataName);
return
view;
} };
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.view_animator_test, menu);
return true;
} }

上面的程序中使用screenNo保存当前正在显示第几屏的程序列表。该程序的关键在于粗体字代码部分,该粗体字代码创建了BaseAdapter对象,这个BaseAdapter对象会根据sceenNo动态计算该Adapter总共包含多少个列表项(如getCout()方法所示)。会根据screenNo计算每个列表项的数据(getItem(int position)方法所示)。
   BaseAdapter的getView()只是简单加载了R.layout.labelicon布局文件,并使用当前列表项的图片数据填充R.layout.labelicon布局文件中的ImageView,使用当前列表项的文本数据填充R.layout.labelicon布局文件中的TextView。下面是R.layout.lablicon布局文件的代码。

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

黑体字使用的R.layout.slidelistview布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:numColumns="4"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</GridView>

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

为了实现ViewSwitcher切换View时的动画效果,程序的事件处理方法中调用了ViewSwitcher的setAnimation()、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>

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

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

R.anim.slide_in_left动画资源对应的代码如下。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- 设置从左边边拖进来的动画
android:duration指定动画持续时间 -->
<translate
android:fromXDelta="-50%p"
android:toXDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>

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

<?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="50%p"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>

运行上面的程序,可以看到下图所示的效果。
 

ViewSwitcher的功能与用法的更多相关文章

  1. Android ViewSwitcher 的功能与用法

    ViewSwitcher 代表了视图切换组件, 本身继承了FrameLayout ,可以将多个View叠在一起 ,每次只显示一个组件.当程序控制从一个View切换到另个View时,ViewSwitch ...

  2. Android 自学之画廊视图(Gallery)功能和用法

    Gallery与之前讲的Spinner有共同的父类:AbsSpinner,表明Gallery和Spinner都是一个列表框.他们之间的区别在于Spinner显示的是一个垂直的列表框,而Gallery显 ...

  3. 搜索框(SearchView)的功能与用法

    SearchView是搜索框组件,它可以让用户在文本框内输入汉字,并允许通过监听器监控用户输入,当用户用户输入完成后提交搜索按钮时,也通过监听器执行实际的搜索. 使用SearchView时可以使用如下 ...

  4. 数值选择器(NumberPicker)的功能与用法

    数值选择器用于让用户输入数值,用户既可以通过键盘输入数值,也可以通过拖动来选择数值.使用该组件常用如下三个方法. setMinValue(int minVal):设置该组件支持的最小值. setMax ...

  5. 日历视图(CalendarView)组件的功能和用法

    日历视图(CalendarView)可用于显示和选择日期,用户既可选择一个日期,也可通过触摸来滚动日历.如果希望监控该组件的日历改变,可调用CalendarView的setOnDateChangeLi ...

  6. 星级评分条(RatingBar)的功能和用法

    星级评分条与拖动条有相同的父类:AbsSeekBar,因此它们十分相似.实际上星级评分条与拖动条的用法.功能都十分接近:它们都是允许用户通过拖动条来改变进度.RatingBar与SeekBar最大区别 ...

  7. 拖动条(SeekBar)的功能和用法

    拖动条和进度条非常相似,只是进度条采用颜色填充来表明进度完成的程序,而拖动条则通过滑块的位置来标识数值——而且拖动条允许用户拖动滑块来改变值,因而拖动条通常用于对系统的某种数值进行调节,比如调节音量等 ...

  8. StackView的功能和用法

    StackView也是AdapterViewAnimator的子类,它也用于显示Adapter提供的系列View.SackView将会以“堆叠(Stack)”方式来显示多个列表项. 为了控制Stack ...

  9. MySQL常用存储引擎功能与用法详解

    本文实例讲述了MySQL常用存储引擎功能与用法. MySQL存储引擎主要有两大类: 1. 事务安全表:InnoDB.BDB. 2. 非事务安全表:MyISAM.MEMORY.MERGE.EXAMPLE ...

随机推荐

  1. CALayer & UIView 关系浅析

    原文链接:http://www.jianshu.com/p/8e6a313c158e 一.CALayer和UIView的关系 UIView显示在屏幕上归功于CALayer 可以说:UIView依赖CA ...

  2. java中“==”和equal区别

    8个月以后就要正式找工作啦,我觉得现在是时候花时间好好深入研究一下以前比较混肴的知识.这就当作是自我成长的第一步! 对于String中的“equal方法”和“==”一直有点混肴,今天重新看了一下他们两 ...

  3. Qt5:窗口背景色的设置

    在Qt中,设置窗口背景色有多种方法,如通过setStyleSheet   和 调色板 setPalette 等 下面是setPalette 方法 QPalette pale = palette(); ...

  4. c# mouseenter mousemove区别?

    onmousedown 当用户用任何鼠标按钮单击对象时触发. onmouseenter 当用户将鼠标指针移动到对象内时触发. onmouseleave 当用户将鼠标指针移出对象边界时触发. onmou ...

  5. js中原生对象、内置对象和宿主对象(转)

    本帖最后由 无解. 于 2012-9-9 12:13 编辑 <ignore_js_op> 这个图来自于<JavaScript语言精髓与编程实践>第三章P184页.最近在改第二版 ...

  6. SVN MERGE 和冲突

    摘要:最佳做法是避免冲突.冲突时,不要把branch merge到trunk. 先由最新版本的trunk得到branch,然后再修改文件,直接merge过去就行.这样不会有冲突.先用svn merge ...

  7. 转 互联网推送服务原理:长连接+心跳机制(MQTT协议)

    http://blog.csdn.net/zhangzeyuaaa/article/details/39028369 目录(?)[-] 无线移动网络的特点 android系统的推送和IOS的推送有什么 ...

  8. COC建筑拖动的实现

    最近在玩COC,多体验一下手游的体验,因为自己毕竟一直是做页游的,有些观念需要转变一下. 好像偏了,玩了几次之后突然想起COC那个地图拖动的自己之前实现过,那是2010年左右的时候,模拟经营类页游大行 ...

  9. fuel健康检查Heat失败的原因

    service openstack-heat-engine restart chkconfig --level 2345 openstack-heat-engine on

  10. PAT (Advanced Level) 1001. A+B Format (20)

    简单题. #include<iostream> #include<cstring> #include<cmath> #include<algorithm> ...