每天一点点
1
1. 创建指定版本
react-native init demo --version 0.55.4 指定版本
2. 跨页面传值
DeviceEventEmitter事件传值
// 引入
import {
...
DeviceEventEmitter
} form 'react-native';
//发送事件的页面
DeviceEventEmitter.emit('userNameDidChange', '传值');
//需要接收事件的页面
componentDidMount() {
this.subscription = DeviceEventEmitter.addListener('userNameDidChange',(userName) =>{
alert(userName);
})
}
//页面卸载 移除事件
componentWillUnmount() {
this.subscription.remove();
}
3. import 导入的几种方式
import Home from './src/Home';
导入‘src/Home’文件里export的带default关键字的组件,即默认组件
2.import { Home,Me } from './src/Home';
导入‘src/Home’文件里export的叫Home和Me的非默认组件,可以导入多个组件,用逗号隔开即可
3.import * as Home from'./src/Home';
意思是将./src/Home'文件里的所有非默认组件,全部集结成一个Home模型组件,命名可以自定义,然后可以通过点语法,来使用组件里面的所有export的组件, 如 Home.A 、Home.B
4. 调用打电话功能
Linking提供了一个通用的接口来与传入和传出的App链接进行交互,比如跳转外部链接,打电话,发邮件,打开某个浏览器链接等
//导入Linking
import {
...
Linking
} from "react-native";
...
call(){
let url = 'tel: ' + '电话号码';
//let url = "mqqwpa://im/chat?chat_type=wpa&uin=QQ号";//调用QQ
Linking.canOpenURL(url).then(supported => {
if (!supported) {
console.log('Can\'t handle url: ' + url);
} else {
Linking.openURL(url);
}
}).catch(err => console.error('An error occurred', err));
}
5. 复制到剪贴板
//导入Clipboard
import {
...
Clipboard
} from "react-native";
//复制电话号码到剪贴板
async _setClipboardContent(tel){
Clipboard.setString(tel);
try {
var content = await Clipboard.getString();
console.log('复制的手机号:');
this.clearClose();
console.log(content);
} catch (e) {
console.log(e.message)
}
}
6. react-navigation 隐藏/显示tabBar
const Tab = TabNavigator(
{
Home: {
screen: HomeScreen,
/* TabBar是否显示/隐藏 */
navigationOptions: ({ navigation }) => {
// console.log('nav state:', navigation.state);
const homeRoute = navigation.state.params;
return {
/**
* 控制tabBar是否显示/隐藏
* 在HomeScreen 页面通过 this.props.navigation.setParams({ tabBarVisible: false/true })控制--
*/
tabBarVisible: homeRoute && homeRoute.tabBarVisible,
}
}
},
....
},
{
....
}
7. 获取Navigator的层级
var currentRoute = this.props.navigator.getCurrentRoutes();
for(var i = 0 ; i
if (currentRoute[i].name == '你想跳转的页面'){
this.props.navigator.popToRoute(currentRoute[i]);
}
}
8. ImageBackground 的圆角在 style 里设置没用 需要用imageStyle
9. 使得任何一个React组件支持动画。
Animated.createAnimatedComponent(Component: any)可以使任何一个React组件支持动画。 默认支持的Animated.Image,Animated.ScrollView,Animated.Text,Animated.View。
Animated FlatList需使用ref属性时 加入以下代码:
ref={(ref) => { this._listRef = ref}}
...
/>
//使用方法
this._listRef.getNode().scrollToOffset({y:0})
10. view 三角冒泡框
// 设置上下越小,三角就越尖
width: 0,
height: 0,
borderTopWidth: 7,
borderTopColor: 'transparent',
borderRightWidth: 10,
borderRightColor: 'red',
borderLeftWidth: 10,
borderLeftColor: 'transparent',
borderBottomWidth: 7,
borderBottomColor: 'transparent',
}} />
11. android环境下gif没有动画,不支持gif图
解决:
在android/app/build.gradle中的dependencies字段中添加:
compile 'com.facebook.fresco:fresco:1.5.0'
compile 'com.facebook.fresco:animated-gif:1.5.0'
12. 性能调试及优化
开发模式 (dev=true)
有个小技巧可以在发布时屏蔽掉所有的console.*调用。React Native中有一个全局变量__DEV__用于指示当前运行环境是否是开发环境。我们可以据此在正式环境中替换掉系统原先的console实现。
if(!__DEV__ ){
global.console={
log:() => {},
info:() => {},
assert: () => {},
warn:() => {},
debug:() => {},
error:() => {}
}
}
_DEV_=true即开发模式下,JavaScript线程的性能是很糟糕的,因为有许多工作需要在运行的时候去做,譬如使你获得良好的警告和错误信息,又比如验证属性类型(propTypes)以及产生各种其他的警告。
13. 使用webview加载html乱码问题
...
source={{uri:this.state.html, baseUrl:''}} // baseUrl:'' 中文乱码解决
/>
14. 字体不随系统字体设置改变而改变
方法一:
const {fontScale} = Dimensions.get('screen');
fontSize: 20*(1.0/fontScale)
方法二:
import { Text, TextInput } from 'react-native'
TextInput.defaultProps = Object.assign({}, TextInput.defaultProps, {defaultProps: false});
Text.defaultProps = Object.assign({}, Text.defaultProps, {allowFontScaling: false});
15. xcode10.1 0.55.4-0.56 'config.h' file not found
error:Build input file cannot be found: '/Users/taocong/Desktop/RNProject/AppDemo/node_modules/react-native/third-party/
cd node_modules/react-native/third-party/glog-0.3.4
../../scripts/ios-configure-glog.sh
16.通过findNodeHandle和UIManager来获取组件的尺寸:
import {
findNodeHandle,
UIManager
} from 'react-native';
layout(ref) {
const handle = findNodeHandle(ref);
return new Promise((resolve) => {
UIManager.measure(handle, (x, y, width, height, pageX, pageY) => {
resolve({
x,
y,
width,
height,
pageX,
pageY
});
});
});
}
layout这个函数接受一个ref参数,这个参数表示组件的实例。传入组件的实例后,然后通过findNodeHandle方法获取组件节点。
UIManager.measure接受两个参数,第一个参数是通过findNodeHandle获取的组件节点,第二个参数是获取成功的回调,回调有6个参数:x,y表示组件的相对位置,width,height表示组件的宽度和高度,pageX,pageY表示组件相对于屏幕的绝对位置。
17.PanResponder
onPanResponderMove 和 Animated.event() 的结合使用
利用 PanResponder 做了一个拖动调节图标位置的功能,网上找的方法是在 onPanResponderMove 中使用 Animated.event() 来对 View 进行移动。实现效果不错,但是发现一旦在 onPanResponderMove 中使用了 lambda 表达式后,就不起作用了。后来网上找到这个 issue,发现原来 Animated.event() 会返回一个方法,并且接收 event 和 gestureState 作为参数,所以我们只要去调用一下这个方法即可:
onPanResponderMove: (evt, gestureState) => {
return Animated.event([null, {
dx: this.state.pan.x,
dy: this.state.pan.y,
}])(evt, gestureState)
}
18.TextInput Android 文字对齐问题
当 TextInput multiline为true,发现文字显示在 iOS 上是顶端对齐,而在 Android 上则文本默认会垂直居中,可设置textAlignVertical: 'top'样式来使其居顶显示。
解决方法 TextInput 设置 textAlignVertical: "top" 属性,相关 issue 见:Render Multiline Text at start instead of center
Android 上 TextInput 失去焦点之后键盘无法自动收起
这时候我们可以给根布局设置接收触摸事件:
onStartShouldSetResponder={() => true}
onResponderRelease={() => Keyboard.dismiss()}
19.KeyboardAvoidingView behavior 相关
该组件在 Android 和 iOS 上的表现有区别,所以我们会区分平台使用不同的 behavior,比如下面这样:
style={styles.container}
behavior={Platform.OS === 'android' ? null : 'padding'}
keyboardVerticalOffset={64}>
...
padding 模式下,当键盘弹起的时候,你的 view 会向上弹起并被压缩。使用 padding 作为 behavior 的时候,在 iOS 上表现比较好,而在 Android 上则不设置 behavior 比较好。
position 模式下,view 整体会向上滑动。这种模式 Android 和 iOS 上表现一致,但是前提是此时 KeyboardAvoidingView 是根 view。同时这也会造成一个问题,那就是键盘弹出后,输入组件会一直占有焦点,这在安卓上还好,可以通过返回键关闭键盘,而在 iOS 设备上就会造成键盘无法被关闭的尴尬。解决这一问题的方法是通过在 KeyboardAvoidingView 设置接收触摸事件,当在输入焦点之外获得点击时收起键盘:
style={styles.container}
behavior={'position'}
onStartShouldSetResponder={(evt) => true}
onResponderRelease={() => Keyboard.dismiss()}
/>
20. FlatList onEndReached 刷新次数频繁问题
onEndReached={()=>{
// 等待页面布局完成以后,在让加载更多
if (this.isCanLoadMore){
this.loadMore();
this.isCanLoadMore = false // 加载更多时,不让再次的加载更多
}
}}
onContentSizeChange={()=>{
this.isCanLoadMore = true // flatview内部组件布局完成以后会调用这个方法
}}
onEndReachedThreshold={0.01}
21 view阴影
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 4,
},
shadowOpacity: 0.30,
shadowRadius: 4.65,
elevation: 8,
22 .解决Modal无法有效隐藏状态栏
编辑android/app/src/main/resvalues/styles/styles.xml
23 .RN离线包准备
android
react-native bundle --entry-file index.js --bundle-output ./android/app/src/main/assets/index.android.bundle --platform android --assets-dest ./android/app/src/main/assets --dev false
iOS:
react-native bundle --entry-file index.js --platform ios --dev false --bundle-output ./ios/bundle/index.ios.jsbundle --assets-dest ./ios/bundle
Duplicate resources报错的话
在 /node_modules/react-native/react.gradle 这个文件里加上以下代码
doFirst { ... }
doLast {
def moveFunc = { resSuffix ->
File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
if (originalDir.exists()) {
File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
ant.move(file: originalDir, tofile: destDir);
}
}
moveFunc.curry("ldpi").call()
moveFunc.curry("mdpi").call()
moveFunc.curry("hdpi").call()
moveFunc.curry("xhdpi").call()
moveFunc.curry("xxhdpi").call()
moveFunc.curry("xxxhdpi").call()
}
24. xcode11 0.61.5 react-native-fast-image pod fatal: unable to access 'https://chromium.googlesource.com/webm/libwebp/'
image.png
解决
Finder -> 前往文件夹 (⇧⌘G) -> ~/.cocoapods/repos/master/Specs/1/9/2/libwebp点击最新版本
把https://chromium.googlesource.com/webm/libwebp 替换为 https://github.com/webmproject/libwebp.git 并保存重新pod即可