欢迎页轮播动画

欢迎页轮播动画

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

在来看看效果图。

欢迎页轮播动画

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

首先新建一个类 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日

相关文章

  • 京东小程序折叠屏适配探索

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

    Android 2023年5月8日
    00
  • 钥匙环服务,打造无缝的跨设备登录体验

    近些年来,随着手机技术迭代更新越来越快,用户更换手机的周期也在缩短,在这样的背景下,开发者不得不面临以下问题: 同一开发者旗下常常有多个安卓应用和多形态应用(快应用和Web应用),用户更换一个新的设备(手机或平板)后,在新设备上登录各应用时每次都需要重复输入帐号和密码,导致用户在登录阶段流失率增加,同时开发者还需要承担额外的短信成本(如用户使用短信登录)。 …

    Android 2023年4月17日
    00
  • Android模拟器调试串口

    一、安装虚拟串口软件 虚拟串口软件推荐 Virtual Serial Port Driver 官网 和 Virtual Serial Port Kit 官网 都可以免费试用15天。 这里以Virtual Serial Port Kit为例,打开安装好的Virtual Serial Port Kit,点击菜单栏的新增图标 然后选择两个端口点确定即可 1.1 测…

    Android 2023年4月17日
    00
  • android开发Android Studio Electric Eel版本开始支持手机投屏啦

    android开发Android Studio Electric Eel可以手机投屏啦 在Android Studio Electric Eel版本之前,我们需要进行手机投屏,一般使用Vysor等软件,这还是付费的哦,而且还不是很稳定 Android Studio Electric Eel版本开始有投屏功能了,使用起来就像模拟器一样,投屏的位置就是在模拟器窗…

    Android 2023年4月17日
    00
  • 乐固加固、360加固后安装不了问题。

    腾讯云应用安全已在加固过程中删除签名信息,加固后的安装包需要重新签名。同样近期360加固助手签名设置也需要购买高级加固服务。在进行加固后我们需要手动签名cmd 手动签名 apksigner 1、检查签名文件*.jks或者*.keystore keytool -list -v -keystore 签名文件路径 -storepass 密码 注意有些历史比较悠久的…

    Android 2023年4月18日
    00
  • react-native-web跨平台实战

    1.背景  随着对用户体验要求的提高,产品要求提升用户体验,多端体验一致。随着多端相同的业务也越来越多,需要投入IOS,Android,Web多端开发人员。这就迫切的需要一种一次开发同时使用在Android ,IOS ,Web的解决方案。达到降本增效的目的。在几个小业面尝试,总结经验后,我们采用react-native-web多端适配。   2.问题 a.对…

    Android 2023年4月18日
    00
  • Viu联合华为HMS生态,共创影音娱乐新体验

    华为HMS生态携手流媒体平台Viu,为海外消费者打造精品移动娱乐应用体验,并助力提升流量变现能力。Viu在中东非、东南亚等16个国家及地区提供广告合作和付费会员服务,支持优质视频内容高清点播和直播。自2019年起,Viu在中东非区域与华为HMS生态开展一系列紧密合作,并在2022年实现47%的用户增长。 本次,华为邀请Viu中东非区域首席业务官Rohit D…

    Android 2023年4月22日
    00
  • 手机穿戴设备能力共享,提升丰富交互体验

    HUAWEI Wear Engine面向手机和穿戴设备的应用与服务开发者,提供华为穿戴设备开放能力。 开发者通过调用Wear Engine开放能力,可以实现手机上的生态应用与服务给华为穿戴设备发消息、发通知、传输数据,并获取穿戴设备状态、读取传感器数据等,也可以实现华为穿戴设备上的生态应用与服务给手机发消息、传输数据等。 Wear Engine将手机上的生态…

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