前言
本来想的上一个React项目做完,从容过完1月迎接新年,IT行业的快节奏真是不容许有这种想法;公司把3月上线的react native
项目,时间周期活生生压缩到1月底,真是哭笑不得。这样只能加加班而且保质保量地完成,还是在接口各种报错的前提下利用Mock数据。 言归正传,回到react native
项目中来
xcode配置篇
一、iOS APP图标配置
二、iOS启动页配置、各种尺寸封面大小
- 配置完成icon、launchscreen后,要重启xcode再编译方可成功,不然会有缓存
- Launch Screen苹果官方分辨率大全
TabBar配置篇
一、iPhone X 适配小技巧
- 应对iphone刘海屏statusbar颜色处理,利用
SafeAreaView
包裹整个render
<SafeAreaView style={{backgroundColor:'red'}}></SafeAreaView>
复制代码
- 上面方法虽然能达到效果,但除了statusbar,整个背景都会被color覆盖,解决办法如下。(附上stackoverflow参考链接)
<Fragment>
<SafeAreaView style={{ flex:0, backgroundColor: 'red' }} />
<SafeAreaView style={{ flex:1, backgroundColor: 'gray' }}>
<View style={{ flex: 1, backgroundColor: 'white' }} />
</SafeAreaView>
</Fragment>
复制代码
二、createBottomTabNavigator 个性化图标
1、所需要显现的效果,中间“检测”图标比较难定位
2、代码
import { createBottomTabNavigator, createAppContainer, createStackNavigator } from 'react-navigation' // 引入依赖
const TabNavigator = createBottomTabNavigator({
Home: {
screen: Home,
navigationOptions:()=>({
title:'首页',
tabBarIcon: ({tintColor,focused}) => (
focused ?
<Image source={require('...')} style={style.nav_icon}/> :
<Image source={require('...')} style={style.nav_icon}/>
)
}),
},
Community: {
screen: Community,
navigationOptions:()=>({
title:'社区',
tabBarIcon: ({tintColor,focused}) => (
focused ?
<Image source={require('...')} style={style.nav_icon}/> :
<Image source={require('...')} style={style.nav_icon}/>
),
tabBarOnPress: ({ navigation, defaultHandler }) => {
/** 触发器
* defaultHandler()、navigation.navigate('Community')
* 两个方法都能实现相同效果,跳转至 Community Component
*/
defaultHandler()
navigation.state.params.triggerAvatar()
}
})
},
Detection: {
screen: Detection,
navigationOptions:()=>({
title:'检测',
tabBarLabel: ({tintColor,focused}) => (
focused ?
<ImageBackground
resizeMode="cover"
source={require('...')}
imageStyle={styles.midIcon_img_wrap}
style={styles.midIcon_wrap}>
<Image source={require('...')} style={styles.midIcon}/>
<Text style={styles.midIcon_word}>检测</Text>
</ImageBackground>
:
<ImageBackground
resizeMode="cover"
source={require('...')}
imageStyle={styles.midIcon_img_wrap}
style={styles.midIcon_wrap}>
<Image source={require('...')} style={styles.midIcon}/>
<Text style={styles.midIcon_word}>检测</Text>
</ImageBackground>
)
}),
},
Recover: {
screen: Recover,
navigationOptions:()=>({
title:'康复',
tabBarIcon: ({tintColor,focused}) => (
focused ?
<Image source={require('...')} style={style.nav_icon}/> :
<Image source={require('...')} style={style.nav_icon}/>
)
}),
},
Me: {
screen: Me,
navigationOptions:()=>({
title:'我的',
tabBarIcon: ({tintColor,focused}) => (
focused ?
<View style={style.nav_icon_wrap}>
<Image source={require('...')} style={style.nav_icon}/>
<MsgSpot/>
</View>
:
<View style={style.nav_icon_wrap}>
<Image source={require('...')} style={style.nav_icon}/>
<MsgSpot/>
</View>
)
})
}
},{
initialRouteName:'Home', // 路由最开始访问
lazy:true, // 是否懒加载
tabBarOptions:{
activeTintColor:'#0168F5',
style:{
borderTopWidth:0,
shadowOpacity: 0.1,
shadowRadius: 5,
shadowColor: '#8B8B8B',
shadowOffset:{ width:0,height:-4 },
paddingHorizontal:16
},
labelStyle:{fontSize:10,position:'relative',top:-2},
tabStyle:{paddingTop:2}
}
})
//StackNavigator
const App = createStackNavigator({
TabNavigator: {screen: TabNavigator, navigationOptions: () => ({gesturesEnabled: true,header: null})},
HomeDetail: {screen: HomeDetail, navigationOptions: () => ({gesturesEnabled: true,header: null})}
})
console.disableYellowBox = true // 屏蔽warning弹窗
export default createAppContainer(App)
复制代码
三、TabNavigator站内消息提示小红点
思路:这种跨组件间事件操作,可以利用Redux
实现,但官方给出的是最新版本不会默认集成,那么就自己找方法怎么简单怎么来,首先考虑到的是DeviceEventEmitter
import { DeviceEventEmitter } from 'react-native' // 引入
复制代码
// spot红点事件注册
class MsgSpot extends Component<Props> {
state = { spotShow:false }
componentDidMount(){ // tabbar首次渲染订阅事件
DeviceEventEmitter.addListener('message',param => {
this.setState({spotShow:param.spotShow})
console.log(param)
})
}
render() {
const {spotShow} = this.state
return (
<Fragment>
{spotShow?<View style={[style.redSpot,style.redSpot_nav]}></View>:null}
</Fragment>
)
}
}
复制代码
DeviceEventEmitter.emit('message', {spotShow:true/false}) // 触发事件
复制代码
四、TabNavigator点击触发事情
// 详情看上面tabbar
tabBarOnPress: ({ navigation, defaultHandler }) => {
/** 触发器
* defaultHandler()、navigation.navigate('Community')
* 两个方法都能实现相同效果,跳转至 Community Component
*/
defaultHandler()
navigation.state.params.triggerAvatar()
}
复制代码
五、页面订阅事件
componentDidMount(){
// 订阅生命周期
this._listeners = this.props.navigation.addListener('willFocus', ()=>this.xxx())
}
componentWillUnmount(){
this._listeners.remove() // 移除事件订阅
}
复制代码
六、导航callback与导航事件注册
// 跳转前页面
startScan = (param) => {} // 1、注册回调
navigate('xxx',{ startScan:this.startScan ,callback:()=>{}})
// 跳转后 xxx 页面
state.params.startScan(param) // 1、触发回调
state.params.callback({}) // 2、触发callback
复制代码
滚动事件、布局篇
一、底部按钮与ScrollView样式
<SafeAreaView style={{flex:1}}>
<ScrollView></ScrollView>
<Text>Button</Text>
</SafeAreaView>
复制代码
二、FlatList 上拉、下拉实现
import {
FlatList,
RefreshControl
} from 'react-native' // 引入
constructor(props){
super(props)
this.dataListFake = [] // 列表数据
this.page = 1 // 页码
this.state = {
dataList : [], // 渲染数据
refresh : true,
pullDown: false,
isLast: false,
loading: false // 正在加载
}
}
componentDidMount() {
this._onRefresh()
}
renderItem = ({item}) => { return () }
renderFooter = () => {
// 显示时机
// 1、刚开始加载、之后,不显示
// 2、下刷新,消失
// 3、上拉加载,动画出现
// 加载完,动画消失;没有数据,显示"暂无更多"
const { pullDown, isLast } = this.state
return (
<View style={[style.footLoad,{paddingBottom:200}]}>
{pullDown?<Image source={require('../../assets/loading.gif')} style={style.footImg}/>:null}
{isLast?<Text style={style.footWord}>暂无更多~</Text>:null}
</View>
)
}
renderEmpty = () => {
return (
<View style={style.renderEmpty}>
<Text>暂无数据</Text>
</View>
)
}
// 下拉刷新
_onRefresh = () => {
const {loading} = this.state
// 是否正在loading
if (!loading){
this.page = 1
this.dataListFake = []
this.setState({refresh:true,isLast:false})
this.dataList(dataListCallBack)
}
function dataListCallBack(){
// Toast.success('刷新成功',800)
}
}
// 上拉加载
_onEndReached = () => {
return false // 没有分页
const {isLast,loading} = this.state
if (!loading){// 是否正在loading
if (isLast){
// Toast.sad('暂无更多数据~')
}else{
this.page++
this.setState({pullDown:true})
this.dataList(dataListCallBack)
}
}
function dataListCallBack(){
// Toast.message(`第${_this.page}页`,null,'center')
}
}
// 网络请求
async dataList(callBack) {
try {
this.setState({loading:true})
...
let data = {
...,
page:this.page,
r:10
}
let data_string = queryString.stringify(data)
let url = ...+'?'+data_string
const response = await axios.get(url)
setTimeout(()=>{this.setState({loading:false})},800) // complete
let code = Number(response.data.code)
let info = response.data.info
if (code===0){
let dataList = response.data.data
this.dataListFake = this.dataListFake.concat(dataList)
this.setState({dataList:this.dataListFake})
}else if (code===9000){ // 根据接口情况而定
setTimeout(()=>{this.setState({isLast:true})},800)
}else{
Toast.sad(info)
}
setTimeout(()=>{
this.setState({
refresh:false,
pullDown:false
}) // 不管数据请求如何,状态归位
},800)
console.log(response.data)
console.log(this.page)
callBack() // 假回调
} catch (error) {
this.setState({refresh:false,pullDown:false,loading:false})
Toast.fail('网络请求异常')
}
}
复制代码
render() {
const { dataList, refresh } = this.state
return (
<SafeAreaView style={[style.container,{flex:1}]}>
<StatusBar barStyle="dark-content"/>
<FlatList
contentContainerStyle={styles.introduction}
data={ dataList }
renderItem={this.renderItem}
ListFooterComponent={this.renderFooter}
ListEmptyComponent={this.renderEmpty}
keyExtractor={this._keyExtractor}
onEndReached={ this._onEndReached }
onEndReachedThreshold={0}
refreshing={refresh}
refreshControl={
<RefreshControl
refreshing={ refresh }
colors={['#ff0000', '#00ff00', '#0000ff']}
progressBackgroundColor={"#ffffff"}
onRefresh={ this._onRefresh }
/>
}
/>
</SafeAreaView>
)
}
复制代码
杂文篇
一、条形码扫描 iOS版本
react-native-smart-barcode可以解决大部分问题,集成时因为propTypes的引入没有兼容高版本导致报错,可以去Barcode.js注释掉static propTypes
// 同时利用页面订阅,达到每次显示页面重新扫描的目的
this._listeners = this.props.navigation.addListener('didFocus', ()=> this._startScan())
复制代码
二、富文本解析显示 react-native-htmlview
import HTMLView from 'react-native-htmlview' // 引入
复制代码
<HTMLView
value={htmlContent}
addLineBreaks={false} // 去掉每行之间的空格
stylesheet={styles}/>
复制代码
p:{
color:'#666666',
fontSize:15,
fontWeight:'400',
lineHeight:20,
paddingHorizontal: 0,
marginTop:5,
marginBottom:5
}
复制代码
三、swiper滑动应用 react-native-swiper
四、上传多图
要注意的是传多图时axios需要配置的地方
let config = {headers:{'Content-Type':'multipart/form-data'}}
let formData=new FormData()
xxx.forEach((val,key)=>{
let file = {uri:val.path,type:val.mime,name:val.filename?val.filename:'CAMERA_PHOTO.JPG'}
formData.append(`img${key}`,file)
})
await axios.post(url,formData,config)
复制代码
五、调起打电话
Linking.openURL(`tel:110`)
复制代码
六、react-native-image-crop-picker
图片上传遇到的iOS原生问题
1、cd /guyu/ios/podfile
2、cocoapods 安装配置
sudo gem install cocoapods
pod setup
cd ios
pod init
# 3、配置下面文件
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
# 添加至pod文件里面的配置
target 'guyu' do
pod 'RSKImageCropper'
pod 'QBImagePickerController'
end
复制代码
七、axios处理GET时,URL拼接 query-string
query-string更方便拼接url进行Get请求,也方便从url里面解析出键值对来
NPM库
- teaset
yarn add teaset
- react-native-actionsheet
yarn add react-native-actionsheet
- react-native-fit-image
yarn add react-native-fit-image
作者:ClausWong
链接:https://juejin.im/post/5c5402f8f265da2dbd7fd084
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。