一、介绍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. 案例48-crm练习利用spring管理service和dao层的对象

    1 导包 2 将 Service 对象以及 Dao 对象配置到 spring 容器 <?xml version="1.0" encoding="UTF-8" ...

  2. laravel框架的rabbitmq使用示例[多队列封装]

    RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件).RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的.所有主要 ...

  3. 【坑】自动化测试之Excel表格

    参考一位大神的博客项目架构,把元素和数据都参数化,但是总是被excel表格坑 1.无法下拉 动作列通过下拉列表来控制,点击下拉列表无反应 解决方案:不知道是不是中间动了什么,因为Excel版本的问题, ...

  4. Linux VFS机制简析(一)

    Linux VFS机制简析(一) 本文主要基于Linux内核文档,简单分析Linux VFS机制,以期对编写新的内核文件系统(通常是给分布式文件系统编写内核客户端)的场景有所帮助. 个人渊源 切入正文 ...

  5. 【VMware】VMware的安装和更改虚拟机默认存储路径

    1.VMware Workstation 14中文破解版安装 网盘下载链接:https://pan.baidu.com/s/1pbDXpgpNQTdTRzzKNWfE1A linux镜像(CentOS ...

  6. OGNL,表达式上下文ContextMap

    1.OGNL表达式 object graph navigation language:对象图导航语言 存取对象属性:调用对象方法:字段类型转换等. <input type="text& ...

  7. mysql三-1:理解存储引擎

    一.什么是存储引擎 mysql中建立的库===>文件夹 库中建立的表===>文件 生活中我们用来存储数据的文件有不同的类型,每种文件类型对应各自不同的处理机制:比如处理文本用txt类型,处 ...

  8. Nginx管理(二)

    一.Nginx虚拟主机 一个web服务器软件默认情况下只能发布一个web,因为一个web分享出去需要三个条件(IP.Port.Domain name) Nginx虚拟主机实现一个web服务器软件发布多 ...

  9. SharePoint 2013 - Add-ins

    1. App Web & Host Web The special website to which the app is deployed is called an App Web. The ...

  10. 解决Android报错No resource found that matches the given name (at 'text' with value '@string/hello').

    解决Android项目No resource found that matches the given name (at 'text' with value '@string/hello'). 如图, ...