欢迎页轮播动画

欢迎页轮播动画

如图,引导开始,球从上落下,同时淡入文字,然后文字开始轮播,最后一页时停止,点击进入首页。

在来看看效果图。

欢迎页轮播动画

重力球先不讲,主要欢迎轮播简单实现

首先新建一个类 TextTranslationXGuideView,用于动画展示

文本是类似的,最后会有个图片箭头动画,布局很简单,就是一个 TextView 跟 ImageView,直接写 xml 布局里方便了

所以 TextTranslationXGuideView 直接继承 FrameLayout,然后动态添加布局,控制动画

val root = LayoutInflater.from(context)
            .inflate(R.layout.login_layout_text_translation_x_guide, this, false)
        root.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
        addView(root)
        mBinding = LoginLayoutTextTranslationXGuideBinding.bind(root)
login_layout_text_translation_x_guide
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    tools:background="@color/white"
    tools:layout_marginStart="@dimen/dp_24">

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:fontFamily="@font/misans_bold"
        android:lineSpacingExtra="@dimen/dp_20"
        android:textColor="@color/bl_black"
        android:textSize="@dimen/sp_36"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="欢迎xxx\n111" />

    <ImageView
        android:id="@+id/iv_guide1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/dp_30"
        android:src="@drawable/login_guide_text_right_black"
        android:visibility="gone"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_content"
        tools:visibility="visible" />

    <ImageView
        android:id="@+id/iv_guide2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/login_guide_text_right_end"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="@+id/iv_guide1"
        app:layout_constraintStart_toEndOf="@+id/iv_guide1"
        app:layout_constraintTop_toTopOf="@+id/iv_guide1"
        app:tint="@color/c_f4f4f4"
        tools:visibility="visible" />

</androidx.constraintlayout.widget.ConstraintLayout>

文字颜色换行等通过 span 设置,所以需要一个类去配置

data class TextTranslationXGuideBean(
        val content: String, //内容
        val bright: String?, //高亮文本
        val brightColor: Int = R.color.bl_black //高亮字体颜色
    )

轮播配置成动态的,所以这里使用一个集合去存储

private val guideList = mutableListOf<TextTranslationXGuideBean>()
/**
     * 添加单个引导文本
     * @param content 内容
     * @param bright 高亮文本
     * @param brightColor 高亮字体颜色
     * */
    fun addTextGuide(
        content: String,
        bright: String? = null,
        brightColor: Int? = null
    ): TextTranslationXGuideView {
        guideList.add(TextTranslationXGuideBean(content, bright, brightColor ?: R.color.bl_black))
        return this
    }

然后在动态设置内容跟图片

/** 设置引导内容 */
    private fun setGuideContent(bean: TextTranslationXGuideBean) {
        mBinding?.tvContent?.text = bean.content
        val span = SpanUtils.with(mBinding?.tvContent)
            .append(bean.content)
            .setForegroundColor(resources.getColor(R.color.bl_black, null))
        bean.bright?.let {
            span.append("\n${bean.bright}")
                .setForegroundColor(resources.getColor(bean.brightColor, null))
        }
        span.create()
    }

接下来需要两个动画,一个淡入,一个平移(TextView 自带的跑马灯不好控制,后期如果更换方案改动也大)

private var mTranslationAnimator: ValueAnimator? = null
private var mFlickerAnimator: ValueAnimator? = null

init {
        initView()
        initTranslationAnimation()
        initGuideRightAnimate()
    }

平移动画重复执行,轮播显示,通过下标控制,显示 guideList 中的数据,如果轮播到最后一条,展示箭头闪烁动画

private fun initTranslationAnimation() {
        val point = -ScreenUtils.getScreenWidth().toFloat()
        mTranslationAnimator = ValueAnimator.ofFloat(0f, point)
        mTranslationAnimator?.duration = 300
        mTranslationAnimator?.interpolator = LinearInterpolator()
        mTranslationAnimator?.addUpdateListener { animation ->
            val scrollX = animation.animatedValue as Float
            translationX = scrollX
            if (scrollX <= point) {
                mTranslationAnimator?.cancel()
                alpha = 0f
                translationX = 0f
                nextGuide()
            }
        }
    }

private fun initTranslationAnimation() {
        val point = -ScreenUtils.getScreenWidth().toFloat()
        mTranslationAnimator = ValueAnimator.ofFloat(0f, point)
        mTranslationAnimator?.duration = 300
        mTranslationAnimator?.interpolator = LinearInterpolator()
        mTranslationAnimator?.addUpdateListener { animation ->
            val scrollX = animation.animatedValue as Float
            translationX = scrollX
            if (scrollX <= point) {
                mTranslationAnimator?.cancel()
                alpha = 0f
                translationX = 0f
                nextGuide()
            }
        }
    }


/** 开始时调用 */
    fun initGuide() {
        position = 0
        if (guideList.size > 0) {
            guideList.getOrNull(position)?.let {
                setGuideContent(it)
            }
            //渐入
            alpha = 0f
            startAlphaAnimation(1500) {
                startTranslationAnimator()
            }
        }
    }

结束时清楚缓存跳转首页

fun clear() {
        guideList.clear()
        mTranslationAnimator?.cancel()
        mTranslationAnimator = null
        mFlickerAnimator?.cancel()
        mFlickerAnimator = null
    }

欢迎页轮播动画

全部实现

欢迎页轮播动画

/** 登录引导动画 */
class TextTranslationXGuideView(context: Context, attrs: AttributeSet?) :
    FrameLayout(context, attrs) {

    private var mBinding: LoginLayoutTextTranslationXGuideBinding? = null

    private var mTranslationAnimator: ValueAnimator? = null
    private var mFlickerAnimator: ValueAnimator? = null

    private val guideList = mutableListOf<TextTranslationXGuideBean>()
    private var position = 0//当前显示的引导索引

    var clickRight: (() -> Unit)? = null

    init {
        initView()
        initTranslationAnimation()
        initGuideRightAnimate()
    }

    private fun initView() {
        val root = LayoutInflater.from(context)
            .inflate(R.layout.login_layout_text_translation_x_guide, this, false)
        root.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
        addView(root)
        mBinding = LoginLayoutTextTranslationXGuideBinding.bind(root)
        mBinding?.ivGuide1?.setOnThrottledClickListener {
            clickRight?.invoke()
        }
        mBinding?.ivGuide2?.setOnThrottledClickListener {
            clickRight?.invoke()
        }
    }

    private fun initTranslationAnimation() {
        val point = -ScreenUtils.getScreenWidth().toFloat()
        mTranslationAnimator = ValueAnimator.ofFloat(0f, point)
        mTranslationAnimator?.duration = 300
        mTranslationAnimator?.interpolator = LinearInterpolator()
        mTranslationAnimator?.addUpdateListener { animation ->
            val scrollX = animation.animatedValue as Float
            translationX = scrollX
            if (scrollX <= point) {
                mTranslationAnimator?.cancel()
                alpha = 0f
                translationX = 0f
                nextGuide()
            }
        }
    }

    private fun startTranslationAnimator() {
        mTranslationAnimator?.start()
    }

    private fun initGuideRightAnimate() {
        mFlickerAnimator = ValueAnimator.ofFloat(0f, 1f)
        mFlickerAnimator?.duration = 600
        mFlickerAnimator?.interpolator = LinearInterpolator()
        mFlickerAnimator?.repeatMode = ValueAnimator.REVERSE
        mFlickerAnimator?.repeatCount = ValueAnimator.INFINITE
        mFlickerAnimator?.addUpdateListener { animation ->
            val alpha = animation.animatedValue as Float
            mBinding?.ivGuide2?.alpha = alpha
        }
    }

    private fun startGuideRightAnimator() {
        mBinding?.ivGuide2?.visibility = View.VISIBLE
        mBinding?.ivGuide2?.alpha = 0f
        mFlickerAnimator?.start()
    }

    /** 开始时调用 */
    fun initGuide() {
        position = 0
        if (guideList.size > 0) {
            guideList.getOrNull(position)?.let {
                setGuideContent(it)
            }
            //渐入
            alpha = 0f
            startAlphaAnimation(1500) {
                startTranslationAnimator()
            }
        }
    }

    /** 下一个引导 */
    private fun nextGuide() {
        position += 1
        //是否为最后一条数据
        val isEndGuide = position == guideList.size - 1
        //第一个图标需要先展示
        mBinding?.ivGuide1?.visibility = if (isEndGuide) View.VISIBLE else View.GONE
        guideList.getOrNull(position)?.let {
            setGuideContent(it)
            startAlphaAnimation {
                if (position < guideList.size - 1) {
                    //如果有,循环执行下一个引导
                    startTranslationAnimator()
                } else {
                    //最后一个,执行渐变闪烁动画
                    startGuideRightAnimator()
                }
            }
        }
    }

    private fun startAlphaAnimation(duration: Long = 1000L, endListener: (() -> Unit)) {
        animate().setDuration(duration).alpha(1f)
            .setListener(object : Animator.AnimatorListener {
                override fun onAnimationStart(p0: Animator?) {}

                override fun onAnimationEnd(p0: Animator?) {
                    endListener.invoke()
                }

                override fun onAnimationCancel(p0: Animator?) {}

                override fun onAnimationRepeat(p0: Animator?) {}
            })
    }

    /** 设置引导内容 */
    private fun setGuideContent(bean: TextTranslationXGuideBean) {
        mBinding?.tvContent?.text = bean.content
        val span = SpanUtils.with(mBinding?.tvContent)
            .append(bean.content)
            .setForegroundColor(resources.getColor(R.color.bl_black, null))
        bean.bright?.let {
            span.append("\n${bean.bright}")
                .setForegroundColor(resources.getColor(bean.brightColor, null))
        }
        span.create()
    }

    /**
     * 添加单个引导文本
     * @param content 内容
     * @param bright 高亮文本
     * @param brightColor 高亮字体颜色
     * */
    fun addTextGuide(
        content: String,
        bright: String? = null,
        brightColor: Int? = null
    ): TextTranslationXGuideView {
        guideList.add(TextTranslationXGuideBean(content, bright, brightColor ?: R.color.bl_black))
        return this
    }

    fun clear() {
        guideList.clear()
        mTranslationAnimator?.cancel()
        mTranslationAnimator = null
        mFlickerAnimator?.cancel()
        mFlickerAnimator = null
    }

    data class TextTranslationXGuideBean(
        val content: String, //内容
        val bright: String?, //高亮文本
        val brightColor: Int = R.color.bl_black //高亮字体颜色
    )

}

TextTranslationXGuideView

原文链接:https://www.cnblogs.com/LiuZhen/p/17333741.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:欢迎页轮播动画 - Python技术站

(0)
上一篇 2023年4月19日
下一篇 2023年4月20日

相关文章

  • 在线文本翻译能力新增14个直译模型,打造以中文为轴心语言的翻译系统

    经济全球化的今天,人们在工作和生活中经常会与外语打交道。相较传播性较广的英语而言,其他语种的识别和阅读对大多数人来说是一件难事,此时就需要借助语言翻译软件来帮助理解。 华为 HMS Core 机器学习服务(ML Kit)翻译功能提供了多种翻译模式,不仅可以满足应用出行购物、网络社交等日常场景,还提供办公文档、视频字幕等专业翻译服务,满足多种语言和场景应用。其…

    Android 2023年4月18日
    00
  • Android页面渲染效率优化实践

      1.车系页布局渲染现状  车系页是重要的车系信息页面,更新迭代多年,页面布局不断变化,xml布局文件越写越复杂。 获取车系页布局文件耗时:         startTime = System.currentTimeMillis();         setContentView(R.layout.car_series_revision_activity…

    Android 2023年4月17日
    00
  • Android报”OutOfMemoryError”如何解决?

    针对Android报”OutOfMemoryError”异常的原因和解决办法,我会给您提供详细讲解。我们先来看一下什么是”OutOfMemoryError”。 什么是”OutOfMemoryError”? 在Java中,程序运行时经常会需要占用内存资源,对于Android应用而言,相对于Java来说,其内存受到了更大的限制,当程序占用的内存超过了系统为其分配…

    Android 2023年4月3日
    00
  • 京东小程序折叠屏适配探索

    前言 随着近年来手机行业的飞速发展,手机从功能机进入到智能机,手机屏幕占比也随着技术和系统的进步越来越大,特别是Android 10推出以后,折叠屏逐渐成为Android手机发展的趋势。 图 1 Android手机屏幕发展趋势 京东小程序近年来也支持了越来越多的业务和应用,做好小程序的折叠屏的适配也是符合未来的发展趋势,能为用户和业务方提供更好的体验和价值。…

    Android 2023年5月8日
    00
  • Android报”SQLiteException”如何解决?

    下面是关于Android报”SQLiteException”异常的原因和解决办法的详细讲解。 异常原因 在进行Android应用程序开发中,我们可能会遇到SQLite数据库相关的操作,例如创建表格、插入数据、查询数据等操作。当我们在应用程序中进行这些操作时,可能会遇到”SQLiteException”异常,其原因可能如下: SQL语法错误:在进行数据库操作时…

    Android 2023年4月3日
    00
  • 接入HMS Core应用内支付服务过程中一些常见问题总结

    华为HMS Core应用内支付服务(In-App Purchases,IAP)为应用提供便捷的应用内支付体验和简便的接入流程。该服务支持客户端和服务端两种开发形式,具体可以参考官方文档。 往期文章:常见问题总结(2)中分享总结了有关无法拉起支付页面的常见问题,本文将对近期开发者们较为关注的一些集成应用内支付服务过程中的问题进行汇总,并提出解决方案。 问题1:…

    Android 2023年4月18日
    00
  • Android Studio中的一些常见控件

    Android Studio是一款非常流行的用于开发Android应用程序的集成开发环境(IDE)。它提供了许多内置控件,使开发人员可以轻松创建应用程序界面和功能。在本文中,我们将介绍Android Studio中的一些常见控件,例如TextView,Button,EditText,ImageView等。 TextView控件 TextView是一个用于显示…

    Android 2023年4月17日
    00
  • 应用内支付服务现网、沙盒环境下常见关键事件的对比与总结

    在集成和调试订阅型商品时,我们会依赖沙盒环境来进行模拟实际场景。 订阅型商品的购买流程和一次性商品的购买流程类似,但订阅还有其他细节场景,比如续订成功或失败,续订周期时长等。沙盒环境下的订阅续订时间会比正常情况更快,引入“时光机”概念帮助您快速测试您应用的订阅场景。比如订阅周期为1周,商品在3分钟后发生续期,此时订阅型商品有效期延长了3分钟。 下面对沙盒环境…

    Android 2023年4月18日
    00
合作推广
合作推广
分享本页
返回顶部