展会信息港展会大全

Android中ViewFlipper详解
来源:互联网   发布日期:2015-10-02 21:14:10   浏览:1885次  

导读:前面已经讲过ImageSwitcher和TextSwitcher。ImageSwitcher用来切换ImageView的,TextSwitcher是用来切换TextView的。但是我们现在...

前面已经讲过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类中

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

摘自 殇

赞助本站

人工智能实验室

相关热词: android开发 教程

AiLab云推荐
推荐内容
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港