Android中ViewFlipper详解

news/2024/8/26 12:30:07
Android中ViewFlipper详解

 前面已经讲过ImageSwitcher和TextSwitcher。ImageSwitcher用来切换ImageView的,TextSwitcher是用来切换TextView的。
但是我们现在要切换自定义View怎么办?
ImageSwitcher和TextSwitcher已经不能满足我们的需求。ViewFlipper可以在任意View之间切换。下面我们就来讲解它。
先看一下结构图

可以看到ViewSwitcher和ViewFlipper都是继承自ViewAnimator。
 
下面通过一个Demo了解一下ViewFlipper的用法
 

main.xml
[html] <?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
[html]
<?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
[html]
<?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
[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
[html]
<?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
[html]
<?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
[html]
<?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
[html]
<?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> 

MyGestureListener.java
[java]
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类中
好的,讲完了,要想完全理解透彻,跑跑例子,理解理解


http://www.niftyadmin.cn/n/1642241.html

相关文章

浏览器apk图标怎么放上去_多可手机APP怎么下载

多可手机APP不是一个独立的系统&#xff0c;需要和电脑端的多可系统配套使用。同时多可手机APP的下载也需要借助于电脑端的多可。01 找到下载页在电脑浏览器中打开多可系统。在首页的右下方有两个图标&#xff0c;分别是苹果系统和安卓系统的标识&#xff0c;点击他们就能找到A…

普通显示器开启freesync_入门也要240Hz起步!双旦节剁个入门电竞显示器犒劳自己...

我们一起又熬到每年荷包“最难受”的日子了。每年到了岁末这个时候&#xff0c;基本上大家都很关注几大电商哪家提供的优惠活动更吸引我们&#xff0c;哪家电商又发了多少福利&#xff0c;大家谁薅了多少羊毛等等。作为电脑中的保值三法宝(电源、机箱、显示器)&#xff0c;今年…

Android开源项目分类汇总【畜生级别】

Android开源项目分类汇总 欢迎大家推荐好的Android开源项目&#xff0c;可直接Commit或在 收集&提交页 中告诉我&#xff0c;欢迎Star、Fork :) 微博&#xff1a;Trinea 主页&#xff1a;www.trinea.cn 邮箱&#xff1a;trinea.cngmail.com QQ&#xff1a;7177637…

phpmyadmin能合并行吗_能介绍下福特野马历史吗?上一代2.0T的捷豹FTYPE行吗?

《问答》栏目是挑选部分来自公众号或微博的网友问题做解答&#xff0c;欢迎大家日后多多参与。dudy妈能简单介绍介绍福特野马历史吗&#xff1f;不管您是喜欢来自欧系超跑的激情&#xff0c;还是喜欢来自日系街车的内敛&#xff0c;更或是喜欢来自美系肌肉的疯狂。您都不可否认…

iframe嵌套html_如何成为一名前端开发之HTML入门

文末有福利前端开发&#xff0c;入门简单&#xff0c;有一台可以运行多款浏览器的电脑&#xff0c;能联网查询资料即可。深入的部分&#xff0c;需要更多的理论知识、肯钻研的精神。 前端开发&#xff0c;需要入门了解的屈指可数&#xff0c;主要就是如下几个大方面&#xff1a…

vb web客户端发送请求给winform服务端_套接字编程作业一:Web服务器

套接字编程作业一&#xff1a;Web服务器题目&#xff1a;在这个编程作业中&#xff0c;你将用Python语言开发一个简单的Web服务器&#xff0c;它仅能处理一个请求。具体而言&#xff0c;你的Web服务器将&#xff1a;当一个客户(浏览器)联系时创建一个连接套接字&#xff1b;从这…

qthread run结束了算销毁吗_韩国泡菜厂出现集体感染:50吨泡菜将全部销毁,其中40吨已流向市场.........

【环球网报道 记者 丁洁芸】韩国疫情近期出现反弹。据韩联社消息&#xff0c;忠清南道青阳郡一家泡菜厂出现集体感染&#xff0c;截至9月3日&#xff0c;包括泡菜厂员工和家属等在内的20人确诊感染新冠病毒。值得注意的是&#xff0c;该工厂近期生产的50吨泡菜将全部被销毁&…

android应用程序第一次启动时显示引导界面

市面上好多优秀的应用&#xff08;举例新浪微博、UC浏览器&#xff09;都采用了欢迎页面与使用向导的方式给用户带来了良好的用户体验。 一般来说用户第一次安装应用或者安装了新版本后第一次进入应用都会显示成 欢迎页面-使用向导-主界面 的方式 用户没有安装新版本或者不是第…