如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁,
在來看看效果圖,
重力球先不講,主要歡迎輪播簡單實作
首先新建一個類 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.uj5u.com/yidong/550609.html
標籤:Android