如何在 duxapp 中开发一个兼容 RN 的动画库
Taro 一直以来都没有一个能兼容 RN 的动画方案,duxapp 中扩展了 createAnimation 方法,让这个方法兼容了 RN 端,下面让我们来看看实现思路
createAnimation方法
这个方法是用来创建一个动画实例的,使用方法像下面这样,每次 step 创建一组动画,每组动画同时执行,执行完一组继续执行下一组,直到所有的动画执行完
const an = createAnimation()
.translate(50, 50).rotate(180).step()
.translate(0, 0).rotate(0).step()
.export()
将创建的结果设置给 View 的 animation 属性,这个动画就能被执行了
在 Taro 里面这个方法目前兼容小程序 和 H5 端,我们要实现的就是让他兼容 RN,这样后面要给我们的组件加动画就更加简单了,不用在要加动画的组件 H5 写一套,RN 再写一套
RN的动画方案
RN 里面的动画和 createAnimation 这个方式可以说是天差地别,下面来看这个实现淡入动画的代码,这是一个官方示例
import React, { useRef, useEffect } from 'react';
import { Animated, Text, View } from 'react-native';
const FadeInView = (props) => {
const fadeAnim = useRef(new Animated.Value(0)).current // 透明度初始值设为0
React.useEffect(() => {
Animated.timing( // 随时间变化而执行动画
fadeAnim, // 动画中的变量值
{
toValue: 1, // 透明度最终变为1,即完全不透明
duration: 10000, // 让动画持续一段时间
}
).start(); // 开始执行动画
}, [fadeAnim])
return (
<Animated.View // 使用专门的可动画化的View组件
style={{
...props.style,
opacity: fadeAnim, // 将透明度绑定到动画变量值
}}
>
{props.children}
</Animated.View>
);
}
好在 RN 的动画库本身是很强大的,我们要做的是在 RN 端模拟实现一个 createAnimation, 还是有办法解决的
实现
要实现 RN,我们需要两步
- 1、编写一个类,用来模拟
createAnimation方法,通过这个类创建一些动画数据 - 2、将这个类创建的数据传递给一个自定义组件,这个组件里面将这些数据解析成动画,并执行这些动画
创建 Animation 类
这个类就比较简单,模拟 createAnimation 每一个方法即可,并在 export() 之后生成一个数据并返回,因代码过长,下面是部分代码展示
export const create = option => new Animation(option)
class Animation {
constructor(option = {}) {
if (!option.duration) {
option.duration = 400
}
if (!option.timingFunction) {
option.timingFunction = 'linear'
}
if (!option.delay) {
option.delay = 0
}
if (!option.transformOrigin) {
option.transformOrigin = '50% 50% 0'
}
this.defaultOption = option
}
result = []
current = {}
export() {
const res = this.result
this.result = []
return res
}
step(option) {
if (Object.keys(this.current).length) {
this.result.push({
option: {
...this.defaultOption,
...option
},
action: this.current
})
this.current = {}
}
return this
}
set(name, value) {
this.current[name] = value
return this
}
translate(x, y) {
this.translateX(x)
return this.translateY(y)
}
translate3D(x, y, z) {
this.translateX(x)
this.translateY(y)
return this.translateZ(z)
}
translateX(val) {
return this.set('translateX', val)
}
translateY(val) {
return this.set('translateY', val)
}
translateZ(val) {
return this.set('translateZ', val)
}
}
创建组件实现动画
这个地方相对会复杂一些,其中的难点有几个
- 在小程序上的动画,是会根据 css 的默认值去执行变化的,但是 RN 上的默认值需要在动画中设置,因此,需要获取这个默认值
- 将动画拆分成适合 RN 端动画组件的 style 属性
此处代码过长,可以前往 github 查看,或者使用 duxapp 创建项目之后就能看到
使用
动画库写好之后我们就能给我们原有的一些组件进行改造了,例如 PullView,在这之前,这个组件是针对 RN 端和其他端写了两套代码的,现在只需要一套代码就实现了,下面的示例代码展示了这个组件动画实现方式
import { isValidElement, cloneElement, forwardRef, useState, useEffect, useRef, useImperativeHandle, useCallback } from 'react'
import { View } from '@tarojs/components'
import { asyncTimeOut, nextTick, px, pxNum, transformStyle, useBackHandler } from '@/duxapp/utils'
import { Absolute } from '../Absolute'
import { Animated } from '../Animated'
import './index.scss'
export const PullView = forwardRef(({
side = 'bottom',
style,
overlayOpacity = 0.5,
children,
masking = true,
group,
onClose,
modal,
mask = modal,
duration = 200
}, ref) => {
const [mainAn, setMainAn] = useState(Animated.defaultState)
const [maskAn, setMaskAn] = useState(Animated.defaultState)
const ans = useRef()
const refs = useRef({})
refs.current.onClose = onClose
refs.current.overlayOpacity = overlayOpacity
const translate = siteTranslates[side]
const close = useCallback(async () => {
let an = ans.current.main
if (side === 'center' && process.env.TARO_ENV !== 'rn') {
an = an.translate('-50%', '-50%')
}
setMainAn(an[translate.key](pxNum(translate.value)).opacity(0).step(
process.env.TARO_ENV !== 'rn' ? {
transformOrigin: '25% 25% 0'
} : {}
).export())
setMaskAn(ans.current.mask.opacity(0).step().export())
await asyncTimeOut(duration)
refs.current.onClose?.()
}, [duration, side, translate.key, translate.value])
useBackHandler(close, !mask)
useImperativeHandle(ref, () => {
return {
close
}
})
useEffect(() => {
nextTick(() => {
if (!ans.current) {
ans.current = {
main: Animated.create({
duration,
timingFunction: 'ease-in-out'
}),
mask: Animated.create({
duration,
timingFunction: 'ease-in-out'
})
}
}
if (side === 'center') {
let an = ans.current.main.scale(1).opacity(1)
if (process.env.TARO_ENV !== 'rn') {
an = an.translateX('-50%').translateY('-50%')
}
setMainAn(an.step().export())
} else {
setMainAn(ans.current.main.translateX(0).translateY(0).opacity(1).step().export())
}
setMaskAn(ans.current.mask.opacity(refs.current.overlayOpacity).step().export())
})
}, [duration, side])
return <Absolute group={group}>
{masking && <Animated.View
animation={maskAn}
className='PullView'
>
<View className='PullView__other'
onClick={() => {
if (mask) {
return
}
close()
}}
></View>
</Animated.View>}
<Animated.View
animation={mainAn}
className={`PullView__main PullView__main--${side}`}
style={{
...style,
transform: transformStyle(side === 'center' ? {
translateX: '-50%',
translateY: '-50%',
scaleX: 0.4,
scaleY: 0.4
} : {
[translate.key]: px(translate.value)
})
}}
>
{
isValidElement(children) ?
cloneElement(children, {
style: {
...children.props.style,
...(side === 'center'
? {}
: side === 'bottom' || side === 'top'
? { width: '100%' }
: { height: '100%' })
}
}) :
children
}
</Animated.View>
</Absolute>
})
const siteTranslates = {
top: { key: 'translateY', value: -200 },
bottom: { key: 'translateY', value: 200 },
left: { key: 'translateX', value: -200 },
right: { key: 'translateX', value: 200 },
center: { key: 'scale', value: 0.4 }
}
最后
当然这个动画也不是完美的,只是实现了一个基础的动画,甚至使用的时候还有诸多的限制,你可以点击下面的动画文档查看详细的使用方法以及限制
如何在 duxapp 中开发一个兼容 RN 的动画库的更多相关文章
- 如何在JAVA中实现一个固定最大size的hashMap
如何在JAVA中实现一个固定最大size的hashMap 利用LinkedHashMap的removeEldestEntry方法,重载此方法使得这个map可以增长到最大size,之后每插入一条新的记录 ...
- 如何在idea中引入一个新maven项目
如何在idea中引入一个新的maven项目,请参见如下操作:
- 如何在html中把一个图片或者表格覆盖在一张已有图片上的任意位置
如何在html中把一个图片或者表格覆盖在一张已有图片上的任意位置 <div style="position:relative;"> <img src=&quo ...
- (转)如何在Linux中统计一个进程的线程数
如何在Linux中统计一个进程的线程数 原文:http://os.51cto.com/art/201509/491728.htm 我正在运行一个程序,它在运行时会派生出多个线程.我想知道程序在运行时会 ...
- Kubernetes入门(四)——如何在Kubernetes中部署一个可对外服务的Tensorflow机器学习模型
机器学习模型常用Docker部署,而如何对Docker部署的模型进行管理呢?工业界的解决方案是使用Kubernetes来管理.编排容器.Kubernetes的理论知识不是本文讨论的重点,这里不再赘述, ...
- 使用 js 实现一个简易版的动画库
使用 js 实现一个简易版的动画库 具有挑战性的前端面试题 animation css refs https://www.infoq.cn/article/0NUjpxGrqRX6Ss01BLLE x ...
- [C++/Python] 如何在C++中使用一个Python类? (Use Python-defined class in C++)
最近在做基于OpenCV的车牌识别, 其中需要用到深度学习的一些代码(Python), 所以一开始的时候开发语言选择了Python(祸患之源). 固然现在Python的速度不算太慢, 但你一定要用Py ...
- Andriod项目开发实战(1)——如何在Eclipse中的一个包下建新包
最开始是想将各个类分门别类地存放在不同的包中,所以想在项目源码包中新建几个不同功能的包eg:utils.model.receiver等,最后的结果应该是下图左边这样的: 很明显建立项目后的架构是上 ...
- 如何在HoloLens中创建一个2D的Hello World程序
注:本文提及到的代码示例下载地址 > How to build an "Hello World" 2D app in HololLens. HoloLens 是微软的一款MR ...
- IE 中开发,兼容与性能测试工具汇总
前言 对于开发者来说, IE的兼容性是最让人头疼的. 因为是微软的产品, 且绑定在操作系统上, 所以IE的占用率还是相当大, 对于开发者来说, 这部分的兼容的考虑就不可避免了. 对于IE 的各版本来说 ...
随机推荐
- ASP.NET Core – HttpClient
前言 以前写过的文章 Asp.net core 学习笔记 ( HttpClient ). 其实 HttpClient 内容是挺多的, 但是我自己用到的很少. 所以这篇记入一下自己用到的就好了. 参考 ...
- jQuery - 不同版本的差异對比
jQuery 一共分了 1.x.2.x.3.x 这三个大版本. jQuery 的版本都是不向后兼容的! jQuery 的版本都是不向后兼容的! jQuery 的版本都是不向后兼容的!重要的事情说三遍哈 ...
- Tomcat——IDEA中创建 Maven Web 项目
IDEA中创建 Maven Web 项目 首先创建一个新的空项目 1.使用骨架 新建模块-找到如下骨架-创建 删除pom.xml中多余的坐标 ...
- 线段树 ----洛谷p3372
问题描述: 已知一个数列,对数列进行两种操作:1,对数列某个区间中的所有数加d:2,查询数列某区间的区间和 输入: 第一行输入两个整数n和m,分别代表数列中元素个数和对数列的操作次数,第二行输入n个用 ...
- sigmod、tanh、ReLU激活函数的实现
import torch import torch.nn.functional as F import matplotlib.pyplot as plt import numpy as np x = ...
- 墨天轮高分技术文档分享——Oracle升级迁移篇(共96个)
朋友们好久不见,在上期<墨天轮最受欢迎的技术文档-SQL优化篇>的留言中,有许多朋友表示想看数据库升级迁移相关的内容,经过搜集整理,这就为大家呈上!原文送墨值中,欢迎大家参与~ 数据库升级 ...
- kotlin更多语言结构——>选择加入要求
1.3.70 中引入了 @RequireOptIn 与 @OptIn 注解以取代先前使用的 @Experimental 与 @UseExperimental;同时 -Xopt-in 编译器选项也取代了 ...
- kotlin类与对象——>委托、委托属性
1.委托 1.1 委托的实现 委托模式已经证明是实现继承的一个很好的替代方式,而 Kotlin 可以零样板代码地原生支持它. Derived 类可以通过将其所有公有成员都委托给指定对象来实现一个接口 ...
- Android复习(二)应用资源 --> 颜色状态列表
转自: https://developer.android.google.cn/guide/topics/resources/color-list-resource 颜色状态列表资源 ColorSta ...
- Exchange限制邮箱用户每天/每分钟的发送邮件数量和速率
Exchange限制邮箱用户每天/每分钟的发送邮件数量和速率 近期遇到部分Exchange客服反馈内部邮箱账号密码被盗,给内部其他同事和外部邮箱发送大量钓鱼和诈骗邮件:对公司造成很大负面影响和经济损失 ...