前言

京东到家APP的引导页做的可圈可点,插画+动效,简明生动地说明了APP最吸引用户的几个亮点(商品多,价格低,配送快...)。本文主要分析拆解这些动画效果,并完成一个高仿Demo,完整的Demo代码可在文章结尾获取。

先看一下京东到家APP引导页动画效果,如下:

功能分析

分析结果基于对APP进行反编译和我个人的理解(不然还能怎么办呢?我太难了,哈哈哈)

  • 浅浅的背景图+四个引导页面,每一个页面动画播放完成后自动滑动到下一个页面。实现:用ViewPager+4个View实现,每一个页面对应一个View,一个View包含一个LottieAnimationView,在页面中监听Lottie动画的播放,播放完成后自动切换到下一个页面,ViewPager使用的是Alibaba开源的UltraViewPager
背景图片 引导图1 引导图2 引导图3 引导图4
  • 页面滑动切换时有一个旋转动画效果,可自定义ViewPager中的PageTransformer接口实现此效果,Title有透明度渐变效果,用属性动画ObjectAnimator实现

  • 当滑动到最后一个页面时,出现一个带有“立即体验”文本的按钮,出现时从底部向上弹出并且透明度从0到1变化,当从最后一个页面向前滑动时,按钮从底部消失并且透明度从1到0变化,即位移+透明度变化动画,使用属性动画ObjectAnimator可以实现此效果

布局分析

使用uiautomatorviewer查看layout布局文件,如下所示:

  • 根布局为ConstraintLayout,子节点为ViewPager,xml文件如下:
<?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"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/white"> <com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_bg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" /> <com.tmall.ultraviewpager.UltraViewPager
android:id="@+id/viewpager"
android:layout_width="0.0dip"
android:layout_height="0.0dip"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" /> <com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" /> <ImageView
android:id="@+id/ivJump"
android:layout_width="46.0dip"
android:layout_height="0.0dip"
android:layout_marginRight="20.0dip"
android:background="@drawable/pdj_guide_jump"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="63:28.5"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.07" /> <ImageView
android:id="@+id/iv_start"
android:layout_width="104.29999dip"
android:layout_height="30.669983dip"
android:background="@drawable/pdj_guide_button"
android:focusable="true"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/> </androidx.constraintlayout.widget.ConstraintLayout>
  • 引导页总共有四个页面,每一个页面中LottieAnimationView对应一个Lottie文件,xml文件如下:
<?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"
android:layout_width="fill_parent"
android:layout_height="fill_parent"> <com.airbnb.lottie.LottieAnimationView
android:id="@+id/pdj_guide_lottie_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

资源分析

  • 资源文件放在了src/main/assets目录下,配置文件为LottieConfig.json,如下:
{
"radius": 2020,
"totalPageNum": 4,
"lottieBgName": "guide_lottie_bg",
"pageAnimTime": 350,
"buttonAnimTime": 350,
"lottieTitle": [
{
"lottieName": "title_lottie_0"
},
{
"lottieName": "title_lottie_1"
},
{
"lottieName": "title_lottie_2"
},
{
"lottieName": "title_lottie_3"
}
],
"lottieMain": [
{
"lottieName": "main_lottie_0"
},
{
"lottieName": "main_lottie_1"
},
{
"lottieName": "main_lottie_2"
},
{
"lottieName": "main_lottie_3",
"repeatInterval": {
"start": 0.288,
"end": 1
}
}
]
}
  • radius --定义PageTransformer时会用到,用于确定最大旋转角度
  • totalPageNum --引导页的数量
  • lottieBgName --背景图片对应的Lottie文件名
  • pageAnimTime --ViewPager各个页面之间切换的滑动时间
  • buttonAnimTime --最后一个页面"立即体验"按钮做位移和透明度动画的时长
  • lottieTitle --每个引导页标题对应的Lottie文件名
  • lottieMain -- 每个引导页内容对应的Lottie文件名

代码实现

基于以上分析,用代码实现就比较简单了,此处贴出部分实现代码

  • 加载本地Lottie zip文件,Lottie支持加载本地和远程json,zip文件,通常我们将Lottie文件放在src/main/assets目录下
 fun loadAssetsLottieZipFile(context: Context, lottieImageView:LottieAnimationView, fileName:String,repeatCount:Int= LottieDrawable.INFINITE,autoPlay:Boolean=true){
val lottieCompose= if(fileName.endsWith(".zip")){
LottieCompositionFactory.fromAssetSync(context, fileName).value
}
else{
LottieCompositionFactory.fromAssetSync(context, fileName.plus(".zip")).value
}
lottieImageView.progress=0.0f
lottieImageView.repeatCount=repeatCount
lottieImageView.setComposition(lottieCompose!!)
if(autoPlay){
lottieImageView.playAnimation()
} }
  • 添加圆点指示符
        viewpager.initIndicator()
viewpager.indicator.setOrientation(UltraViewPager.Orientation.HORIZONTAL)
.setNormalIcon(drawableToBitmap(ContextCompat.getDrawable(applicationContext, R.drawable.guide_white_dot)!!))
.setFocusIcon(drawableToBitmap(ContextCompat.getDrawable(applicationContext, R.drawable.guide_dark_dot)!!))
.setIndicatorPadding(ScreenHelper.dp2px(applicationContext, 5.0F))
.setMargin(0, 0, 0, ScreenHelper.dp2px(applicationContext, 20.0F))
viewpager.indicator.setGravity(Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
viewpager.indicator.build()

其中drawableToBitmap对应的代码为:

    /**
* Drawable转换成Bitmap
*/
private fun drawableToBitmap(drawable: Drawable): Bitmap {
val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
drawable.draw(canvas)
return bitmap
}
  • 自定义PageTransformer实现页面切换旋转效果

    • position < -1 时,旋转到最大角度,旋转中心为右下角;
    • -1 < position < 0 时,position 越靠近 0 ,旋转角度越小,旋转中心向下边缘中心靠拢;
    • 0 <= position <= 1 时,position 越靠近 0 ,旋转角度越小,旋转中心向下边缘中心靠拢;
    • position > 1 时,旋转到最大角度,旋转中心为左下角。

代码如下所示:

import android.content.Context
import android.view.View
import androidx.viewpager.widget.ViewPager
import com.kongpf.commonhelper.ScreenHelper
import kotlin.math.atan2 class GuideTransformer(context: Context, private val mRadius: Int) : ViewPager.PageTransformer {
private var mMaxRotate = 0f init {
if (mRadius > 0) {
mMaxRotate = (2.0 * Math.toDegrees(atan2((ScreenHelper.getScreenWidth(context) / 2).toDouble(), mRadius.toDouble()))).toFloat()
}
} override fun transformPage(page: View, position: Float) {
if (mRadius == 0) {
return
} when {
position < -1.0f -> {
page.rotation = -1.0f * mMaxRotate
page.pivotX = page.width.toFloat()
page.pivotY = page.height.toFloat()
}
position <= 1.0f -> {
if (position < 0.0f) {
page.pivotX = page.width * (0.5f + 0.5f * -position)
page.pivotY = page.height.toFloat()
page.rotation = position * mMaxRotate
} else {
page.pivotX = 0.5f * page.width * (1.0f - position)
page.pivotY = page.height.toFloat()
page.rotation = position * mMaxRotate
}
}
else -> {
page.rotation = mMaxRotate
page.pivotX = 0f
page.pivotY = page.height.toFloat()
}
}
}
}

完整代码地址

https://github.com/kongpf8848/Animation

高仿京东到家APP引导页炫酷动画效果的更多相关文章

  1. Android高级控件(四)——VideoView 实现引导页播放视频欢迎效果,超级简单却十分的炫酷

    Android高级控件(四)--VideoView 实现引导页播放视频欢迎效果,超级简单却十分的炫酷 是不是感觉QQ空间什么的每次新版本更新那炫炫的引导页就特别的激动,哈哈,其实他实现起来真的很简单很 ...

  2. android仿网易云音乐引导页、仿书旗小说Flutter版、ViewPager切换、爆炸菜单、风扇叶片效果等源码

    Android精选源码 复现网易云音乐引导页效果 高仿书旗小说 Flutter版,支持iOS.Android Android Srt和Ass字幕解析器 Material Design ViewPage ...

  3. 浅谈android中只使用一个TextView实现高仿京东,淘宝各种倒计时

    今天给大家带来的是只使用一个TextView实现一个高仿京东.淘宝.唯品会等各种电商APP的活动倒计时.近期公司一直加班也没来得及时间去整理,今天难得歇息想把这个分享给大家.只求共同学习,以及自己兴许 ...

  4. iOS - GitHub干货分享(APP引导页的高度集成 - DHGuidePageHUD - ②)

    距上一篇博客"APP引导页的高度集成 - DHGuidePageHUD - ①"的发布有一段时间了, 后来又在SDK中补充了一些新的内容进去但是一直没来得及跟大家分享, 今天来跟大 ...

  5. iOS - GitHub干货分享(APP引导页的高度集成 - DHGuidePageHUD - ①)

    好长时间没更新博客, 是时候来一波干货分享了;APP引导页话不多说每一个APP都会用到,分量不重但是不可缺少,不论是APP的首次安装还是版本的更新,首先展现给用户眼前的也就只有它了吧,当然这里讲的不是 ...

  6. GitHub干货分享(APP引导页的高度集成 - DHGuidePageHUD)

    每一个APP都会用到APP引导页,分量不重但是不可缺少,不论是APP的首次安装还是版本的更新,首先展现给用户眼前的也就只有它了,当然这里讲的不是APP引导页的美化而是APP引导页的高度集成,一行代码搞 ...

  7. [Android实例] app引导页(背景图片切换加各个页面动画效果)(申明:来源于网络)

    [Android实例] app引导页(背景图片切换加各个页面动画效果)(申明:来源于网络) 地址: http://www.eoeandroid.com/thread-918356-1-1.html h ...

  8. 使用CoordinatorLayout打造各种炫酷的效果

    使用CoordinatorLayout打造各种炫酷的效果 自定义Behavior -- 仿知乎,FloatActionButton隐藏与展示 NestedScrolling 机制深入解析 一步步带你读 ...

  9. 15个来自 CodePen 的酷炫 CSS 动画效果【下篇】

    CodePen 是一个在线的前端代码编辑和展示网站,能够编写代码并即时预览效果.你在上面可以在线分享自己的 Web 作品,也可以欣赏到世界各地的优秀开发者在网页中实现的各种令人惊奇的效果. 今天这篇文 ...

随机推荐

  1. Google Developer Profile

    Google Developer Profile https://google.dev/u/me https://google.dev/u/109030792841960772125 Google D ...

  2. how to install MySQL on macOS

    how to install MySQL on macOS MySQL Community Server 8.0.21 # version $ mysqladmin --version # 8.0.2 ...

  3. 抓手 & 技术管理

    抓手 & 技术管理 https://zhuanlan.zhihu.com/p/28891618 技术管理的目的 管理就是通过别人拿到结果.而管理的两个着眼点就是:成事.育人. 把事情搞定,把人 ...

  4. Nestjs 上传文件到七牛云

    $ npm install qiniu import * as url from 'url'; import * as qiniu from 'qiniu'; @Post('upload') @Use ...

  5. Baccarat凭什么吸引做市商?2021年将如何发展?

    在过去的一年里,基于资金池的AMM自动化做市商几乎统治了所有DeFi活动,他们没有订单簿,而是根据算法曲线提供资产.尽管在流动性和交易方面取得了令人惊叹的成绩,但是其自身具有无常损失.多代币敞口以及低 ...

  6. jetty的jndi

    jetty的jndi和tomcat的用法 tomcat的jndi是内置的,在web.xml文件里直接默认支持的,所有web项目可以直接使用 <resources> <!-- < ...

  7. 【commons-pool2源码】写前思考

    写作的初衷 工作4年多, 一直没有系统的阅读过优秀的开源代码, 所以从今年开始做一些尝试, 阅读源码并且试着将自己的理解以文章的形式输出, 从而达到以下目的: 通过阅读源码提升自身的技术水准, 通过写 ...

  8. JavaScript:什么是回调?

    翻译练习 原博客地址:JavaScript: What the heck is a Callback? 在6分钟内通过简单的例子学习和理解回调的基本原理. 什么是回调? 简单地说:回调就是一个在另一个 ...

  9. 分布式实时处理系统——C++高性能编程

    [前言]基于通信基础,介绍Hurricane实时处理系统的工程实现,主要使用C++语言. 一.IPC.socket.异步I/O epoll 二.C++11 1.linux内存管理中使用RALL原则,C ...

  10. mysql索引的性能分析

    [前言]上一篇博客介绍了InnoDB引擎的索引机制,主要围绕B+树的建立,目录项记录里主键和页号,到页目录下的二分法定位数据:二级索引里的主键和索引列,及其回表操作.这一篇分析一下索引的性能,围绕如何 ...