`
java-mans
  • 浏览: 11455763 次
文章分类
社区版块
存档分类
最新评论

Android中ViewFlipper详解

 
阅读更多

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

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

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

先看一下结构图


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


下面通过一个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>

MyGestureListener.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

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

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。

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

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





分享到:
评论

相关推荐

    Android中ViewFlipper的使用及设置动画效果实例详解

    主要介绍了Android中ViewFlipper的使用及设置动画效果的方法,以实例形式较为详细的分析了ViewFlipper的功能、原理及设置与使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下

    Android ViewFlipper的详解及实例

    主要介绍了Android ViewFlipper的详解及实例的相关资料,通过本文希望能帮助大家理解这部分内容,需要的朋友可以参考下

    《ViewFlipper使用详解》对应源码

    博客《ViewFlipper使用详解》对应源码,博客地址:http://blog.csdn.net/harvic880925/article/details/39585347

    Android ViewFlipper翻转视图使用详解

    主要为大家详细介绍了Android ViewFlipper翻转视图的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    解析Android中实现滑动翻页之ViewFlipper的使用详解

    有一些场景,我们需要向用户展示一系列的页面。比如我们正在开发一个看漫画的应用,可能就需要向用户展示一张一张的漫画图片,用户使用手指滑动屏幕,可以在前一幅漫画和后一...这个时候ViewFlipper就是一个很好的选择

    Android ViewFlipper的简单使用

    大家都使用过ViewPager...在Android Studio中新建一个工程,实现这样一个效果:创建红、橙、绿、蓝四种颜色的页面,然后通过ViewFlipper让它们来回切换。四个页面布局文件的名称如下所示: item_view1.xml的代码如下:

    Android TextSwitcher文本切换器和ViewFlipper使用详解

    主要为大家详细介绍了Android TextSwitcher文本切换器和ViewFlipper的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    ANDROID中使用VIEWFLIPPER类实现屏幕切换(关于坐标轴的问题已补充更改)

    屏幕切换指的是在同一个Activity内屏幕间的切换,ViewFlipper继承了Framelayout类,ViewAnimator类的作用是为FrameLayout里面的View切换提供动画效果。如下动图: 该类有如下几个和动画相关的函数: ...

    Android典型技术模块开发详解

    2.2 HelloAndroid详解 2.2.1 程序结构 2.2.2 代码分析 2.3 权限permission 2.4 LogCat日志调试 2.5 示例练习 2.5.1 登录界面 2.5.2 事件处理 2.6 本章小结 第二篇 Android开发关键组件 第3章 Activity(活动) 3.1 ...

    Android仿京东淘宝自动无限循环轮播控件思路详解

    在App的开发中,很多的时候都需要实现类似京东淘宝一样的自动无限轮播的广告栏,这里小编写了一个,分享到脚本之家平台供大家参考

    Android实现左右滑动效果的方法详解

    关于滑动效果,在Android中用得比较多,本示例实现的滑动效果是使用ViewFlipper来实现的,当然也可以使用其它的View来实现。接下来就让我们开始实现这种效果。为了方便大家理解,我们先来看一下效果图:主要效果图如...

    Android学习系列教程实例.pdf

    2.2.4. Activity 中四个重要的概念 .. 30 2.3. 旋转屏幕重新加载 Acitivity .......... 33 第 3 章 第三章 ................... 40 3.1. 缓冲界面 ......................................... 40 3.1.1. Demo1 ........

    Android实现绕球心旋转的引导页效果

    这里我们用到了Android系统的一个组件ViewFlipper,该控件的主要作用是为其中的View切换提供动画效果,主要的方法如下: setInAnimation:设置View进入屏幕时的动画。 setOutAnimation:设置View退出屏幕时的动画...

Global site tag (gtag.js) - Google Analytics