关闭

ViewAnimator 之(二)ViewFlipper

394人阅读 评论(0) 收藏 举报
分类:


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

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

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

先看一下结构图


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


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

main.xml

  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:orientation="vertical" >  
  6.   
  7.     <ViewFlipper  
  8.         android:id="@+id/viewFlipper"  
  9.         android:layout_width="fill_parent"  
  10.         android:layout_height="fill_parent" >  
  11.   
  12.         <include  
  13.             android:id="@+id/layout01"  
  14.             layout="@layout/layout01" />  
  15.   
  16.         <include  
  17.             android:id="@+id/layout02"  
  18.             layout="@layout/layout02" />  
  19.     </ViewFlipper>  
  20.   
  21. </LinearLayout>  

layout01.xml

  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:orientation="vertical" >  
  6.   
  7.     <TextView  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="fill_parent"  
  10.         android:gravity="center"  
  11.         android:text="一个TextView"  
  12.         android:textSize="40dip" />  
  13.   
  14. </LinearLayout>  

layout02.xml

  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:orientation="vertical" >  
  6.   
  7.     <LinearLayout  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="fill_parent"  
  10.         android:gravity="center"  
  11.         android:orientation="vertical" >  
  12.   
  13.         <ImageView  
  14.             android:layout_width="wrap_content"  
  15.             android:layout_height="wrap_content"  
  16.             android:src="@drawable/ic_launcher" />  
  17.   
  18.         <TextView  
  19.             android:layout_width="wrap_content"  
  20.             android:layout_height="wrap_content"  
  21.             android:text="一个TextView + 一个ImageView"  
  22.             android:textSize="20dip" />  
  23.     </LinearLayout>  
  24.   
  25. </LinearLayout>  

ViewFlipperDemoActivity.java

  1. package com.tianjf;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.view.MotionEvent;  
  6. import android.view.View;  
  7. import android.view.View.OnTouchListener;  
  8. import android.view.animation.AnimationUtils;  
  9. import android.widget.ViewFlipper;  
  10.   
  11. public class ViewFlipperDemoActivity extends Activity implements  
  12.         OnTouchListener {  
  13.   
  14.     private ViewFlipper viewFlipper;  
  15.   
  16.     // 左右滑动时手指按下的X坐标  
  17.     private float touchDownX;  
  18.     // 左右滑动时手指松开的X坐标  
  19.     private float touchUpX;  
  20.   
  21.     @Override  
  22.     public void onCreate(Bundle savedInstanceState) {  
  23.         super.onCreate(savedInstanceState);  
  24.         setContentView(R.layout.main);  
  25.   
  26.         viewFlipper = (ViewFlipper) findViewById(R.id.viewFlipper);  
  27.         viewFlipper.setOnTouchListener(this);  
  28.     }  
  29.   
  30.     @Override  
  31.     public boolean onTouch(View v, MotionEvent event) {  
  32.         if (event.getAction() == MotionEvent.ACTION_DOWN) {  
  33.             // 取得左右滑动时手指按下的X坐标  
  34.             touchDownX = event.getX();  
  35.             return true;  
  36.         } else if (event.getAction() == MotionEvent.ACTION_UP) {  
  37.             // 取得左右滑动时手指松开的X坐标  
  38.             touchUpX = event.getX();  
  39.             // 从左往右,看前一个View  
  40.             if (touchUpX - touchDownX > 100) {  
  41.                 // 设置View切换的动画  
  42.                 viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,  
  43.                         android.R.anim.slide_in_left));  
  44.                 viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,  
  45.                         android.R.anim.slide_out_right));  
  46.                 // 显示前一个View  
  47.                 viewFlipper.showPrevious();  
  48.                 // 从右往左,看后一个View  
  49.             } else if (touchDownX - touchUpX > 100) {  
  50.                 // 设置View切换的动画  
  51.                 // 由于Android没有提供slide_out_left和slide_in_right,所以仿照slide_in_left和slide_out_right编写了slide_out_left和slide_in_right  
  52.                 viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,  
  53.                         R.anim.slide_in_right));  
  54.                 viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,  
  55.                         R.anim.slide_out_left));  
  56.                 // 显示下一个View  
  57.                 viewFlipper.showNext();  
  58.             }  
  59.             return true;  
  60.         }  
  61.         return false;  
  62.     }  
  63. }  

slide_in_right.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <set xmlns:android="http://schemas.android.com/apk/res/android">  
  3.     <translate android:fromXDelta="50%p" android:toXDelta="0" android:duration="300"/>  
  4.     <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" />  
  5. </set>  

slide_out_left.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <set xmlns:android="http://schemas.android.com/apk/res/android">  
  3.     <translate android:fromXDelta="0" android:toXDelta="-50%p" android:duration="300"/>  
  4.     <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="300" />  
  5. </set>  

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

先上代码再讲解

main.xml

  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:orientation="vertical" >  
  6.   
  7.     <com.tianjf.MyViewFlipper  
  8.         android:id="@+id/myViewFlipper"  
  9.         android:layout_width="fill_parent"  
  10.         android:layout_height="fill_parent"  
  11.         android:background="@android:color/white"  
  12.         android:gravity="center" >  
  13.     </com.tianjf.MyViewFlipper>  
  14.   
  15. </LinearLayout>  

flipper_view.xml
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <ScrollView xmlns: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.   
  7.     <LinearLayout  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="wrap_content"  
  10.         android:gravity="center"  
  11.         android:orientation="vertical" >  
  12.   
  13.         <ImageView  
  14.             android:layout_width="wrap_content"  
  15.             android:layout_height="wrap_content"  
  16.             android:src="@drawable/ic_launcher" />  
  17.   
  18.         <TextView  
  19.             android:id="@+id/textView"  
  20.             android:textSize="100dip"  
  21.             android:layout_width="wrap_content"  
  22.             android:layout_height="wrap_content" />  
  23.     </LinearLayout>  
  24.   
  25. </ScrollView>  

MyGestureListener.java

  1. package com.tianjf;  
  2.   
  3. import android.view.GestureDetector.SimpleOnGestureListener;  
  4. import android.view.MotionEvent;  
  5.   
  6. public class MyGestureListener extends SimpleOnGestureListener {  
  7.       
  8.     private OnFlingListener mOnFlingListener;  
  9.   
  10.     public OnFlingListener getOnFlingListener() {  
  11.         return mOnFlingListener;  
  12.     }  
  13.   
  14.     public void setOnFlingListener(OnFlingListener mOnFlingListener) {  
  15.         this.mOnFlingListener = mOnFlingListener;  
  16.     }  
  17.   
  18.     @Override  
  19.     public final boolean onFling(final MotionEvent e1, final MotionEvent e2,  
  20.             final float speedX, final float speedY) {  
  21.         if (mOnFlingListener == null) {  
  22.             return super.onFling(e1, e2, speedX, speedY);  
  23.         }  
  24.   
  25.         float XFrom = e1.getX();  
  26.         float XTo = e2.getX();  
  27.         float YFrom = e1.getY();  
  28.         float YTo = e2.getY();  
  29.         // 左右滑动的X轴幅度大于100,并且X轴方向的速度大于100  
  30.         if (Math.abs(XFrom - XTo) > 100.0f && Math.abs(speedX) > 100.0f) {  
  31.             // X轴幅度大于Y轴的幅度  
  32.             if (Math.abs(XFrom - XTo) >= Math.abs(YFrom - YTo)) {  
  33.                 if (XFrom > XTo) {  
  34.                     // 下一个  
  35.                     mOnFlingListener.flingToNext();  
  36.                 } else {  
  37.                     // 上一个  
  38.                     mOnFlingListener.flingToPrevious();  
  39.                 }  
  40.             }  
  41.         } else {  
  42.             return false;  
  43.         }  
  44.         return true;  
  45.     }  
  46.   
  47.     public interface OnFlingListener {  
  48.         void flingToNext();  
  49.   
  50.         void flingToPrevious();  
  51.     }  
  52. }  

MyViewFlipper.java

  1. package com.tianjf;  
  2.   
  3. import com.tianjf.MyGestureListener.OnFlingListener;  
  4.   
  5. import android.content.Context;  
  6. import android.util.AttributeSet;  
  7. import android.view.GestureDetector;  
  8. import android.view.MotionEvent;  
  9. import android.view.View;  
  10. import android.widget.ViewFlipper;  
  11.   
  12. public class MyViewFlipper extends ViewFlipper implements OnFlingListener {  
  13.   
  14.     private GestureDetector mGestureDetector = null;  
  15.   
  16.     private OnViewFlipperListener mOnViewFlipperListener = null;  
  17.   
  18.     public MyViewFlipper(Context context) {  
  19.         super(context);  
  20.     }  
  21.   
  22.     public MyViewFlipper(Context context, AttributeSet attrs) {  
  23.         super(context, attrs);  
  24.     }  
  25.   
  26.     public void setOnViewFlipperListener(OnViewFlipperListener mOnViewFlipperListener) {  
  27.         this.mOnViewFlipperListener = mOnViewFlipperListener;  
  28.         MyGestureListener myGestureListener = new MyGestureListener();  
  29.         myGestureListener.setOnFlingListener(this);  
  30.         mGestureDetector = new GestureDetector(myGestureListener);  
  31.     }  
  32.   
  33.     @Override  
  34.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  35.         if (null != mGestureDetector) {  
  36.             return mGestureDetector.onTouchEvent(ev);  
  37.         } else {  
  38.             return super.onInterceptTouchEvent(ev);  
  39.         }  
  40.     }  
  41.   
  42.     @Override  
  43.     public void flingToNext() {  
  44.         if (null != mOnViewFlipperListener) {  
  45.             int childCnt = getChildCount();  
  46.             if (childCnt == 2) {  
  47.                 removeViewAt(1);  
  48.             }  
  49.             addView(mOnViewFlipperListener.getNextView(), 0);  
  50.             if (0 != childCnt) {  
  51.                 setInAnimation(getContext(), R.anim.left_slip_in);  
  52.                 setOutAnimation(getContext(), R.anim.left_slip_out);  
  53.                 setDisplayedChild(0);  
  54.             }  
  55.         }  
  56.     }  
  57.   
  58.     @Override  
  59.     public void flingToPrevious() {  
  60.         if (null != mOnViewFlipperListener) {  
  61.             int childCnt = getChildCount();  
  62.             if (childCnt == 2) {  
  63.                 removeViewAt(1);  
  64.             }  
  65.             addView(mOnViewFlipperListener.getPreviousView(), 0);  
  66.             if (0 != childCnt) {  
  67.                 setInAnimation(getContext(), R.anim.right_slip_in);  
  68.                 setOutAnimation(getContext(), R.anim.right_slip_out);  
  69.                 setDisplayedChild(0);  
  70.             }  
  71.         }  
  72.     }  
  73.   
  74.     public interface OnViewFlipperListener {  
  75.         View getNextView();  
  76.   
  77.         View getPreviousView();  
  78.     }  
  79. }  

ViewFlipperDemoActivity.java

  1. package com.tianjf;  
  2.   
  3. import com.tianjf.MyViewFlipper.OnViewFlipperListener;  
  4.   
  5. import android.app.Activity;  
  6. import android.os.Bundle;  
  7. import android.view.LayoutInflater;  
  8. import android.view.View;  
  9. import android.widget.ScrollView;  
  10. import android.widget.TextView;  
  11.   
  12. public class ViewFlipperDemoActivity extends Activity implements OnViewFlipperListener {  
  13.   
  14.     private MyViewFlipper myViewFlipper;  
  15.     private int currentNumber;  
  16.   
  17.     @Override  
  18.     public void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         setContentView(R.layout.main);  
  21.   
  22.         currentNumber = 1;  
  23.         myViewFlipper = (MyViewFlipper) findViewById(R.id.myViewFlipper);  
  24.         myViewFlipper.setOnViewFlipperListener(this);  
  25.         myViewFlipper.addView(creatView(currentNumber));  
  26.     }  
  27.   
  28.     @Override  
  29.     public View getNextView() {  
  30.         currentNumber = currentNumber == 10 ? 1 : currentNumber + 1;  
  31.         return creatView(currentNumber);  
  32.     }  
  33.   
  34.     @Override  
  35.     public View getPreviousView() {  
  36.         currentNumber = currentNumber == 1 ? 10 : currentNumber - 1;  
  37.         return creatView(currentNumber);  
  38.     }  
  39.   
  40.     private View creatView(int currentNumber) {  
  41.         LayoutInflater layoutInflater = LayoutInflater.from(this);  
  42.         ScrollView resultView = (ScrollView) layoutInflater.inflate(R.layout.flipper_view, null);  
  43.         ((TextView) resultView.findViewById(R.id.textView)).setText(currentNumber + "");  
  44.         return resultView;  
  45.     }  
  46. }  

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

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类中
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:571552次
    • 积分:7128
    • 等级:
    • 排名:第3254名
    • 原创:88篇
    • 转载:365篇
    • 译文:0篇
    • 评论:80条
    最新评论