zoukankan      html  css  js  c++  java
  • Android学习笔记_21_ViewFlipper使用详解 手势识别器

    一、介绍ViewFilpper类

    1.1 屏幕切换

        屏幕切换指的是在同一个Activity内屏幕见的切换,最长见的情况就是在一个FrameLayout内有多个页面,比如一个系统设置页面;一个个性化设置页面。

    1.2 ViewFilpper类

         ViewFlipper extends ViewAnimator

     

    java.lang.Object
       ↳ android.view.View
         ↳ android.view.ViewGroup
           ↳ android.widget.FrameLayout
             ↳ android.widget.ViewAnimator
               ↳ android.widget.ViewFlipper

    Class Overview

    Simple ViewAnimator that will animate between two or more views that have been added to it. Only one child is shown at a time. If requested, can automatically flip between each child at a regular interval.

        意思是:简单的ViewAnimator之间,两个或两个以上的view加上动画效果。只有一个小孩会显示在一个时间。如果需要,每个孩子能自动翻转之间在固定的时间间隔。

       该类继承了Framelayout类,ViewAnimator类的作用是为FrameLayout里面的View切换提供动画效果。
       该类有如下几个和动画相关的函数:

       setInAnimation:设置View进入屏幕时候使用的动画,该函数有两个版本,一个接受单个参数,类型为android.view.animation.Animation;一个接受两个参数,类型为Context和int,分别为Context对象和定义Animation的resourceID。  

       setOutAnimation: 设置View退出屏幕时候使用的动画,参数setInAnimation函数一样。

       showNext: 调用该函数来显示FrameLayout里面的下一个View。

       showPrevious: 调用该函数来显示FrameLayout里面的上一个View。

        简单ViewFlipper的应用

    二、ViewFlipper复杂应用

    2.1 动态添加多个View

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

    main.xml

    <?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
        android:orientation="vertical" > 
     
        <ViewFlipper 
            android:id="@+id/viewFlipper" 
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent" > 
     
            <include 
                android:id="@+id/layout01" 
                layout="@layout/layout01" /> 
     
            <include 
                android:id="@+id/layout02" 
                layout="@layout/layout02" /> 
        </ViewFlipper> 
     
    </LinearLayout> 

      layout01.xml

    <?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
        android:orientation="vertical" > 
     
        <TextView 
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent" 
            android:gravity="center" 
            android:text="一个TextView" 
            android:textSize="40dip" /> 
     
    </LinearLayout> 

      layout02.xml

    <?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
        android:orientation="vertical" > 
     
        <LinearLayout 
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent" 
            android:gravity="center" 
            android:orientation="vertical" > 
     
            <ImageView 
                android:layout_width="wrap_content" 
                android:layout_height="wrap_content" 
                android:src="@drawable/ic_launcher" /> 
     
            <TextView 
                android:layout_width="wrap_content" 
                android:layout_height="wrap_content" 
                android:text="一个TextView + 一个ImageView" 
                android:textSize="20dip" /> 
        </LinearLayout> 
     
    </LinearLayout> 

      ViewFlipperDemoActivity.java

    package com.tianjf; 
     
    import android.app.Activity; 
    import android.os.Bundle; 
    import android.view.MotionEvent; 
    import android.view.View; 
    import android.view.View.OnTouchListener; 
    import android.view.animation.AnimationUtils; 
    import android.widget.ViewFlipper; 
     
    public class ViewFlipperDemoActivity extends Activity implements 
            OnTouchListener { 
     
        private ViewFlipper viewFlipper; 
     
        // 左右滑动时手指按下的X坐标 
        private float touchDownX; 
        // 左右滑动时手指松开的X坐标 
        private float touchUpX; 
     
        @Override 
        public void onCreate(Bundle savedInstanceState) { 
            super.onCreate(savedInstanceState); 
            setContentView(R.layout.main); 
     
            viewFlipper = (ViewFlipper) findViewById(R.id.viewFlipper); 
            viewFlipper.setOnTouchListener(this); 
        } 
     
        @Override 
        public boolean onTouch(View v, MotionEvent event) { 
            if (event.getAction() == MotionEvent.ACTION_DOWN) { 
                // 取得左右滑动时手指按下的X坐标 
                touchDownX = event.getX(); 
                return true; 
            } else if (event.getAction() == MotionEvent.ACTION_UP) { 
                // 取得左右滑动时手指松开的X坐标 
                touchUpX = event.getX(); 
                // 从左往右,看前一个View 
                if (touchUpX - touchDownX > 100) { 
                    // 设置View切换的动画 
                    viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this, 
                            android.R.anim.slide_in_left)); 
                    viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, 
                            android.R.anim.slide_out_right)); 
                    // 显示下一个View 
                    viewFlipper.showPrevious(); 
                    // 从右往左,看后一个View 
                } else if (touchDownX - touchUpX > 100) { 
                    // 设置View切换的动画 
                    // 由于Android没有提供slide_out_left和slide_in_right,所以仿照slide_in_left和slide_out_right编写了slide_out_left和slide_in_right 
                    viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this, 
                            R.anim.slide_in_right)); 
                    viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, 
                            R.anim.slide_out_left)); 
                    // 显示前一个View 
                    viewFlipper.showNext(); 
                } 
                return true; 
            } 
            return false; 
        } 
    } 

      slide_in_right.xml

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

      slide_out_left.xml

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

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

      main.xml布局文件

    <?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
        android:orientation="vertical" > 
     
        <com.tianjf.MyViewFlipper 
            android:id="@+id/myViewFlipper" 
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent" 
            android:background="@android:color/white" 
            android:gravity="center" > 
        </com.tianjf.MyViewFlipper> 
     
    </LinearLayout> 

        flipper_view.xml布局文件

    <?xml version="1.0" encoding="utf-8"?> 
    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
        android:scrollbars="none" > 
     
        <LinearLayout 
            android:layout_width="fill_parent" 
            android:layout_height="wrap_content" 
            android:gravity="center" 
            android:orientation="vertical" > 
     
            <ImageView 
                android:layout_width="wrap_content" 
                android:layout_height="wrap_content" 
                android:src="@drawable/ic_launcher" /> 
     
            <TextView 
                android:id="@+id/textView" 
                android:textSize="100dip" 
                android:layout_width="wrap_content" 
                android:layout_height="wrap_content" /> 
        </LinearLayout> 
     
    </ScrollView> 
    package com.tianjf; 
     
    import android.view.GestureDetector.SimpleOnGestureListener; 
    import android.view.MotionEvent; 
     
    public class MyGestureListener extends SimpleOnGestureListener { 
         
        private OnFlingListener mOnFlingListener; 
     
        public OnFlingListener getOnFlingListener() { 
            return mOnFlingListener; 
        } 
     
        public void setOnFlingListener(OnFlingListener mOnFlingListener) { 
            this.mOnFlingListener = mOnFlingListener; 
        } 
     
        @Override 
        public final boolean onFling(final MotionEvent e1, final MotionEvent e2, 
                final float speedX, final float speedY) { 
            if (mOnFlingListener == null) { 
                return super.onFling(e1, e2, speedX, speedY); 
            } 
     
            float XFrom = e1.getX(); 
            float XTo = e2.getX(); 
            float YFrom = e1.getY(); 
            float YTo = e2.getY(); 
            // 左右滑动的X轴幅度大于100,并且X轴方向的速度大于100 
            if (Math.abs(XFrom - XTo) > 100.0f && Math.abs(speedX) > 100.0f) { 
                // X轴幅度大于Y轴的幅度 
                if (Math.abs(XFrom - XTo) >= Math.abs(YFrom - YTo)) { 
                    if (XFrom > XTo) { 
                        // 下一个 
                        mOnFlingListener.flingToNext(); 
                    } else { 
                        // 上一个 
                        mOnFlingListener.flingToPrevious(); 
                    } 
                } 
            } else { 
                return false; 
            } 
            return true; 
        } 
     
        public interface OnFlingListener { 
            void flingToNext(); 
     
            void flingToPrevious(); 
        } 
    } 
    MyViewFlipper.java
    [java]
    package com.tianjf; 
     
    import com.tianjf.MyGestureListener.OnFlingListener; 
     
    import android.content.Context; 
    import android.util.AttributeSet; 
    import android.view.GestureDetector; 
    import android.view.MotionEvent; 
    import android.view.View; 
    import android.widget.ViewFlipper; 
     
    public class MyViewFlipper extends ViewFlipper implements OnFlingListener { 
     
        private GestureDetector mGestureDetector = null; 
     
        private OnViewFlipperListener mOnViewFlipperListener = null; 
     
        public MyViewFlipper(Context context) { 
            super(context); 
        } 
     
        public MyViewFlipper(Context context, AttributeSet attrs) { 
            super(context, attrs); 
        } 
     
        public void setOnViewFlipperListener(OnViewFlipperListener mOnViewFlipperListener) { 
            this.mOnViewFlipperListener = mOnViewFlipperListener; 
            MyGestureListener myGestureListener = new MyGestureListener(); 
            myGestureListener.setOnFlingListener(this); 
            mGestureDetector = new GestureDetector(myGestureListener); 
        } 
     
        @Override 
        public boolean onInterceptTouchEvent(MotionEvent ev) { 
            if (null != mGestureDetector) { 
                return mGestureDetector.onTouchEvent(ev); 
            } else { 
                return super.onInterceptTouchEvent(ev); 
            } 
        } 
     
        @Override 
        public void flingToNext() { 
            if (null != mOnViewFlipperListener) { 
                int childCnt = getChildCount(); 
                if (childCnt == 2) { 
                    removeViewAt(1); 
                } 
                addView(mOnViewFlipperListener.getNextView(), 0); 
                if (0 != childCnt) { 
                    setInAnimation(getContext(), R.anim.left_slip_in); 
                    setOutAnimation(getContext(), R.anim.left_slip_out); 
                    setDisplayedChild(0); 
                } 
            } 
        } 
     
        @Override 
        public void flingToPrevious() { 
            if (null != mOnViewFlipperListener) { 
                int childCnt = getChildCount(); 
                if (childCnt == 2) { 
                    removeViewAt(1); 
                } 
                addView(mOnViewFlipperListener.getPreviousView(), 0); 
                if (0 != childCnt) { 
                    setInAnimation(getContext(), R.anim.right_slip_in); 
                    setOutAnimation(getContext(), R.anim.right_slip_out); 
                    setDisplayedChild(0); 
                } 
            } 
        } 
     
        public interface OnViewFlipperListener { 
            View getNextView(); 
     
            View getPreviousView(); 
        } 
    } 
    
    ViewFlipperDemoActivity.java
    [java]
    package com.tianjf; 
     
    import com.tianjf.MyViewFlipper.OnViewFlipperListener; 
     
    import android.app.Activity; 
    import android.os.Bundle; 
    import android.view.LayoutInflater; 
    import android.view.View; 
    import android.widget.ScrollView; 
    import android.widget.TextView; 
     
    public class ViewFlipperDemoActivity extends Activity implements OnViewFlipperListener { 
     
        private MyViewFlipper myViewFlipper; 
        private int currentNumber; 
     
        @Override 
        public void onCreate(Bundle savedInstanceState) { 
            super.onCreate(savedInstanceState); 
            setContentView(R.layout.main); 
     
            currentNumber = 1; 
            myViewFlipper = (MyViewFlipper) findViewById(R.id.myViewFlipper); 
            myViewFlipper.setOnViewFlipperListener(this); 
            myViewFlipper.addView(creatView(currentNumber)); 
        } 
     
        @Override 
        public View getNextView() { 
            currentNumber = currentNumber == 10 ? 1 : currentNumber + 1; 
            return creatView(currentNumber); 
        } 
     
        @Override 
        public View getPreviousView() { 
            currentNumber = currentNumber == 1 ? 10 : currentNumber - 1; 
            return creatView(currentNumber); 
        } 
     
        private View creatView(int currentNumber) { 
            LayoutInflater layoutInflater = LayoutInflater.from(this); 
            ScrollView resultView = (ScrollView) layoutInflater.inflate(R.layout.flipper_view, null); 
            ((TextView) resultView.findViewById(R.id.textView)).setText(currentNumber + ""); 
            return resultView; 
        } 
    } 
      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。
    调用onFling方法中的mOnFlingListener.flingToNext();
    flingToNext方法的是实现在MyViewFlipper类中,调用flingToNext方法的addView(mOnViewFlipperListener.getNextView(), 0);
    getNextView的实现在ViewFlipperDemoActivity类中

    1.3  手势识别器

      

    public class DemoActivity extends Activity {
    ViewFlipper vf;
    //手势识别的帮助类 
    GestureDetector  mGestureDetector ;
        
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            vf = (ViewFlipper) this.findViewById(R.id.vf);
            TextView tv1 = new TextView(this);
            tv1.setText("第一个界面");
            ImageView iv2 = new ImageView(this);
            iv2.setImageResource(R.drawable.ic_launcher);
            TextView tv3 = new TextView(this);
            tv3.setText("第三个界面");
            
            vf.addView(tv1);
            vf.addView(iv2);
            vf.addView(tv3);
            mGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener(){
    
                //e1:手指进入屏幕事件,e2:手指离开屏幕事件。
                @Override
                public boolean onFling(MotionEvent e1, MotionEvent e2,
                        float velocityX, float velocityY) {
                
                    if( Math.abs(e1.getY()-e2.getY()) > 100){
                        //垂直方向变化过大 无效事件
                        return false;
                    }
                    if( e1.getX() - e2.getX() > 100 && Math.abs(velocityX)>100)
                    {
                        
                        showpre();
                        return false;
                    }
                    if( e2.getX() - e1.getX() > 100 && Math.abs(velocityX)>100 )
                    {
                        
                        shownext();
                        
                        return false;
                    }
                    
                    return super.onFling(e1, e2, velocityX, velocityY);
                }
                
                
                
            });
            
            
        }
        public void pre(View view){
            showpre();
        }
        private void showpre() {
            vf.showPrevious();
            AlphaAnimation inaa = new AlphaAnimation(0.0f, 1.0f);
            inaa.setDuration(1000);
            vf.setInAnimation(inaa);
            AlphaAnimation outaa = new AlphaAnimation(1.0f, 0.0f);
            outaa.setDuration(1000);
            vf.setOutAnimation(outaa);
        }
        public void next(View view){
            shownext();
        }
        private void shownext() {
            vf.showNext();
            AlphaAnimation inaa = new AlphaAnimation(0.0f, 1.0f);
            inaa.setDuration(1000);
            vf.setInAnimation(inaa);
            AlphaAnimation outaa = new AlphaAnimation(1.0f, 0.0f);
            outaa.setDuration(1000);
            vf.setOutAnimation(outaa);
        }
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            
            // 把当前屏幕触摸的事件 传递个手势识别器 
            mGestureDetector.onTouchEvent(event);
            //有的时候 消费掉 触摸事件 (防止事件层层传递)
            //return true;
            // 控制当前的事件 是否让(上层框架)系统的框架 默认处理 
            return super.onTouchEvent(event);
        }
    }
  • 相关阅读:
    【原创】InstallSheild使用问题笔记卸载程序之后重新启动,总是报错找不到文件?
    【学习】关于绩效管理的知识
    【原创】Asp.net MVC学习笔记之基于类型来绑定Model的属性
    【学习】如何进行绩效面谈
    【原创】【续】InstallSheild使用问题笔记卸载程序之后重新启动,总是报错找不到文件?
    SharePoint 2010 学习资料索引与注解(2)
    一张很厉害的图
    SharePoint 2010 学习资料索引与注解(1)
    StackOverflow 并不只是一个问答网站
    最近花了点儿时间看书学习
  • 原文地址:https://www.cnblogs.com/lbangel/p/3459829.html
Copyright © 2011-2022 走看看