ViewAnimator是一个基类,它继承了FrameLayout。因此它表现出FrameLayout的特征,可以将多个View组“叠”在一起。
ViewAnimator可以在View切换时表现出动画效果。
ViewAnimator及其子类也是一组非常重要的UI组件,这种组件的主要功能是增加动画效果。从而使界面更加“炫”。
【ViewAnimator及其子类的继承关系】
图2.56
【ViewAnimator支持的常见XML属性】
android:animateFirstView 设置ViewAnimator显示第一个View组件时是否使用动画
android:inAnimation 设置ViewAnimator显示组件时使用的动画
android:outAnimation 设置ViewAnimator隐藏组件时使用的动画
★★★ ViewSwitcher的功能与用法 ★★★
ViewSwitcher代表了视图切换组件。它本身继承了FrameLayout。因此可以将多个View层叠加在一起,
每次只显示一个组件。当程序控制从一个View切换到另一个View时,ViewSwitcher支持指定动画效果。
为了给ViewSwitcher添加多个组件,一般通过调用ViewSwitcher的setFactory(ViewSwitcher.ViewFactory)方法为之设置ViewFactory,
并由该ViewFactory为之创建View即可。
实例:仿Android系统Launcher界面
本实例就是通过ViewSwitcher来实现Android4.2的Launcher分屏、左右滑动。
为了实现该效果,程序主界面考虑使用ViewSwitcher来组合多个GridView。每个GridView代表一个屏幕
的应用程序。
布局文件:
1 <RelativeLayout 2 xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent"> 5 <!-- 定义一个ViewSwitcher组件 --> 6 <ViewSwitcher 7 android:id="@+id/viewSwitcher" 8 android:layout_width="fill_parent" 9 android:layout_height="fill_parent" /> 10 <!-- 定义滚动到上一屏的按钮 --> 11 <Button 12 android:id="@+id/button_prev" 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:layout_alignParentBottom="true" 16 android:layout_alignParentLeft="true" 17 android:onClick="prev" 18 android:text="<" /> 19 <!-- 定义滚动到下一屏的按钮 --> 20 <Button 21 android:id="@+id/button_next" 22 android:layout_width="wrap_content" 23 android:layout_height="wrap_content" 24 android:layout_alignParentBottom="true" 25 android:layout_alignParentRight="true" 26 android:onClick="next" 27 android:text=">" /> 28 </RelativeLayout>
Activity代码:
1 public class ViewSwitcherTest extends Activity { 2 // 定义一个常量,用于显示每屏显示的应用程序数 3 public static final int NUMBER_PER_SCREEN = 12; 4 5 // 代表应用程序的内部类, 6 public static class DataItem { 7 // 应用程序名称 8 public String dataName; 9 // 应用程序图标 10 public Drawable drawable; 11 } 12 13 // 保存系统所有应用程序的List集合 14 private ArrayList<DataItem> items = new ArrayList<DataItem>(); 15 // 记录当前正在显示第几屏的程序 16 private int screenNo = -1; 17 // 保存程序所占的总屏数 18 private int screenCount; 19 ViewSwitcher switcher; 20 // 创建LayoutInflater对象 21 LayoutInflater inflater; 22 23 @Override 24 public void onCreate(Bundle savedInstanceState) { 25 super.onCreate(savedInstanceState); 26 setContentView(R.layout.main); 27 inflater = LayoutInflater.from(ViewSwitcherTest.this); 28 // 创建一个包含40个元素的List集合,用于模拟包含40个应用程序 29 for (int i = 0; i < 40; i++) { 30 String label = "" + i; 31 Drawable drawable = getResources().getDrawable( 32 R.drawable.ic_launcher); 33 DataItem item = new DataItem(); 34 item.dataName = label; 35 item.drawable = drawable; 36 items.add(item); 37 } 38 // 计算应用程序所占的总屏数。 39 // 如果应用程序的数量能整除NUMBER_PER_SCREEN,除法的结果就是总屏数。 40 // 如果不能整除,总屏数应该是除法的结果再加1。 41 screenCount = items.size() % NUMBER_PER_SCREEN == 0 ? items.size() 42 / NUMBER_PER_SCREEN : items.size() / NUMBER_PER_SCREEN + 1; 43 switcher = (ViewSwitcher) findViewById(R.id.viewSwitcher); 44 switcher.setFactory(new ViewFactory() { 45 // 实际上就是返回一个GridView组件 46 @Override 47 public View makeView() { 48 // 加载R.layout.slidelistview组件,实际上就是一个GridView组件。 49 return inflater.inflate(R.layout.slidelistview, null); 50 } 51 }); 52 // 页面加载时先显示第一屏。 53 next(null); 54 } 55 56 public void next(View v) { 57 if (screenNo < screenCount - 1) { 58 screenNo++; 59 // 为ViewSwitcher的组件显示过程设置动画 60 switcher.setInAnimation(this, R.anim.slide_in_right); 61 // 为ViewSwitcher的组件隐藏过程设置动画 62 switcher.setOutAnimation(this, R.anim.slide_out_left); 63 // 控制下一屏将要显示的GridView对应的 Adapter 64 ((GridView) switcher.getNextView()).setAdapter(adapter); 65 // 点击右边按钮,显示下一屏, 66 // 学习手势检测后,也可通过手势检测实现显示下一屏. 67 switcher.showNext(); // ① 68 } 69 } 70 71 public void prev(View v) { 72 if (screenNo > 0) { 73 screenNo--; 74 // 为ViewSwitcher的组件显示过程设置动画 75 switcher.setInAnimation(this, android.R.anim.slide_in_left); 76 // 为ViewSwitcher的组件隐藏过程设置动画 77 switcher.setOutAnimation(this, android.R.anim.slide_out_right); 78 // 控制下一屏将要显示的GridView对应的 Adapter 79 ((GridView) switcher.getNextView()).setAdapter(adapter); 80 // 点击左边按钮,显示上一屏,当然可以采用手势 81 // 学习手势检测后,也可通过手势检测实现显示上一屏. 82 switcher.showPrevious(); // ② 83 } 84 } 85 86 // 该BaseAdapter负责为每屏显示的GridView提供列表项 87 private BaseAdapter adapter = new BaseAdapter() { 88 @Override 89 public int getCount() { 90 // 如果已经到了最后一屏,且应用程序的数量不能整除NUMBER_PER_SCREEN 91 if (screenNo == screenCount - 1 92 && items.size() % NUMBER_PER_SCREEN != 0) { 93 // 最后一屏显示的程序数为应用程序的数量对NUMBER_PER_SCREEN求余 94 return items.size() % NUMBER_PER_SCREEN; 95 } 96 // 否则每屏显示的程序数量为NUMBER_PER_SCREEN 97 return NUMBER_PER_SCREEN; 98 } 99 100 @Override 101 public DataItem getItem(int position) { 102 // 根据screenNo计算第position个列表项的数据 103 return items.get(screenNo * NUMBER_PER_SCREEN + position); 104 } 105 106 @Override 107 public long getItemId(int position) { 108 return position; 109 } 110 111 @Override 112 public View getView(int position, View convertView, ViewGroup parent) { 113 View view = convertView; 114 if (convertView == null) { 115 // 加载R.layout.labelicon布局文件 116 view = inflater.inflate(R.layout.labelicon, null); 117 } 118 // 获取R.layout.labelicon布局文件中的ImageView组件,并为之设置图标 119 ImageView imageView = (ImageView) view.findViewById(R.id.imageview); 120 imageView.setImageDrawable(getItem(position).drawable); 121 // 获取R.layout.labelicon布局文件中的TextView组件,并为之设置文本 122 TextView textView = (TextView) view.findViewById(R.id.textview); 123 textView.setText(getItem(position).dataName); 124 return view; 125 } 126 }; 127 }
适配器Item的布局文件labelicon.xml。
1 <?xml version="1.0" encoding="utf-8"?> 2 <!-- 定义一个垂直的LinearLayout,该容器中放置一个ImageView和一个TextView --> 3 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:gravity="center" 7 android:orientation="vertical" > 8 <ImageView 9 android:id="@+id/imageview" 10 android:layout_width="wrap_content" 11 android:layout_height="wrap_content" /> 12 <TextView 13 android:id="@+id/textview" 14 android:layout_width="wrap_content" 15 android:layout_height="wrap_content" 16 android:gravity="center" /> 17 </LinearLayout>
GridView布局slidelistview.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <GridView 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:numColumns="4" />
为了实现ViewSwitcher切换View时的动画效果,程序的事件处理方法中调用了ViewSwitcher的
setInAnimation()、setOutAnimation()来设置动画效果。
R.anim.slide_in_right
1 <?xml version="1.0" encoding="utf-8"?> 2 <set xmlns:android="http://schemas.android.com/apk/res/android"> 3 <!-- 设置从右边拖进来的动画 4 android:duration指定动画持续时间 --> 5 <translate 6 android:fromXDelta="100%p" 7 android:toXDelta="0" 8 android:duration="@android:integer/config_mediumAnimTime" /> 9 </set>
R.anim.slide_out_left
1 <?xml version="1.0" encoding="utf-8"?> 2 <set xmlns:android="http://schemas.android.com/apk/res/android"> 3 <!-- 设置从左边拖出去的动画 4 android:duration指定动画持续时间 --> 5 <translate 6 android:fromXDelta="0" 7 android:toXDelta="-100%p" 8 android:duration="@android:integer/config_mediumAnimTime" /> 9 </set>
★★★ 图片切换器(ImageSwitcher)的功能与用法 ★★★
ImageSwitcher继承了ViewSwitcher,并且重写了ViewSwitvher的showNext()、showPrevious().
因此它具有与ViewSwitvher相同的特征;可以在切换View组件时使用动画效果。
(1)为ImageSwitcher提供一个ViewFactory,该ViewFactory生成的View组件必须是ImageView。
(2)需要切换图片时,只要调用ImageSwitcher的setImageDrawable(Drawable drawable)。
setImageResource(int resid)和setImageURI(Uri uri)更换图片即可。
【提示】ImageSwitcher与ImageView的功能有点相似。它们都可用于显示图片,区别在于ImageSwitcher
的效果更炫,它可以指定图片切换时的动画效果。
实例:支持动画的图片浏览器
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:gravity="center_horizontal" 6 android:orientation="vertical" > 7 8 <!-- 定义一个GridView组件 --> 9 <GridView 10 android:id="@+id/grid01" 11 android:layout_width="fill_parent" 12 android:layout_height="wrap_content" 13 android:gravity="center" 14 android:horizontalSpacing="pt" 15 android:numColumns="4" 16 android:verticalSpacing="2pt" /> 17 18 <!-- 定义一个ImageSwitcher组件 --> 19 <ImageSwitcher 20 android:id="@+id/switcher" 21 android:layout_width="300dp" 22 android:layout_height="300dp" 23 android:layout_gravity="center_horizontal" 24 android:inAnimation="@android:anim/fade_in" 25 android:outAnimation="@android:anim/fade_out" /> 26 </LinearLayout>
1 public class ImageSwitcherTest extends Activity { 2 int[] imageIds = new int[] { R.drawable.bomb5, R.drawable.bomb6, 3 R.drawable.bomb7, R.drawable.bomb8, R.drawable.bomb9, 4 R.drawable.bomb10, R.drawable.bomb11, R.drawable.bomb12, 5 R.drawable.bomb13, R.drawable.bomb14, R.drawable.bomb15, 6 R.drawable.bomb16 }; 7 ImageSwitcher switcher; 8 9 @Override 10 public void onCreate(Bundle savedInstanceState) { 11 super.onCreate(savedInstanceState); 12 setContentView(R.layout.main); 13 // 创建一个List对象,List对象的元素是Map 14 List<Map<String, Object>> listItems = new ArrayList<Map<String, Object>>(); 15 for (int i = 0; i < imageIds.length; i++) { 16 Map<String, Object> listItem = new HashMap<String, Object>(); 17 listItem.put("image", imageIds[i]); 18 listItems.add(listItem); 19 } 20 // 获取显示图片的ImageSwitcher 21 switcher = (ImageSwitcher) findViewById(R.id.switcher); 22 // 为ImageSwitcher设置图片切换的动画效果 23 switcher.setFactory(new ViewFactory() { 24 @Override 25 public View makeView() { 26 // 创建ImageView对象 27 ImageView imageView = new ImageView(ImageSwitcherTest.this); 28 imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); 29 imageView.setLayoutParams(new ImageSwitcher.LayoutParams( 30 LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 31 // 返回ImageView对象 32 return imageView; 33 } 34 }); 35 // 创建一个SimpleAdapter 36 SimpleAdapter simpleAdapter = new SimpleAdapter(this, 37 listItems 38 // 使用/layout/cell.xml文件作为界面布局 39 , R.layout.cell, new String[] { "image" }, 40 new int[] { R.id.image1 }); 41 GridView grid = (GridView) findViewById(R.id.grid01); 42 // 为GridView设置Adapter 43 grid.setAdapter(simpleAdapter); 44 // 添加列表项被选中的监听器 45 grid.setOnItemSelectedListener(new OnItemSelectedListener() { 46 @Override 47 public void onItemSelected(AdapterView<?> parent, View view, 48 int position, long id) { 49 // 显示当前被选中的图片 50 switcher.setImageResource(imageIds[position]); 51 } 52 @Override 53 public void onNothingSelected(AdapterView<?> parent) { 54 } 55 }); 56 // 添加列表项被单击的监听器 57 grid.setOnItemClickListener(new OnItemClickListener() { 58 @Override 59 public void onItemClick(AdapterView<?> parent, View view, 60 int position, long id) { 61 // 显示被单击的图片的图片 62 switcher.setImageResource(imageIds[position]); 63 } 64 }); 65 } 66 }
★★★ 文本切换器(TextSwitcher)的功能与用法 ★★★
TextSwitcher继承了ViewSwitcher。可以在切换View组件时使用动画效果。与ImageSwitcher相似的是,
使用TextSwitcher也需要设置一个ViewFactory。与ImageSwitcher不同的是,TextSwitcher所需的
ViewFactory的makeView()必须返回一个TextView组件。
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" > 7 <!-- 定义一个TextSwitcher,并指定了文本切换时的动画效果 --> 8 <TextSwitcher 9 android:id="@+id/textSwitcher" 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content" 12 android:onClick="next" 13 android:inAnimation="@android:anim/slide_in_left" 14 android:outAnimation="@android:anim/slide_out_right" /> 15 </LinearLayout>
1 public class TextSwitcherTest extends Activity { 2 TextSwitcher textSwitcher; 3 String[] strs = new String[] { "Android", "IOS", "JAVAEE", "PHP" }; 4 int curStr; 5 6 @Override 7 public void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.main); 10 textSwitcher = (TextSwitcher) findViewById(R.id.textSwitcher); 11 textSwitcher.setFactory(new ViewSwitcher.ViewFactory() { 12 public View makeView() { 13 TextView tv = new TextView(TextSwitcherTest.this); 14 tv.setTextSize(40); 15 tv.setTextColor(Color.MAGENTA); 16 return tv; 17 } 18 }); 19 // 调用next方法显示下一个字符串 20 next(null); 21 } 22 23 // 事件处理函数,控制显示下一个字符串 24 public void next(View source) { 25 textSwitcher.setText(strs[curStr++ % strs.length]); 26 } 27 }
上面的代码重写了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属性。
范例:自动播放的图片库
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 android:orientation="vertical" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent"> 7 <ViewFlipper 8 android:id="@+id/details" 9 android:layout_width="match_parent" 10 android:layout_height="match_parent" 11 android:persistentDrawingCache="animation" 12 android:flipInterval="1000"> 13 <ImageView 14 android:src="@drawable/java" 15 android:layout_width="fill_parent" 16 android:layout_height="wrap_content" /> 17 <ImageView 18 android:src="@drawable/android" 19 android:layout_width="fill_parent" 20 android:layout_height="wrap_content" /> 21 <ImageView 22 android:src="@drawable/ee" 23 android:layout_width="fill_parent" 24 android:layout_height="wrap_content" /> 25 </ViewFlipper> 26 <Button 27 android:text="<" 28 android:onClick="prev" 29 android:layout_width="wrap_content" 30 android:layout_height="wrap_content" 31 android:layout_alignParentBottom="true" 32 android:layout_alignParentLeft="true" /> 33 <Button 34 android:layout_width="wrap_content" 35 android:layout_height="wrap_content" 36 android:layout_alignParentBottom="true" 37 android:layout_centerInParent="true" 38 android:onClick="auto" 39 android:text="自动播放" /> 40 <Button 41 android:text=">" 42 android:onClick="next" 43 android:layout_width="wrap_content" 44 android:layout_height="wrap_content" 45 android:layout_alignParentBottom="true" 46 android:layout_alignParentRight="true" /> 47 </RelativeLayout>
上面的布局文件定义了一个ViewFlipper,并在该ViewFlipper中定义了三个ImageView,这意味着该
ViewFlipper包含了三个子组件。接下来在Activity代码中即可调用ViewFlipper的showPrevious()、
showNext()等方法控制ViewFlipper显示上一个、下一个子组件。为了控制组件切换时的动画效果。
还需要调用ViewFlipper的setInAnimation()、setOutAnimation()方法设置动画效果。
1 public class ViewFlipperTest extends Activity { 2 private ViewFlipper viewFlipper; 3 4 @Override 5 public void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.main); 8 viewFlipper = (ViewFlipper) findViewById(R.id.details); 9 } 10 11 public void prev(View source) { 12 viewFlipper.setInAnimation(this, R.anim.slide_in_right); 13 viewFlipper.setOutAnimation(this, R.anim.slide_out_left); 14 // 显示上一个组件 15 viewFlipper.showPrevious(); 16 // 停止自动播放 17 viewFlipper.stopFlipping(); 18 } 19 20 public void next(View source) { 21 viewFlipper.setInAnimation(this, android.R.anim.slide_in_left); 22 viewFlipper.setOutAnimation(this, android.R.anim.slide_out_right); 23 // 显示下一个组件。 24 viewFlipper.showNext(); 25 // 停止自动播放 26 viewFlipper.stopFlipping(); 27 } 28 29 public void auto(View source) { 30 viewFlipper.setInAnimation(this, android.R.anim.slide_in_left); 31 viewFlipper.setOutAnimation(this, android.R.anim.slide_out_right); 32 // 开始自动播放 33 viewFlipper.startFlipping(); 34 } 35 }