欢迎页轮播动画

欢迎页轮播动画

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

在来看看效果图。

欢迎页轮播动画

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

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

相关文章

  • uniapp解决未配置appkey成功运行并离线打包apk的详细图文

    官方文档 https://nativesupport.dcloud.net.cn/AppDocs/usesdk/android.html 一、将写好的uniapp 右键→发行→原生app-本地打包→生成本地打包App资源(它会要求你登录账号) 二、它会生成一个文件夹 三、点击连接可以直接进入文件夹,路径往上一级找,找到resources文件夹将下面刚才生成的…

    Android 2023年4月18日
    00
  • 仿豆瓣发布-编辑框自适应高度,自动滚动定位到焦点输入

    效果图 随着输入的文本自动增加高度,键盘上方自定义菜单布局,随键盘弹起 点击编辑框,自动滚动到焦点处输入 布局层次 <ConstraintLayout>   <ScrollView>     <LinearLayout>        <Edittext/>       <自定义布局/>     &…

    Android 2023年4月18日
    00
  • 语言录制兼容长按跟点击录制

    录音需求中,往往有两种常规操作。 长按基本实现流程: 监听触摸事件,按下时录制,抬起时停止。 点击基本流程: 点击开始录制,在次点击停止录制 但是凡事有绝对,如果需要同时支持长按录制抬起结束跟点击录制在次点击结束呢?面对如此无理的需求,从技术层面上怎么如丝滑般去兼容呢。 需要两者兼容,只能从触摸事件入手了,这里的重点其实就在于怎么在触摸事件中去区分点击事件跟…

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

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

    Android 2023年4月20日
    00
  • 小程序容器助力组装移动银行超级APP

    移动银行APP作为一种重要的商业渠道,是数字获客客户、生态建设和品牌传播的关键。近年来,作为银行机构客户经营的重要平台,移动银行APP利用技术不断迭代升级和创新手机银行APP服务功能。 根据艾瑞关于2022年中国手机银行 App 的研究分析显示,自2016年起,银行业平均业务离柜率呈上升趋势,2021年已有超90%的银行业务实现离柜办理,截止到2022年6月…

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

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

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

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

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

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

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