View组件
View组件
是React Native
最基本的组件。View
是一个支持Flexbox
布局、样式、一些触摸处理、和一些无障碍功能的容器,并且它可以放到其它的视图里,也可以有任意多个任意类型的子视图。不论在什么平台上,View
都会直接对应一个平台的原生视图,无论它是 UIView
、div
还是 android.view.View
。
1、View组件的颜色与边框
borderStyle
的取值为enum('solid', 'dotted', 'dashed')
,用来设置边框的风格,三个值分别对应着实线边框、点状边框和虚线边框,默认值为solid
。除了可以设置边框的风格,还可以用定义边框的颜色和边框的圆角。
边框的颜色设置有
borderColor
borderTopColor
borderRightColor
borderBottomColor
borderLeftColor
取值都为string
,通常情况下用borderColor
边框的圆角设置有
borderRadius
borderTopLeftRadius
borderTopRightRadius
borderBottomLeftRadius
borderBottomRightRadius
取值为number
显示圆角
import React, { Component } from 'react';
import {
StyleSheet, View
} from 'react-native';
export default class ViewComponent extends Component {
// 设置多个view的显示样式
render() {
return (
// opacity组件透明度,取值0-1,当值为0,表示组件透明,值为1完全不透明
);
}
}
// 定义显示样式
var styles = StyleSheet.create({
container: {
flex: 1, // flex布局
justifyContent: 'space-around',
alignItems: "center", // 据中显示
backgroundColor: 'grey', // 灰色
},
welcome: {
width: 50, // 组件宽
height: 50, // 组件高
borderWidth: 1, // 边框
backgroundColor: 'white', // 指定背景颜色,如果没有指定,默认的背景颜色会浅
borderRadius: 25, // 边框圆角大小
borderStyle: "solid", // 边框风格,默认为solid(实线边框),还有dotted(点状边框) 、dashed(虚线边框)
},
});
上面代码渲染了多个View
组件,并设置了圆角和透明度
实现效果
2、View组件阴影和其他效果
下面是阴影相关的样式键
export interface ShadowStyleIOS {
shadowColor?: string; // 阴影颜色
shadowOffset?: { width: number; height: number }; // 阴影位移
shadowOpacity?: number; //阴影透明度
shadowRadius?: number; // 阴影圆角
}
设置View组件
的阴影属性并没有什么意义,在View组件
中定义这些样式是为了让继承它的组件去各自实现这些效果,比如:Text组件
需要注意的是只有iOS平台能使用shadow属性
。
elevation (Android)
elevation
取值为number
。Android
平台没有shadow
来设置阴影,但是,可以用elevation
属性来间接的设置阴影`,这样就会在界面上呈现出阴影的效果,此属性仅支持Android 5.0及以上版本。
import React, {Component} from 'react';
import {AppRegistry, StyleSheet, View} from 'react-native';
class ViewApp extends Component {
render() {
return (
);
}
}
var styles = StyleSheet.create({
shadow: {
height: 120,
width: 120,
backgroundColor: 'black',
elevation: 20,
shadowOffset: {width: 0, height: 0},
shadowColor: 'black',
shadowOpacity: 1,
shadowRadius: 5
}
});
AppRegistry.registerComponent('ViewSample', () => ViewApp);
在iOS平台运行如上代码,效果为:
在Android平台运行效果则为:
很明显,elevation的效果远远不及shadow,这时我们可以采用第三方库react-native-shadow。
overflow属性
定义当View
组件中的子组件宽高超出View
组件宽高时的行为。默认是hidden
隐藏,也可以设置visible
显示出来
3、View组件的变形
在React Native
开发中,使用transform
样式键设置组件的变形,从而实现文字或图像的变形
translate
:移动
scale
:缩放
ratate
:旋转
skew
:倾斜
样式属性如下
export interface TransformsStyle {
transform?: (
| PerpectiveTransform // 3D变换
| RotateTransform
| RotateXTransform
| RotateYTransform
| RotateZTransform
| ScaleTransform
| ScaleXTransform
| ScaleYTransform
| TranslateXTransform
| TranslateYTransform
| SkewXTransform
| SkewYTransform)[];
transformMatrix?: Array;
rotation?: number;
scaleX?: number;
scaleY?: number;
translateX?: number;
translateY?: number;
}
简单使用View的变形效果
import React, { Component } from 'react';
import {
StyleSheet, View, Text
} from 'react-native';
export default class ViewTransform extends Component {
render() {
return (
Welcome to React native!
Welcome to React native!
Welcome to React native!
Welcome to React native!
Welcome to React native!
Welcome to React native!
Welcome to React native!
Welcome to React native!
Welcome to React native!
Welcome to React native!
Welcome to React native!
);
}
}
// 定义变形样式
var transformStyles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center", // 主轴排列方向
alignItems: "center", // 次轴排列方向
backgroundColor: '#f5fcff',
},
welcome0: {
flex: 1,
justifyContent: "center",
alignItems: "center",
transform: [{rotate: '45deg'}], // 角度用xdeg来表示,这里x的取值为45,可以使用0-360任意角度
},
welcome1: {
flex: 1,
justifyContent: "center",
alignItems: "center",
transform: [{rotateX: '45deg'}],
},
welcome2: {
flex: 1,
justifyContent: "center",
alignItems: "center",
transform: [{rotateY: '45deg'}],
},
welcome3: {
flex: 1,
justifyContent: "center",
alignItems: "center",
transform: [{rotateZ: '45deg'}],
},
welcome4: {
flex: 1,
justifyContent: "center",
alignItems: "center",
transform: [{scale: 2}],
},
welcome5: {
flex: 1,
justifyContent: "center",
alignItems: "center",
transform: [{scaleX: 2}],
},
welcome6: {
flex: 1,
justifyContent: "center",
alignItems: "center",
transform: [{scaleY: 2}],
},
welcome7: {
flex: 1,
justifyContent: "center",
alignItems: "center",
transform: [{translateX: 200}],
},
welcome8: {
flex: 1,
justifyContent: "center",
alignItems: "center",
transform: [{translateY: 150}],
},
welcome9: {
flex: 1,
justifyContent: "center",
alignItems: "center",
transform: [{skewX: '45deg'}],
},
welcome10: {
flex: 1,
justifyContent: "center",
alignItems: "center",
transform: [{skewY: '45deg'}],
},
});
实现效果如下
4、合成触摸事件
用于 View
响应属性 (例如, onResponderMove
), 合成触摸事件采用以下的格式:
nativeEvent
-
changedTouches
- 从上一次事件以来的触摸事件数组。
-identifier
- 触摸事件的 ID。 -
locationX
- 触摸事件相对元素位置的 X 坐标。 -
locationY
- 触摸事件相对元素位置的 Y 坐标。 -
pageX
- 触摸事件相对根元素位置的 X 坐标。 -
pageY
- 触摸事件相对根元素位置的 Y 坐标。 -
target
- 接收触摸事件的元素 ID. -
timestamp
- 触摸事件的时间标记,用来计算速度. -
touches
- 屏幕上所有当前触摸事件的数组.
5、View组件的回调函数
假设A组件
有一个属性,名称为onB
(表示B事件发生了),它要求开发者提供的onB
的值必须是一个函数的引用,当B事件
发生时,RN框架通过onB的值
来回调这个函数。
- onMoveShouldSetResponder
这个视图想要“认领”这个touch move
事件吗?每当有touch move
事件在这个视图中发生,并且这个视图没有被设置为这个touch move
的响应时,这个函数就会被调用。
View.props.onMoveShouldSetResponder: (event) => [true | false]
其中event
是一个合成触摸事件。
- onMoveShouldSetResponderCapture
如果父视图想要阻止子视图响应touch move
事件时,它就应该设置这个方法并返回true
View.props.onMoveShouldSetResponderCapture: (event) => [true | false]
其中event
是一个合成触摸事件。
- onResponderGrant
这个视图开始响应触摸事件。此时需要高亮告诉用户正在响应。(对于大部分的触摸处理,你只需要用TouchableHighlight
或 TouchableOpacity
包装你的组件。)
- onResponderMove
当用户正在屏幕上移动手指时调用这个函数。
View.props.onResponderMove: (event) => {},
其中event
是一个合成触摸事件。
onResponderReject
有一个响应器正处于活跃状态,并且不会向另一个要求响应这个事件的视图释放这个事件。
View.props.onResponderReject: (event) => {}
其中 event
是一个合成触摸事件。
- onResponderRelease
在整个触摸事件结束时调用这个函数。
View.props.onResponderRelease: (event) => {}
其中event
是一个合成触摸事件。
- onResponderTerminate
响应被从这个视图上“劫走”了。可能是在调用了 onResponderTerminationRequest
之后,被另一个视图“劫走”了(见 onresponderterminationrequest
), 也可能是由于 OS 无条件终止了响应(比如说被 iOS 上的控制中心/消息中心)
View.props.onResponderTerminate: (event) => {}
其中event
是一个合成触摸事件
- onResponderTerminationRequest
其他某个视图想要成为事件的响应者,并要求这个视图放弃对事件的响应时,就会调用这个函数。如果允许释放响应,就返回true。
View.props.onResponderTerminationRequest: (event) => {}
其中event
是一个合成触摸事件。
- onStartShouldSetResponderCapture
如果父视图想要阻止子视图响应touch start 事件,它就应该设置这个方法并返回 true。
View.props.onStartShouldSetResponderCapture: (event) => [true | false]
其中event
是一个合成触摸事件。
- onStartShouldSetResponder
设置这个视图是否要响应touch start
事件。
View.props.onStartShouldSetResponder: (event) => [true | false]
其中event
是一个合成触摸事件。
6、屏幕设置状态与Layout函数
RN开发中,通过指定根View组件
的Layout回调函数
可以很方便的得到初始设备状态,检测设备放置状态并得到改变后新的屏幕宽度和高度
import React, {Component} from 'react';
import {
StyleSheet, View, Text
} from 'react-native';
export default class ScreenChanged extends Component {
render() {
return (
Welcome to React Native!
);
}
_onLayout(event) {
// 解构赋值
let {x,y,width,height} = event.nativeEvent.layout;
// 打印坐标
console.log('width from View onLayout: ' + width);
console.log('height from View onLayout' + height);
console.log('x from View onLayout' + x);
console.log('y from View onLayout' + y);
}
_onLayoutText(event) {
// 解构赋值
let {x,y,width,height} = event.nativeEvent.layout;
// 打印坐标
console.log('width from Text onLayout: ' + width);
console.log('height from Text onLayout' + height);
console.log('x from Text onLayout' + x);
console.log('y from Text onLayout' + y);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#f5fcff",
},
welcome: {
fontSize: 20,
textAlign: "center",
margin: 10,
},
});
7、pointerEvents属性
在开发中,很多组件被布局到屏幕上,其中有一些组件使用决定定位布局,在代码运行时的某个时刻有可能会遮盖它的位置下方的组件部分或全部。在React Native框架中,触摸事件总是被传送给最上层的组件。对于某些情况,被遮盖的组件需要处理触摸事件,这时就需要使用组件的pointerEvents属性解决
pointerEvents属性是字符串类型,可以取值为none、box-none、box-only、auto。
- 当取值
none
时,发生在本组件与子组件上的触摸事件交给本组件的父组件处理 - 当取值
box-none
,发生在本组件显示范围内(但非本组件的子组件的显示范围)的触摸事件交由本组件的父组件处理,发生在本组件的子组件显示范围内触摸事件交由子组件处理 - 当取值
box-only
,发生在本组件显示范围内的触摸事件交由本组件处理(即使触摸事件发生在子组件显示范围) - 当取值
auto
,视组件的不同而不同
简单使用
import React, {Component} from 'react';
import {
StyleSheet, View, Text
} from 'react-native';
export default class ScreenChanged extends Component {
// 构造函数
constructor(props) {
super(props);
this.state = {bigButtonPointerEvents: null};
this.onBigButtonPressed = this.onBigButtonPressed.bind(this);
this.onSmallButtonPressed = this.onSmallButtonPressed.bind(this);
}
// 按钮点击触发函数
onBigButtonPressed() {
console.log('big button pressed');
}
onSmallButtonPressed() {
if (this.state.bigButtonPointerEvents == null){
console.log('big button will not responde');
this.setState({bigButtonPointerEvents: 'none'});
return;
}
console.log('big button willresponde');
this.setState({bigButtonPointerEvents: null}); // 改变状态机变量值
}
render() {
return (
small button
big button
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
},
bigButtonStyle: { // 大按钮显示样式
fontSize: 20,
left: 130,
top: 130,
width: 150,
height: 70,
backgroundColor: 'grey',
},
smallButtonStyle: { // 小按钮显示样式
fontSize: 20,
left: 130,
top: 50,
width: 150,
height: 35,
backgroundColor: 'red',
},
});
效果如下
最开始,屏幕上的big button
可以正常工作,点击后打印输出,当点击small button
之后big button
点击无效,当再次点击small button
之后big button
点击才有效
9、removeClippedSubviews
removeClippedSubviews
的取值为bool
。它的一个特殊的与性能优化相关的属性,通常在ListView
和ScrollView
中使用,当组件有很多子组件不在屏幕显示范围时,可以将removeClippedSubviews
设置为true
,允许释放不在显示范围子组件,从而优化了性能。需要注意的是,要想让此属性生效,要确保overflow
属性为默认的hidden
。
10、动画相关
- needsOffscreenAlphaCompositing (Android)
needsOffscreenAlphaCompositing
的取值为bool
,是Android平台独有的属性。它用来决定视图是否要先离屏渲染再进行半透明度处理,来确保颜色和混合效果正确。为了正确的显示透明表现而进行离屏渲染会带来极大的开销,对于非原生开发者来说很难调试,因此,它的默认值为false。
- renderToHardwareTextureAndroid (Android)
renderToHardwareTextureAndroid
的取值为bool
,同样是是Android平台独有的属性。它用来决定视图是否要把它本身(以及所有的子视图)渲染到一个GPU上的硬件纹理中。
在Android平台上,这对于只修改透明度、旋转、位移和缩放的动画和交互是很有用的:视图不必每次都重新绘制,显示列表也不需要重新执行,纹理可以被重用于不同的参数。负面作用是这会大量消耗显存,所以当交互/动画结束后应该把此属性设置回false。
- shouldRasterizeIOS (iOS)
shouldRasterizeIOS
的取值为bool
,是iOS平台独有的属性。它决定视图是否需要在被混合之前绘制到一个位图上。
这对于动画和交互来说是有很有用的,它不会修改这个组件的尺寸和它的子组件。举例来说,当我们移动一个静态视图的位置的时候,栅格化允许渲染器重用静态视图的缓存位图,并快速合成。
栅格化会导致离屏的绘图传递,位图会消耗内存。所以使用此属性需要进行充分的测试和评估。
还有一些View属性这里没有给出,比如RN为了方便失能人士使用手机而提供的相关属性等等,具体的属性请查看官方文档。
参考
View组件