23. 【Android教程】轮播滚动视图:ViewFlipper

news2024/11/26 19:24:44

轮播视图 ViewFlipper 是 Android 从第一个版本就开始提供的 UI 控件,它能够承载多个 View,但一个时机只会有一个 View 展示在屏幕上。通过 ViewFlipper 我们可以实现很多常见的带有展示类型的功能,类似 Gallery、轮播图、导航栏、广告banner等功能,我们可以通过左右滑动、也可以设置定时自动滚动来切换 View。

1. ViewFlipper 的特性

ViewFlipper 是 FrameLayout 的子类,我们可以向 ViewFlipper 中插入一个或多个 View,而由于它是直接继承自 ViewAnimator,从名字上我们可以猜到,它可以对我们插入的多个 View 做各种动画效果,最常见的效果就是对图片做定时轮播。

2. ViewFlipper 的基本用法

在第 1 小节我们提到过,ViewFlipper 拥有两大特性:可以插入 View 并且支持对插入的 View 添加动画,这两个特性都可以采用布局和代码的形式进行设置,下面分别做介绍。

2.1 ViewFlipper 的常用属性

  • android:inAnimation:
    设置 View 进入屏幕的动画效果,默认采用系统动画。
  • android:outAnimation:
    设置 View 离开屏幕时的动画效果,默认采用系统动画。
  • android:flipInterval:
    设置各个 View 切换的时间间隔。

2.2 ViewFlipper 的常用API

对于 ViewFlipper 如果只是简单的滚动,用属性静态设置是非常方便的。但实际开发中很多场景需要配合一些业务逻辑控制,所以大多数时候我们会用 API 来控制翻滚。

  • setInAnimation:
    设置入场动画,类似属性android:inAnimation
  • setOutAnimation:
    设置出场动画,类似属性android:outAnimation
  • showNext:
    展示 ViewFlipper 里的下一个 View。
  • showPrevious:
    展示 ViewFlipper 里的上一个 View。
  • setFilpInterval:
    设置各个 View 切换的时间间隔。
  • startFlipping:
    为 ViewFlipping 的所有子 View 启动一个定时器控制轮播。
  • stopFlipping:
    停止 ViewFlipping 切换。
  • setAutoStart:
    是否自动启动,设置成 true 则会在 ViewFlipping attach 到 Window 的时候自动调用startFlipping启动轮播。

3. ViewFlipper 使用示例

本节我们会实现一个 3 屏轮流滚动的功能,支持 View 之间自动滚动并通过监听 MotionEvent 来支持左右滑动切换。

3.1 布局文件

首先我们来通过 xml 编写布局文件,根据上面的需求要在 ViewFlipper 中放入 3 个布局。我们用一个 RelativeLayout 作为一个 ViewFlipper 的子 View 占满一屏内容,只需要包含三个这样的 RelativeLayout 即可,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:showIn="@layout/activity_main">

    <ViewFlipper
        android:id="@+id/view_flipper"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:inAnimation="@anim/in_from_right"
        android:outAnimation="@anim/out_from_left">

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent">

            <ImageView
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_gravity="center"
                android:adjustViewBounds="true"
                android:background="@android:color/black"
                android:scaleType="centerCrop" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:gravity="center"
                android:text="第一屏:好好学Android"
                android:textColor="@android:color/white"
                android:textSize="18dp"
                android:textStyle="bold" />
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent">

            <ImageView
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_gravity="center"
                android:adjustViewBounds="true"
                android:background="@android:color/darker_gray"
                android:scaleType="centerCrop" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:gravity="center"
                android:text="第二屏:好好学Android"
                android:textSize="18dp"
                android:textStyle="bold" />
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent">

            <ImageView
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_gravity="center"
                android:adjustViewBounds="true"
                android:background="@android:color/holo_green_light"
                android:scaleType="centerCrop" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:gravity="center"
                android:text="第三屏:好好学Android"
                android:textSize="18dp"
                android:textStyle="bold" />
        </RelativeLayout>
    </ViewFlipper>
</RelativeLayout>

可以看到其实 ViewFlipper 的子 View 和我们平时开发时用到的布局没有什么差别,然后将每一屏的内容作为 ViewFlipper 的子 View 添加进去即可。

3.2 编写入场和出场动画

细心的朋友们应该会注意到,在布局文件的<ViewFlipper/>标签中有这么两个属性:

android:inAnimation="@anim/in_from_right"
android:outAnimation="@anim/out_from_left"

根据 2.1 小节对属性的介绍,我们知道这是用来设置出场和入场动画的,所以接下来我们就来完善这两个动画效果,首先按照以下步骤创建一个动画资源:

  1. 右键点击“res”目录,一次选择“New” -> “Android Resource Directory”
  2. 在“Resource type”中选择“anim”,点“OK”,创建一个动画资源目录
  3. 此时“res”目录下就有了“anim”文件夹,在里面创建四个动画文件:
  • in_from_left.xml:

表示从左侧进入的动画,代码如下:

其中<translate/>标签表示一个 TranslateAnimation,专门用来实现移动补间动画,具体关于动画的用法在后面的动画专题章节有详细的讲解,这里我们关注 ViewFlipper,对动画只需要做一点了解即可。
其余三个动画都类似:

  • **in_from_right.xml:**表示从右侧进入,代码如下:
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:duration="1400"
        android:fromXDelta="100%"
        android:fromYDelta="0%" />
</set>
  • **out_from_left:**从左侧移出:
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:duration="1400"
        android:fromXDelta="0%"
        android:toXDelta="-100%"/>
</set>
  • **out_from_right:**从右侧移出:
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:duration="1400"
        android:fromXDelta="0%"
        android:fromYDelta="0%"
        android:toXDelta="100%"
        android:toYDelta="0%" />
</set>

3.3 编写 MainActivity

我们要实现 ViewFlipper 的滑动切换,也就是在用户左滑的时候切换到下一页,而右滑切换到上一页。所以在 MainActivity 里面主要做的是获取 ViewFlipper 对象,然后监听用户的滑动手势从而设置相应的出场 / 入场动画,最后调用showNext()showPrevious()来最终实现上下页切换的效果,整体代码如下:

package com.emercy.myapplication;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.animation.AnimationUtils;
import android.widget.ViewFlipper;


public class MainActivity extends Activity {

    private ViewFlipper mViewFlipper;
    private Context mContext;
    private float initialX;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = this;
        mViewFlipper = findViewById(R.id.view_flipper);
    }

    @Override
    public boolean onTouchEvent(MotionEvent touchEvent) {
        switch (touchEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 记录滑动初始坐标
                initialX = touchEvent.getX();
                break;
            case MotionEvent.ACTION_UP:
                // 记录滑动结束坐标
                float finalX = touchEvent.getX();
                if (initialX > finalX) {
                    // 初始坐标大于结束坐标,说明为左滑,则播放下一页
                    if (mViewFlipper.getDisplayedChild() != 2) {
                        mViewFlipper.setInAnimation(mContext, R.anim.in_from_right);
                        mViewFlipper.setOutAnimation(mContext, R.anim.out_from_left);
                        mViewFlipper.showNext();
                    }
                } else {
                    // 初始坐标不大于结束坐标,说明为右滑,则播放上一页
                    if (mViewFlipper.getDisplayedChild() != 0) {
                        mViewFlipper.setInAnimation(mContext, R.anim.in_from_left);
                        mViewFlipper.setOutAnimation(mContext, R.anim.out_from_right);
                        mViewFlipper.showPrevious();
                    }
                }
                break;
        }
        return false;
    }
}

在代码中我们覆写了onTouchEvent,在 Activity 中的 View 被触摸的时候会回调此函数,我们在MotionEvent.ACTION_DOWN的时候记录触摸时的坐标,然后在MotionEvent.ACTION_UP的时候记录抬起时的坐标,根据触摸起始和结束坐标的差值我们能够推断出用户是左滑还是右滑,从而播放下一页或者上一页。

3.4 自动轮播

第 2 小节介绍了一个API:setAutoStart(),它是用来实现自动播放的,所以我们可以给 ViewFlipper 加上自动轮播的功能。
为了控制自动播放和停止,在布局代码中我们加入两个 Button,样式可以直接借用系统播放器的两个资源文件:@android:drawable/ic_media_play@android:drawable/ic_media_pause,从名字可以看出这是“播放”和“停止”两个按钮,直接在activity_main.xml中根布局<RelativeLayout/>标签的最后加入以下布局代码:

   <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentTop="true"
        android:gravity="center"
        android:orientation="horizontal">

        <Button
            android:id="@+id/play"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginRight="10dp"
            android:background="@android:drawable/ic_media_play" />

        <Button
            android:id="@+id/stop"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="@android:drawable/ic_media_pause" />
    </LinearLayout>

在 Java 代码中监听这两个 Button 的点击事件,在点击播放的时候自动翻下一页,对应的动画就是右边进入和左边退出,即in_from_rightout_from_left。我们可以在布局文件中的<ViewFlipper/>标签中加入

android:inAnimation="@anim/in_from_right"
android:outAnimation="@anim/out_from_left"

或者在 Java 代码中通过

mViewFlipper.setInAnimation();
mViewFlipper.setOutAnimation();

设置入场和出场动画,最终在 MainActivity 的 onCreate()函数的末尾添加如下 Java 代码:

findViewById(R.id.play).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mViewFlipper.setAutoStart(true);
                mViewFlipper.setInAnimation(mContext, R.anim.in_from_right);
                mViewFlipper.setOutAnimation(mContext, R.anim.out_from_left);
                mViewFlipper.setFlipInterval(2000);
                mViewFlipper.startFlipping();
                Toast.makeText(MainActivity.this,
                        "启动自动播放", Toast.LENGTH_SHORT).show();
            }
        });


        findViewById(R.id.stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mViewFlipper.stopFlipping();
                Toast.makeText(MainActivity.this,
                        "停止自动播放", Toast.LENGTH_SHORT).show();
            }
        });

运行之后点击播放即可实现自动翻页。

4. 小结

本节学习了一个很方便实现幻灯片、轮播图的控件:ViewFlipper,在运营活动、广告 Banner 等场景非常常见,可以通过 xml 静态或者 API 动态设置动画及翻转时间间隔,也可以主动触发上翻和下翻动作。大家可以自己思考一下,如果不用 ViewFlipper,只用前面讲的基础布局如何实现这个效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1590872.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Springboot+Vue的Java项目-旅游网站系统(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…

C# WinForm —— 项目目录结构

1. WinForm 应用程序项目 Properties&#xff1a;属性文件夹存放了一个自动生成的类文件AssemblyInfo.cs&#xff0c;保存了一些应用程序集的一些信息引用存放了一些为应用程序提供所需的&#xff0c;某些功能的一些程序集&#xff08;dll文件&#xff09;等添加引用&#xff…

一些知识点小细节

当遇到的问题有关逆序输出&#xff0c;可以转换一下思想&#xff0c;就是使用for循环的时候&#xff0c;i的初始化是从数组或者是字符串的最后一个&#xff0c;然后注意设置循环结束的条件&#xff0c;最重要的是不要忘记i--;而不是I&#xff1b; 注意&#xff1a;当要逆序输出…

蚓链赋能企业拥有“数据能力”会带来哪些变革?

数字时代&#xff0c;对任何一家无论大小的企业&#xff0c;数据都是不可或缺的资源和工具。蚓链赋能企业拥有“数据能力”将会给企业带来哪些变革呢&#xff1f; 首先&#xff0c;将会提高企业的业务效率&#xff0c;通过数据分析和挖掘&#xff0c;企业可以更好地了解客户需…

Composer安装与配置

Composer&#xff0c;作为PHP的依赖管理工具&#xff0c;极大地简化了PHP项目中第三方库的安装、更新与管理过程。本文将详细介绍Composer的安装步骤、基本配置方法&#xff0c;以及一些实用的操作示例&#xff0c;帮助读者快速上手并熟练运用Composer。 一、Composer安装 环…

redis 数据迁移到rds2214(TongRDS-2.2.1.3.Load版 by lqw)

​ 文章目录 一.备份redis文件 vi redis.conf &#xff0c;看看有没有这两行设置&#xff0c;有的话改成跟下面的一致&#xff1a; appendonly yes appendfilename “appendonly.aof” 之后连接redis客户端&#xff0c;输入INFO persistence&#xff0c;如图所示即为开启成功…

中国历年GDP统计-探数API统计

数据介绍 时间维度&#xff1a;1978年-2021年 单位&#xff1a;亿元 该数据来源于国家统计局发布的中国统计年鉴2021&#xff0c;为按当年价格计算的中国历年GDP以及人均GDP。 数据说明&#xff1a; 数据来源于国家统计局。

SpringBoot-自定义Starter精华版

SpringBoot自定义Starter精华版 一、自定义 Starter 分析 项目首先加载 starter,starter加载自动配置类&#xff0c;然后再通过配置绑定对象读取配置属性&#xff0c;注册组件。 二、实现步骤 ​ 开发的自定义 Starter 需求是&#xff0c;项目依赖starterTest-spring-boot-s…

重生奇迹MU圣导师与弓箭手职业对比

职业定位对比 在职业定位上&#xff0c;弓箭手是一个远程物理输出职业&#xff0c;不过弓箭手也有一定的辅助能力&#xff0c;可以为队友提供控场效果&#xff0c;还能为队友提供一个攻击力加成BUFF。同时弓箭手也是一个非常需要操作的职业&#xff0c;想要玩好这个职业&#…

智能体Agent是AI时代普通人可参与的第一个红利机会

自从生成式 AI 兴起&#xff0c;掌握 prompt 能让 AI 工具更好为我们服务。而智能体的出现&#xff0c;让 AI 的使用门槛更是不断降低——都不用写 Prompt 了&#xff0c;直接用智能体就行了。 智能体Agent是AI时代普通人可参与的第一个红利机会© 由 ZAKER科技 提供 前几…

基于java+springboot+vue实现的药品管理系统(文末源码+Lw)23-297

摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;药品信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行处理不能满足广…

Go 自定义14位时间类型 yyyyMMddHHmmss

目录 功能 代码 功能 数据库或者接口时间类型&#xff0c;经常会使用14位的时间格式。每次都转换有点麻烦。可以自定义一个时间类型。 自定义类型需要实现json接口中的MarshalJSON与UnmarshalJSON两个函数&#xff0c;这样在做json编码解码时就会自动转为14位的时间格式了。…

【力扣】142. 环形链表 II

142. 环形链表 II 题目描述 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&am…

第6章:6.3.3 正则表达式的应用 (MATLAB入门课程)

讲解视频&#xff1a;可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇&#xff08;数学建模清风主讲&#xff0c;适合零基础同学观看&#xff09;_哔哩哔哩_bilibili 到目前为止&#xff0c;我们已经系统地介绍了正则表达式的基本语…

Bytebase 2.15.0 - GitOps 整体升级

&#x1f514; GitOps 整体升级 新版 GitOps 和之前版本不兼容&#xff0c;如果需要升级协助&#xff0c;请联系我们。 使用访问令牌进行身份验证。支持项目中配置多个 VCS 连接器。支持在 VCS 连接器中指定数据库分组为目标&#xff08;默认情况下应用于项目中的所有数据库&…

uni-app实现下拉刷新

业务逻辑如下&#xff1a; 1.在滚动容器中加入refresher-enabled属性&#xff0c;表示为开启下拉刷新 2.监听事件&#xff0c;添加refresherrefresh事件 3.在事件监听函数中加载数据 4.关闭动画&#xff0c;添加refresher-triggered属性&#xff0c;在数据请求前开启刷新动画…

自营商城上货采集,上货软件采集(淘宝1688)接口

自营商城上货采集及上货软件采集涉及到淘宝和1688等平台的接口时&#xff0c;主要流程包括确定数据源、申请API权限、编写自动化采集脚本以及后续的数据处理和商城上货。 taobao.item_get-获取淘宝商品数据接口返回值说明 1.请求方式&#xff1a;HTTP POST GET &#xff08;复…

信息学奥赛一本通T1441-生日蛋糕【dfs】

信息学奥赛一本通T1441-生日蛋糕 - C语言网 (dotcpp.com) #include <iostream> #include <algorithm> #include <cmath> using namespace std; const int N1e5100; int n,m; int res1e9; void dfs(int spv,int cnt,int r,int h,int sarea) //spv:剩余的体积&…

【电控笔记0】拉式转换与转移函数

概要 laplace&#xff1a;单输入单输出&#xff0c;线性系统 laplace 传递函数 总结

Codeforces Round 521 (Div. 3)

目录 A. Frog Jumping B. Disturbed People C. Good Array D. Cutting Out E. Thematic Contests F1. Pictures with Kittens (easy version) F2. Pictures with Kittens (hard version) A. Frog Jumping 直接模拟即可注意数据范围需要开long long void solve(){LL a,…