前面已经讲过ImageSwitcher和TextSwitcher。ImageSwitcher用来切换ImageView的,TextSwitcher是用来切换TextView的。

但是我们现在要切换自定义View怎么办?

ImageSwitcher和TextSwitcher已经不能满足我们的需求。ViewFlipper可以在任意View之间切换。下面我们就来讲解它。

先看一下结构图


可以看到ViewSwitcher和ViewFlipper都是继承自ViewAnimator。


下面通过一个Demo了解一下ViewFlipper的用法

main.xml

Html代码
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical">
  6. <ViewFlipper
  7. android:id="@+id/viewFlipper"
  8. android:layout_width="fill_parent"
  9. android:layout_height="fill_parent">
  10. <include
  11. android:id="@+id/layout01"
  12. layout="@layout/layout01"/>
  13. <include
  14. android:id="@+id/layout02"
  15. layout="@layout/layout02"/>
  16. </ViewFlipper>
  17. </LinearLayout>

layout01.xml
Html代码
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical">
  6. <TextView
  7. android:layout_width="fill_parent"
  8. android:layout_height="fill_parent"
  9. android:gravity="center"
  10. android:text="一个TextView"
  11. android:textSize="40dip"/>
  12. </LinearLayout>

layout02.xml
Html代码
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical">
  6. <LinearLayout
  7. android:layout_width="fill_parent"
  8. android:layout_height="fill_parent"
  9. android:gravity="center"
  10. android:orientation="vertical">
  11. <ImageView
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"
  14. android:src="@drawable/ic_launcher"/>
  15. <TextView
  16. android:layout_width="wrap_content"
  17. android:layout_height="wrap_content"
  18. android:text="一个TextView+一个ImageView"
  19. android:textSize="20dip"/>
  20. </LinearLayout>
  21. </LinearLayout>

ViewFlipperDemoActivity.java
Java代码
  1. packagecom.tianjf;
  2. importandroid.app.Activity;
  3. importandroid.os.Bundle;
  4. importandroid.view.MotionEvent;
  5. importandroid.view.View;
  6. importandroid.view.View.OnTouchListener;
  7. importandroid.view.animation.AnimationUtils;
  8. importandroid.widget.ViewFlipper;
  9. publicclassViewFlipperDemoActivityextendsActivityimplements
  10. OnTouchListener{
  11. privateViewFlipperviewFlipper;
  12. //左右滑动时手指按下的X坐标
  13. privatefloattouchDownX;
  14. //左右滑动时手指松开的X坐标
  15. privatefloattouchUpX;
  16. @Override
  17. publicvoidonCreate(BundlesavedInstanceState){
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.main);
  20. viewFlipper=(ViewFlipper)findViewById(R.id.viewFlipper);
  21. viewFlipper.setOnTouchListener(this);
  22. }
  23. @Override
  24. publicbooleanonTouch(Viewv,MotionEventevent){
  25. if(event.getAction()==MotionEvent.ACTION_DOWN){
  26. //取得左右滑动时手指按下的X坐标
  27. touchDownX=event.getX();
  28. returntrue;
  29. }elseif(event.getAction()==MotionEvent.ACTION_UP){
  30. //取得左右滑动时手指松开的X坐标
  31. touchUpX=event.getX();
  32. //从左往右,看前一个View
  33. if(touchUpX-touchDownX>100){
  34. //设置View切换的动画
  35. viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
  36. android.R.anim.slide_in_left));
  37. viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
  38. android.R.anim.slide_out_right));
  39. //显示下一个View
  40. viewFlipper.showPrevious();
  41. //从右往左,看后一个View
  42. }elseif(touchDownX-touchUpX>100){
  43. //设置View切换的动画
  44. //由于Android没有提供slide_out_left和slide_in_right,所以仿照slide_in_left和slide_out_right编写了slide_out_left和slide_in_right
  45. viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
  46. R.anim.slide_in_right));
  47. viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
  48. R.anim.slide_out_left));
  49. //显示前一个View
  50. viewFlipper.showNext();
  51. }
  52. returntrue;
  53. }
  54. returnfalse;
  55. }
  56. }

slide_in_right.xml
Html代码
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <setxmlns:android="http://schemas.android.com/apk/res/android">
  3. <translateandroid:fromXDelta="50%p"android:toXDelta="0"android:duration="300"/>
  4. <alphaandroid:fromAlpha="0.0"android:toAlpha="1.0"android:duration="300"/>
  5. </set>

slide_out_left.xml
Html代码
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <setxmlns:android="http://schemas.android.com/apk/res/android">
  3. <translateandroid:fromXDelta="0"android:toXDelta="-50%p"android:duration="300"/>
  4. <alphaandroid:fromAlpha="1.0"android:toAlpha="0.0"android:duration="300"/>
  5. </set>

上面的例子是在布局文件中为ViewFlipper固定添加了两个View,如果现在有N个View怎么办呢?那么我们就需要在Java代码里面动态的添加View

先上代码再讲解

main.xml

Html代码
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical">
  6. <com.tianjf.MyViewFlipper
  7. android:id="@+id/myViewFlipper"
  8. android:layout_width="fill_parent"
  9. android:layout_height="fill_parent"
  10. android:background="@android:color/white"
  11. android:gravity="center">
  12. </com.tianjf.MyViewFlipper>
  13. </LinearLayout>

flipper_view.xml
Html代码
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <ScrollViewxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:scrollbars="none">
  6. <LinearLayout
  7. android:layout_width="fill_parent"
  8. android:layout_height="wrap_content"
  9. android:gravity="center"
  10. android:orientation="vertical">
  11. <ImageView
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"
  14. android:src="@drawable/ic_launcher"/>
  15. <TextView
  16. android:id="@+id/textView"
  17. android:textSize="100dip"
  18. android:layout_width="wrap_content"
  19. android:layout_height="wrap_content"/>
  20. </LinearLayout>
  21. </ScrollView>

MyGestureListener.java

Java代码
  1. packagecom.tianjf;
  2. importandroid.view.GestureDetector.SimpleOnGestureListener;
  3. importandroid.view.MotionEvent;
  4. publicclassMyGestureListenerextendsSimpleOnGestureListener{
  5. privateOnFlingListenermOnFlingListener;
  6. publicOnFlingListenergetOnFlingListener(){
  7. returnmOnFlingListener;
  8. }
  9. publicvoidsetOnFlingListener(OnFlingListenermOnFlingListener){
  10. this.mOnFlingListener=mOnFlingListener;
  11. }
  12. @Override
  13. publicfinalbooleanonFling(finalMotionEvente1,finalMotionEvente2,
  14. finalfloatspeedX,finalfloatspeedY){
  15. if(mOnFlingListener==null){
  16. returnsuper.onFling(e1,e2,speedX,speedY);
  17. }
  18. floatXFrom=e1.getX();
  19. floatXTo=e2.getX();
  20. floatYFrom=e1.getY();
  21. floatYTo=e2.getY();
  22. //左右滑动的X轴幅度大于100,并且X轴方向的速度大于100
  23. if(Math.abs(XFrom-XTo)>100.0f&&Math.abs(speedX)>100.0f){
  24. //X轴幅度大于Y轴的幅度
  25. if(Math.abs(XFrom-XTo)>=Math.abs(YFrom-YTo)){
  26. if(XFrom>XTo){
  27. //下一个
  28. mOnFlingListener.flingToNext();
  29. }else{
  30. //上一个
  31. mOnFlingListener.flingToPrevious();
  32. }
  33. }
  34. }else{
  35. returnfalse;
  36. }
  37. returntrue;
  38. }
  39. publicinterfaceOnFlingListener{
  40. voidflingToNext();
  41. voidflingToPrevious();
  42. }
  43. }

MyViewFlipper.java

Java代码
  1. packagecom.tianjf;
  2. importcom.tianjf.MyGestureListener.OnFlingListener;
  3. importandroid.content.Context;
  4. importandroid.util.AttributeSet;
  5. importandroid.view.GestureDetector;
  6. importandroid.view.MotionEvent;
  7. importandroid.view.View;
  8. importandroid.widget.ViewFlipper;
  9. publicclassMyViewFlipperextendsViewFlipperimplementsOnFlingListener{
  10. privateGestureDetectormGestureDetector=null;
  11. privateOnViewFlipperListenermOnViewFlipperListener=null;
  12. publicMyViewFlipper(Contextcontext){
  13. super(context);
  14. }
  15. publicMyViewFlipper(Contextcontext,AttributeSetattrs){
  16. super(context,attrs);
  17. }
  18. publicvoidsetOnViewFlipperListener(OnViewFlipperListenermOnViewFlipperListener){
  19. this.mOnViewFlipperListener=mOnViewFlipperListener;
  20. MyGestureListenermyGestureListener=newMyGestureListener();
  21. myGestureListener.setOnFlingListener(this);
  22. mGestureDetector=newGestureDetector(myGestureListener);
  23. }
  24. @Override
  25. publicbooleanonInterceptTouchEvent(MotionEventev){
  26. if(null!=mGestureDetector){
  27. returnmGestureDetector.onTouchEvent(ev);
  28. }else{
  29. returnsuper.onInterceptTouchEvent(ev);
  30. }
  31. }
  32. @Override
  33. publicvoidflingToNext(){
  34. if(null!=mOnViewFlipperListener){
  35. intchildCnt=getChildCount();
  36. if(childCnt==2){
  37. removeViewAt(1);
  38. }
  39. addView(mOnViewFlipperListener.getNextView(),0);
  40. if(0!=childCnt){
  41. setInAnimation(getContext(),R.anim.left_slip_in);
  42. setOutAnimation(getContext(),R.anim.left_slip_out);
  43. setDisplayedChild(0);
  44. }
  45. }
  46. }
  47. @Override
  48. publicvoidflingToPrevious(){
  49. if(null!=mOnViewFlipperListener){
  50. intchildCnt=getChildCount();
  51. if(childCnt==2){
  52. removeViewAt(1);
  53. }
  54. addView(mOnViewFlipperListener.getPreviousView(),0);
  55. if(0!=childCnt){
  56. setInAnimation(getContext(),R.anim.right_slip_in);
  57. setOutAnimation(getContext(),R.anim.right_slip_out);
  58. setDisplayedChild(0);
  59. }
  60. }
  61. }
  62. publicinterfaceOnViewFlipperListener{
  63. ViewgetNextView();
  64. ViewgetPreviousView();
  65. }
  66. }

ViewFlipperDemoActivity.java
Java代码
  1. packagecom.tianjf;
  2. importcom.tianjf.MyViewFlipper.OnViewFlipperListener;
  3. importandroid.app.Activity;
  4. importandroid.os.Bundle;
  5. importandroid.view.LayoutInflater;
  6. importandroid.view.View;
  7. importandroid.widget.ScrollView;
  8. importandroid.widget.TextView;
  9. publicclassViewFlipperDemoActivityextendsActivityimplementsOnViewFlipperListener{
  10. privateMyViewFlippermyViewFlipper;
  11. privateintcurrentNumber;
  12. @Override
  13. publicvoidonCreate(BundlesavedInstanceState){
  14. super.onCreate(savedInstanceState);
  15. setContentView(R.layout.main);
  16. currentNumber=1;
  17. myViewFlipper=(MyViewFlipper)findViewById(R.id.myViewFlipper);
  18. myViewFlipper.setOnViewFlipperListener(this);
  19. myViewFlipper.addView(creatView(currentNumber));
  20. }
  21. @Override
  22. publicViewgetNextView(){
  23. currentNumber=currentNumber==10?1:currentNumber+1;
  24. returncreatView(currentNumber);
  25. }
  26. @Override
  27. publicViewgetPreviousView(){
  28. currentNumber=currentNumber==1?10:currentNumber-1;
  29. returncreatView(currentNumber);
  30. }
  31. privateViewcreatView(intcurrentNumber){
  32. LayoutInflaterlayoutInflater=LayoutInflater.from(this);
  33. ScrollViewresultView=(ScrollView)layoutInflater.inflate(R.layout.flipper_view,null);
  34. ((TextView)resultView.findViewById(R.id.textView)).setText(currentNumber+"");
  35. returnresultView;
  36. }
  37. }

好了,代码上完了,开始讲解!

ViewFilpper的showPrevious()方法和showNext()方法是用来显示已经在布局文件中定义好了的View,现在我们没有在布局文件中为ViewFlipper添加View,那么showPrevious()方法和showNext()方法就不能用了。但是我们怎么实现滑动来切换View呢?用什么方法呢?

这时候,我们就要自定义一个MyViewFlipper来监听滑动事件,并做切换视图的处理。

你可以让MyViewFlipper实现OnTouchListener接口,然后实现onTouch方法,然后根据MotionEvent.ACTION_DOWN和MotionEvent.ACTION_UP的坐标判断是不是滑动事件,就像ImageSwitcher中讲解的那样(http://blog.csdn.net/tianjf0514/article/details/7556487)

除了自己判断是不是滑动事件,那么Android有没有直接提供哪个方法作为滑动事件的回调函数呢?答案是:提供了。OnGestureListener中的onFling方法就是滑动事件的回调函数。这时候你也许会毫不犹豫的让MyViewFlipper实现OnGestureListener接口,并复写onFling方法。这样做当然可以,不过实现OnGestureListener接口不仅仅要复写onFling方法,还要复写其他的方法(onDown()、onShowPress()、onSingleTapUp()、onScroll()、onLongPress()),但是这些回调函数我们不需要,这就造成了垃圾代码。

为了避免垃圾代码,Android提供了一个类SimpleOnGestureListener已经实现了OnGestureListener接口和OnDoubleTapListener接口,并复写了所有方法。那么我们只要新建一个自己的MyGestureListener.java来继承SimpleOnGestureListener,并有选择性的复写需要的方法(我们在此只复写onFling方法)。

这时,我们就自定义了一个手势类,并且这个手势类会监听滑动事件来做一些处理。但是我们怎么利用这个手势类呢?怎么利用到MyViewFlipper类中去呢?

关于onFling方法,有一点要注意:不是每个View都能有onFling回调函数,一开始,我的flipper_view.xml布局文件最外层是一个LinearLayout,死活都走不到onFling方法,后来在外层又套了一个ScrollView,就能正常走到OnFling方法里面了。

可以看到flingToNext方法和flingToPrevious方法里面会判断childCnt,如果为2,就removeViewAt(1);,然后再addView(mOnViewFlipperListener.getNextView(), 0);。这就要回顾一下ImageSwitcher的原理,ViewFlipper的原理和ImageSwitcher一样,有且仅有2个子View,滑动时候就在这两个子View上来回切换。index为0的就是当前看到的,index为1的就是看不见的。上面代码的意思就是:当滑动时,必然要新添加一个View,那么子View的个数有可能大于2,随意要先判断一下如果childCnt == 2,那么就把index == 1的那个View(即看不见的View)给Remove调,然后把新添加的View添加到index == 0处。这样可以减少内存消耗。


OK,这个例子的基本的注意点已经讲完了。下面在系统的回顾一下这个例子的具体流程。

在我们滑动手机屏幕的时候(假设我们从右往左滑动),那么应该显示下一个View。

  1. 调用onFling方法中的mOnFlingListener.flingToNext();
  2. flingToNext方法的是实现在MyViewFlipper类中,调用flingToNext方法的addView(mOnViewFlipperListener.getNextView(), 0);
  3. getNextView的实现在ViewFlipperDemoActivity类中

好的,讲完了,要想完全理解透彻,跑跑例子,理解理解。



更多相关文章

  1. Android控件之Spinner用法详解
  2. Android(第三种动画)属性动画完全解析(上),初识属性动画的基本用法
  3. Android(安卓)focus search returned a view that wasn't able t
  4. 探究Android(安卓)View 绘制流程,Canvas 的由来。
  5. Android一年工作经验应掌握的知识点
  6. Android(安卓)ContentProvider学习
  7. android中selector改变界面状态用法小结
  8. android关闭其他app
  9. 在Android(安卓)Jar包使用图片资源的解决方法

随机推荐

  1. Android ViewPager中嵌套Banner 导致水平
  2. Android服务器端开发
  3. Android 如何在Java代码中手动设置控件的
  4. Android 自动换行流式布局的RadioGroup
  5. android view相对于根布局的坐标获取
  6. Android腾讯微博客户端开发四:微博发送篇
  7. android 4.2版本的sdcard文件目录分析
  8. 捕获Android文本输入框的软键盘完成(Done
  9. Stopping ADB server failed(code -1)安
  10. Android(安卓)2.2 SDK操作系统界面截屏抢