首页 > 其他分享 >欢迎页轮播动画

欢迎页轮播动画

时间:2023-04-19 17:15:07浏览次数:33  
标签:mBinding 动画 轮播 val 欢迎 private mTranslationAnimator fun null

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

在来看看效果图。

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

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

标签:mBinding,动画,轮播,val,欢迎,private,mTranslationAnimator,fun,null
From: https://www.cnblogs.com/LiuZhen/p/17333741.html

相关文章

  • Label 显示Gif动画,窗口关闭偶发性抛出 在创建窗口句柄之前,不能在控件上调用 Invoke
    2个问题如下,解决方案都一样 问题1UnhandledException:System.InvalidOperationException:在创建窗口句柄之前,不能在控件上调用Invoke或BeginInvoke。在System.Windows.Forms.Control.MarshaledInvoke(Controlcaller,Delegatemethod,Object[]args,Booleansynchro......
  • 直播app源码,使用vue-awesome-swiper创建轮播图幻灯片
    直播app源码,使用vue-awesome-swiper创建轮播图幻灯片1.引入引入方式可以参考官方文档,两种方式选一种即可:vue-awesome-swiperatv3.1.3 (1)第一种方式:在main.js入口文件中全局引入 ///src/main.js //swiper全局引入importVueAwesomeSwiperfrom'vue-awesome-swiper'im......
  • React 组件进入和退出动画实现
    在实现一个React中的弹框组件时,想给组件加个进入和退出动画,但发现React没有Vue3那样现成的api,因此需要自己设计。主要思路为给组件添加一个state来选择className,不同的className会给组件添加不同的动画效果,再使用cssanimation中的forwards来使组件固定在结束的位置。核心代码如......
  • cocos studio 2.3.3制作骨骼动画
    1、新建骨骼动画文件2、把需要的图片资源,比如头、武器等,拖动到工作区,形成Sprite控件,摆好各个图片第一帧的状态3、在形体模式下,点击工具栏目的创建骨骼:   每个骨骼对应1个Sprite【1条骨骼的起点和终点都是可以运动的】   第一个点击的骨骼是root,root旋转,他下面的child骨骼都......
  • cocos-js 播放cocos studio创建的时间轴场景动画
    ctor:1、加载场景动画json2、把场景动画的node添加到层3、找到运动的node4、关联动画和nodeload.node.runAction(load.action)播放:this._load.action.gotoFrameAndPlay(0,100,false);如果需要改变运动的node下面的子节点,可以把子节点removeFromParent然后创建一个新的Sp......
  • cocos2dx-js 帧动画的播放方法
    ctor:varload=ccs.load(res.Ani_json);varmainNode=load.node;this.addChild(mainNode);//对应帧动画的节点,使用seekWidgetByName无效,需要用getChildByNamethis._spriteAni=mainNode.getChildByName("spriteAni");this._spriteAni.setVisible(false);this._lo......
  • cocos studio 2.3.3创建帧动画
    新建一个layer文件左下角60FPS的下面有个+号【添加动画】点击+添加动画,设置好名称和帧数拖动帧的第一个图片到场景里面,自动生成一个sprite把所有的帧图全部拖动到sprite的节点层【当拖动到上面出现+号的时候,就可以放开鼠标了】根据时间轴有多少帧,重新设置下帧动画的配置【+号左边的......
  • uni中使用轮播图
    最近在写一个类似于滚动弹幕,使用纯css,效果有点假,不太真实因此想起来uni中有轮播图,可以直接使用<swiperclass="swiper"style="height:90rpx;"circularvertical="true":autoplay="true":interval="3000":duration="1000"> <swi......
  • 卧龙苍天陨落cg动画可以回放吗 剧情动画能重新看吗_卧龙的梗
    才刚肝完《华阳:彼方横空出世》最后完整版,根本难以说淮南子+七国吗香!姿势格斗游戏太招揽我了,加之解像度、动效、声效也很极好。《华阳:彼方横空出世》这款暗影系七国表现手法的姿势格斗游戏,以西汉初年中原地区星辰为T台,进行了一连串的七国翻拍故事情节。玩者在格斗游戏上将化身为无......
  • 架构师之路-开设学习交流群 欢迎加入
    [top]一:架构师之路学习交流群1.目标-用codechangetheworld2.微信联系方式-联系加群"""WX:zll1314520930"""......