React Native UI界面还原,组件布局与动画效果
写React Native UI和写 Android XML layout 布局 ,个人感觉是大同小异
在《ReactJS到React-Native,架构原理概述》里面提过
web 环境中,React 框架,JSX 源码通过 React 框架最终渲染到了浏览器的真实 DOM 中
在 React Native 框架中,JSX 源码通过 React Native 框架编译后,通过对应平台的 Bridge 实现了与原生框架的通信。如果我们在程序中调用了 React Native 提供的 API,那么 React Native 框架就通过 Bridge 调用原生框架中的方法。 因为 React Native 的底层为 React 框架,所以如果是 UI 层的变更,那么就映射为虚拟 DOM 后进行 diff 算法,diff 算法计算出变动后的 JSON 映射文件,最终由 Native 层将此 JSON 文件映射渲染到原生 App 的页面元素上,最终实现了在项目中只需要控制 state 以及 props 的变更来引起 iOS 与 Android 平台的 UI 变更。 编写的 React Native代码最终会打包生成一个 main.bundle.js 文件供 App 加载,此文件可以在 App 设备本地,也可以存放于服务器上供 App 下载更新
Yoga
Yoga C语言写的一个 CSS3/Flexbox 的跨平台 实现的Flexbox布局引擎, 意在打造一个跨iOS、Android、Windows平台在内的布局引擎,兼容Flexbox布局方式,让界面布局更加简单。
Yoga 通过实现许多设计师熟悉的 API 并在不同平台上向开发人员开放。
利用YOGA我们可以:
只写一次布局,就可以得到在不同端上的布局展示。
动态更改view的布局
目前已经被用于在React Native 和 Weex 等开源项目中
但是Yoga只实现了W3C标准的一个子集,所以样式方面,也只有随着Yoga了
其根由还是 yoga FlexBox布局引擎,https://yogalayout.com/
UI组件
React Native | Android View | iOS View | Web Analog | Description |
---|---|---|---|---|
<View> |
<ViewGroup> |
<UIView> |
A non-scrollling
|
A container that supports layout with flexbox, style, some touch handling, and accessibility controls |
<Text> |
<TextView> |
<UITextView> |
<p> |
Displays, styles, and nests strings of text and even handles touch events |
<Image> |
<ImageView> |
<UIImageView> |
<img> |
Displays different types of images |
<ScrollView> |
<ScrollView> |
<UIScrollView> |
<div> |
A generic scrolling container that can contain multiple components and views |
<TextInput> |
<EditText> |
<UITextField> |
<input type="text"> |
Allows the user to enter text |
核心组件和API:https://www.reactnative.cn/docs/components-and-apis
UI样式
为了给React-Native组件加上样式,你需要在JavaScript中添加样式表。
<View style={styles.container}>
<Text style={styles.intro}>Hello world!</Text>
</View>
Flexbox构建响应式App的最佳选择——CSS中的表现不太一致,React-Native并不是为web元素而生,不能像web 应用在html里面使用CSS
这里还是体现了Weex优势
React 和宿主平台之间的桥接包含了一个缩减版CSS 子集的实现。这个CSS 子集主要通过flexbox 进行布局,做到了尽量简单化,而不是去实现所有的CSS 规则。
React Native 也坚持使用内联样式,通过JavaScript 对象进行样式组织。React 团队先前也提倡在Web 环境的React 中使用内联样式。
相对于样式表来说,使用样式对象可能需要一些思维上的调整,从而改变你编写样式的方法。然而,在React Native 中,这是一个实用的转变。
当样式复杂时,建议使用StyleSheet.create来集中定义组件的样式。
const styles = StyleSheet.create({
blueText: {
color: 'blue',
fontSize: 30,
}
});
StyleSheet.create可以弥补编写复杂样式时,不能使用css的不便。
宽高单位与布局调整
RN中宽高可以直接通过style指定,与web不同的是,RN中尺寸是无单位的,表示与设备像素无关的逻辑像素点。
在组件样式中使用flex可以使其在可利用的空间中动态地扩张或收缩。flex布局,跟Android LinearLayout layout_weight——值越大,组件获取剩余空间的比例越多,类似。不同的是,LinearLayout可以设置android:weightSum属性,其子元素可以设置android:layout_weight属性,用于等分的效果。与android类似,flex的优先级是高于width的。
推荐阅读《Android XML与HTML5 排布布局分析与对比—style的异同》
动画
React Native 提供了两个互补的动画系统:用于创建精细的交互控制的动画Animated和用于全局的布局动画LayoutAnimation
Animated
Animated旨在以声明的形式来定义动画的输入与输出,在其中建立一个可配置的变化函数,然后使用start/stop方法来控制动画按顺序执行。 Animated仅封装了 6 个可以动画化的组件:View、Text、Image、ScrollView、FlatList和SectionList,不过你也可以使用Animated.createAnimatedComponent()来封装你自己的组件。
import React, { useRef, useEffect } from 'react';
import { Animated, Text, View } from 'react-native';
//在FadeInView的构造函数里,创建了一个名为fadeAnim的Animated.Value,并放在state中
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>
);
}
// 然后你就可以在组件中像使用`View`那样去使用`FadeInView`了
export default () => {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<FadeInView style={{width: 250, height: 50, backgroundColor: 'powderblue'}}>
<Text style={{fontSize: 28, textAlign: 'center', margin: 10}}>Fading in</Text>
</FadeInView>
</View>
)
}
这一过程经过特别优化,执行效率会远高于反复调用setState和多次重渲染。
因为这一过程是纯声明式的,因此还有进一步优化的空间,比如我们可以把这些声明的配置序列化后发送到一个高优先级的线程上运行。
配置动画
动画拥有非常灵活的配置项。自定义的或预定义的 easing 函数、延迟、持续时间、衰减系数、弹性常数等都可以在对应类型的动画中进行配置。
Animated.timing(this.state.xPosition, {
toValue: 100,
easing: Easing.back(),
duration: 2000}).start();
https://www.reactnative.cn/docs/animated#配置动画
组合动画
多个动画可以通过parallel(同时执行)、sequence(顺序执行)、stagger和delay来组合使用。它们中的每一个都接受一个要执行的动画数组,并且自动在适当的时候调用start/stop。
Animated.sequence([
// decay, then spring to start and twirl
Animated.decay(position, {
// coast to a stop
velocity: { x: gestureState.vx, y: gestureState.vy }, // velocity from gesture release
deceleration: 0.997
}),
Animated.parallel([
// after decay, in parallel:
Animated.spring(position, {
toValue: { x: 0, y: 0 } // return to start
}),
Animated.timing(twirl, {
// and twirl
toValue: 360
})
])]).start(); // start the sequence group
默认情况下,如果任何一个动画被停止或中断了,组内所有其它的动画也会被停止。Parallel 有一个stopTogether属性,如果设置为false,可以禁用自动停止。
在Animated文档的组合动画一节中列出了所有的组合方法。
合成动画值
const a = new Animated.Value(1);
const b = Animated.divide(1, a); Animated.spring(a, {
toValue: 2
}).start();
可以使用加减乘除以及取余等运算来把两个动画值合成为一个新的动画值。
插值
每个动画属性都可以设置值变化区间
style={{
opacity: this.state.fadeAnim, // Binds directly
transform: [{
translateY: this.state.fadeAnim.interpolate({
inputRange: [-300, -100, 0, 100, 101],
outputRange: [150, 0] // 0 : 150, 0.5 : 75, 1 : 0
}),
}],
}}
interpolate()还支持定义多个区间段落,常用来定义静止区间等。举个例子,要让输入在接近-300 时取相反值,然后在输入接近-100 时到达 0,然后在输入接近 0 时又回到 1,接着一直到输入到 100 的过程中逐步回到 0,最后形成一个始终为 0 的静止区间,对于任何大于 100 的输入都返回 0。
跟踪动态值
动画中所设的值还可以通过跟踪别的值得到。你只要把 toValue 设置成另一个动态值而不是一个普通数字就行了。
Animated.spring(follower, { toValue: leader }).start();Animated.timing(opacity, {
toValue: pan.x.interpolate({
inputRange: [0, 300],
outputRange: [1, 0]
})}).start();
比如在上面的代码片段中,leader和follower可以同时为valueXY类型,这样 x 和 y 的值都会被跟踪。
启用原生动画驱动
通过启用原生驱动,我们在启动动画前就把其所有配置信息都发送到原生端,利用原生代码在 UI 线程执行动画,而不用每一帧都在两端间来回沟通。如此一来,动画一开始就完全脱离了 JS 线程,因此此时即便 JS 线程被卡住,也不会影响到动画了。
Animated.timing(this.state.animatedValue, {
toValue: 1,
duration: 500,
useNativeDriver: true // <-- 加上这一行
}).start();
动画值在不同的驱动方式之间是不能兼容的。因此如果你在某个动画中启用了原生驱动,那么所有和此动画依赖相同动画值的其他动画也必须启用原生驱动。
原生驱动还可以在Animated.event中使用。
<Animated.ScrollView // <-- 使用可动画化的ScrollView组件
scrollEventThrottle={1} // <-- 设为1以确保滚动事件的触发频率足够密集
onScroll={Animated.event(
[
{
nativeEvent: {
contentOffset: { y: this.state.animatedValue }
}
}
],
{ useNativeDriver: true } // <-- 加上这一行
)}>
{content}
</Animated.ScrollView>
其他这里省略了
LayoutAnimation API
LayoutAnimation允许你在全局范围内创建和更新动画,这些动画会在下一次渲染或布局周期运行。它常用来更新 flexbox 布局,因为它可以无需测量或者计算特定属性就能直接产生动画。尤其是当布局变化可能影响到父节点(譬如“查看更多”展开动画既增加父节点的尺寸又会将位于本行之下的所有行向下推动)时,如果不使用LayoutAnimation,可能就需要显式声明组件的坐标,才能使得所有受影响的组件能够同步运行动画。
注意尽管LayoutAnimation非常强大且有用,但它对动画本身的控制没有Animated或者其它动画库那样方便,所以如果你使用LayoutAnimation无法实现一个效果,那可能还是要考虑其他的方案。
另外,如果要在Android上使用 LayoutAnimation,那么目前还需要在UIManager中启用::
// 在执行任何动画代码之前,比如在入口文件App.js中执行
UIManager.setLayoutAnimationEnabledExperimental &&
UIManager.setLayoutAnimationEnabledExperimental(true);
在需要的地方
import React from 'react';
import {
NativeModules,
LayoutAnimation,
Text,
TouchableOpacity,
StyleSheet,
View,
} from 'react-native'; const { UIManager } = NativeModules; UIManager.setLayoutAnimationEnabledExperimental &&
UIManager.setLayoutAnimationEnabledExperimental(true); export default class App extends React.Component {
state = {
w: 100,
h: 100,
}; _onPress = () => {
// Animate the update
LayoutAnimation.spring();
this.setState({w: this.state.w + 15, h: this.state.h + 15})
} render() {
return (
<View style={styles.container}>
<View style={[styles.box, {width: this.state.w, height: this.state.h}]} />
<TouchableOpacity onPress={this._onPress}>
<View style={styles.button}>
<Text style={styles.buttonText}>Press me!</Text>
</View>
</TouchableOpacity>
</View>
);
}
} const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
box: {
width: 200,
height: 200,
backgroundColor: 'red',
},
button: {
backgroundColor: 'black',
paddingHorizontal: 20,
paddingVertical: 15,
marginTop: 15,
},
buttonText: {
color: '#fff',
fontWeight: 'bold',
},
});
https://github.com/facebook/react-native/blob/master/Libraries/LayoutAnimation/LayoutAnimation.js
转载本站文章《React Native UI界面还原,组件布局与动画效果》,
请注明出处:https://www.zhoulujun.cn/html/webfront/AppDev/ReactNative/8482.html
React Native UI界面还原,组件布局与动画效果的更多相关文章
- React Native填坑之旅--布局篇
代码在这里: https://github.com/future-challenger/petshop/tree/master/client/petshop/src/controller 回头看看RN ...
- React Native 学习(三)之 FlexBox 布局
React Native 学习(三)之 FlexBox 布局
- [RN] React Native 使用 FlatList 实现九宫格布局 GridList
React Native 使用 FlatList 实现九宫格布局 先看图片演示实例: 本文以图片列表为例,实现九宫格布局! 主要有两种方法: 1)方法一: 利用FlatList的 numColumns ...
- React Native 项目常用第三方组件汇总
React Native 项目常用第三方组件汇总 https://www.jianshu.com/p/d9cd9a868764?utm_campaign=maleskine&utm_conte ...
- React Native 学习笔记--进阶(二)--动画
React Native 进阶(二)–动画 动画 流畅.有意义的动画对于移动应用用户体验来说是非常必要的.我们可以联合使用两个互补的系统:用于全局的布局动画LayoutAnimation,和用于创建更 ...
- React Native入门教程 3 -- Flex布局
上一篇文章中介绍了基本组件的使用 React Native入门教程(笔记) 2 – 基本组件使用及样式 本节内容将继续沿用facebook官方例子介绍如何使用Flexbox布局把界面设计的多样化. 转 ...
- React Native 开发之 (05) flexbox布局
一 flexbox布局 1 flex布局 flexbox是ReactNative 应用开发中必不可少的内容,也是最常用的内容. 传统的页面布局是基于盒子模型,依赖定位属性,流动属性和显示属性来解决. ...
- React Native(一) FlexBox布局
欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/53241550 本文出自:[余志强的博客] 在React Native ...
- React Native知识5-Touchable类组件
React Native 没有像web那样可以给元素绑定click事件,前面我们已经知道Text组件有onPress事件,为了给其他组件 也绑定点击事件,React Native提供了3个组件来做这件 ...
- React Native超棒的LayoutAnimation(布局动画)
该文翻译自:https://medium.com/@Jpoliachik/react-native-s-layoutanimation-is-awesome-4a4d317afd3e#.6 ...
随机推荐
- 《HelloGitHub》第 91 期
兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 HelloGitHub 分享 GitHub 上有趣.入门级的开源项目. https://github.com/521xueweiha ...
- java学习内容-2
目录 java编程基础 (一)变量的数据类型 (二)类型转换 (三)运算符 (四)数组 (五)构造函数 (六)static (七)final (八)继承1 (九)覆盖(override) (十)sup ...
- 夯实JAVA基本之一 —— 泛型详解(1):基本使用(转)
一.引入1.泛型是什么首先告诉大家ArrayList就是泛型.那ArrayList能完成哪些想不到的功能呢?先看看下面这段代码:ArrayList<String> strList = ne ...
- JS判断点是否在线段上
本文利用向量的点积和叉积来判断点是否在线段上. 基础知识补充 从零开始的高中数学--向量.向量的点积.带你一次搞懂点积(内积).叉积(外积).Unity游戏开发--向量运算(点乘和叉乘 说明 点积可以 ...
- 计算网络之IPv6配置DHCP服务及acl
一.DHCPv6服务 DHCP即动态主机地址分配协议,在前面已经启动过IPv4的动态主机分配了, 还是来介绍两种方式 接口模式 全局模式 现在需要了解的就是DHCHv6,即基于IPv6的动态主机地址分 ...
- SMTP操作使用详解并通过python进行smtp邮件发送示例
转载请注明出处: 1.SMTP SMTP 的全称是"Simple Mail Transfer Protocol",即简单邮件传输协议.它是一组用于从源地址到目的地址传输 ...
- lua面向对象(类)和lua协同线程与协同函数、Lua文件I/O
-- create a class Animal={name = "no_name" , age=0 } function Animal:bark(voice) print(sel ...
- SpringBoot实战项目:蚂蚁爱购(从零开发)
简介 这是从零开发的SpringBoot实战项目,名字叫蚂蚁爱购. 从零开发项目,视频加文档,十天彻底掌握开发SpringBoot项目. 教程路线是:搭建环境=> 安装软件=> 创建项 ...
- 怎么在Android项目中导入ffmpeg库?
1.前言 在这里我以导入静态库(.a)为例进行分析,动态库(.so)是类似的.在导入前,各位要先编译好ffmpeg库,需要注意的是在编译的时候要开启交叉编译,目标平台为Android,其他平台的库(w ...
- vue-test --------ref
<template> <div ref="contain">{{content}}</div> <button @click=" ...