一、介绍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);
}
}

Android学习笔记_21_ViewFlipper使用详解 手势识别器的更多相关文章

  1. Android学习笔记之Activity详解

    1 理解Activity Activity就是一个包含应用程序界面的窗口,是Android四大组件之一.一个应用程序可以包含零个或多个Activity.一个Activity的生命周期是指从屏幕上显示那 ...

  2. Android学习笔记之Toast详解

    1. 贴一段Android API-Toast Toast public class Toast  extends Object java.lang.Object ↳ android.widget.T ...

  3. Android学习笔记4——Activity详解

    在 Android 开发过程中,与程序员打交道最多的应该就是作为四大组件之一的 Activity 了.接下来我们就一起来揭开 Activity 的神秘面纱吧~ 一.概述 什么是 Activity(活动 ...

  4. expect学习笔记及实例详解【转】

    1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的语法如下所示:1.1 首行加上/usr/bin/expect1.2 spawn: 后面加上需要执行的shell命令,比如说sp ...

  5. Docker技术入门与实战 第二版-学习笔记-3-Dockerfile 指令详解

    前面已经讲解了FROM.RUN指令,还提及了COPY.ADD,接下来学习其他的指令 5.Dockerfile 指令详解 1> COPY 复制文件 格式: COPY  <源路径> .. ...

  6. Redis学习笔记4-Redis配置详解

    在Redis中直接启动redis-server服务时, 采用的是默认的配置文件.采用redis-server   xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务.按照本Redi ...

  7. Struts2学习笔记(二)——配置详解

    1.Struts2配置文件加载顺序: default.properties(默认常量配置) struts-default.xml(默认配置文件,主要配置bean和拦截器) struts-plugin. ...

  8. Struts2学习笔记二 配置详解

    Struts2执行流程 1.简单执行流程,如下所示: 在浏览器输入请求地址,首先会被过滤器处理,然后查找主配置文件,然后根据地址栏中输入的/hello去每个package中查找为/hello的name ...

  9. android学习-Activity启动过程详解

    注:只是说明启动activity的过程(ActivityThread如何与ActivityManagerService简称AmS进行进程间通信调用全过程),不解析android从zygote(受精卵) ...

随机推荐

  1. 使用Amoeba for mysql实现mysql读写分离(测试可行)

    Amoeba for MySQL致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的时候充当query 路由功能,专注 分布式数据库 proxy 开发.座落与Client.DB S ...

  2. 用R处理不平衡的数据

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文来自云+社区翻译社,作者ArrayZoneYour 在分类问题当中,数据不平衡是指样本中某一类的样本数远大于其他的类别样本数.相比于多分 ...

  3. Where Should an Architect Begin?--reference

    http://www.bitnative.com/2014/01/24/where-should-a-software-architect-begin/ Where Should an Archite ...

  4. 深入学习keepalived之一 keepalived的启动

    1.keepalived的启动过程: 启动健康检查子进程和vrrp子进程.其中_WITH_LVS_,_WITH_VRRP_在configure和configure.in文件中定义. 源码如下: /* ...

  5. js根据子目录数目显示父级目录

    需求:<ul>中<li>数量为0,则不显示<ul>以及<b>:<div>中<ul>数量为0,则不显示<div> 1. ...

  6. [转]scp命令学习

    原博客地址http://www.cnblogs.com/peida/archive/2013/03/15/2960802.html scp是secure copy的简写,用于在Linux下进行远程拷贝 ...

  7. 绘图和数据可视化工具包——matplotlib

    一.Matplotlib介绍 Matplotlib是一个强大的Python**绘图**和**数据可视化**的工具包. # 安装方法 pip install matplotlib # 引用方法 impo ...

  8. html5 填表 表单 form label input button legend fieldset

      <form>本身没有什么意义, 但是某些依赖form的标签元素一旦没有了form就不能生效. 所以form是提供一个定义环境给form的插件元素去生效的. 1.method 属性pos ...

  9. 网易回合制游戏录像批量下载(失效 不是因为代码 是因为网易官方关闭了录像网站 :P)

    最近在访问网易大话西游2的录像专区时,发现页面还是很早之前的板式,网易的编辑并没有打算重新美化的打算,不由得内心一寒,结合之前好几个回合制游戏的倒闭,让很多人回顾都没办法回顾, 而且,很多人现在也没有 ...

  10. 一次完整的HTTP事务过程

    基本流程: a. 域名解析 b. 发起TCP的3次握手 c. 建立TCP连接后发起http请求 d. 服务器端响应http请求,浏览器得到html代码 e. 浏览器解析html代码,并请求html代码 ...