【水滴石穿】react-native-app
项目地址:https://github.com/WQone/react-native-app
这个是一个非常优秀的小姐姐写的,希望大家能够以她为榜样,一起加油进步呀~
先看效果
分析package.json可以发现其实没有遇到很多很特别的组件
还是先来分析代码
//index.js
/**
* @format
*/
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);
//app.js
//主要定义的是routter
import router from './src/router/index'
//导航注册
export default router;
//index.js
import React from 'react';
import {
createStackNavigator,
createAppContainer,
createBottomTabNavigator,
createSwitchNavigator,
} from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import Login from '../views/Login/index';
import Home from '../views/Home/index';
import Mine from '../views/Mine/index';
const BottomNavigator = createBottomTabNavigator(
{
Home: {
screen: Home,
navigationOptions: {
title: '首页',
tabBarIcon: ({ focused, horizontal, tintColor }) => {
return <Ionicons name={'ios-home'} size={25} style={{ color: tintColor }} />;
},
},
},
Mine: {
screen: Mine,
navigationOptions: {
title: '我的',
tabBarIcon: ({ focused, horizontal, tintColor }) => {
return <Ionicons name={'logo-octocat'} size={25} style={{ color: tintColor }} />;
},
},
},
},
{
tabBarOptions: {
activeTintColor: '#168f48',
},
},
);
const AppNavigator = createStackNavigator(
{
Home: {
screen: BottomNavigator,
navigationOptions: () => ({
title: '首页',
headerBackTitle: null,
}),
},
},
{
headerMode: 'none',
},
);
const LoginNavigator = createStackNavigator(
{
Login: {
screen: Login,
navigationOptions: () => ({
title: '登录',
headerBackTitle: null,
}),
},
},
{
headerMode: 'none',
// navigationOptions: {
// headerStyle: {
// backgroundColor: '#f4511e',
// },
// headerTintColor: '#fff',
// headerTitleStyle: {
// fontWeight: 'bold',
// },
// },
// headerLayoutPreset: 'center',
},
);
//路由定义了初始化显示页面
const App = createSwitchNavigator(
{
LoginNavigator,
AppNavigator,
},
{
initialRouteName: 'LoginNavigator',
},
);
//导航注册
export default createAppContainer(App);
//src/utils/constance.js
//对设备类型进行了判断
/**
* 常量
*/
import { Dimensions, Platform } from 'react-native';
const { height, width } = Dimensions.get('window');
export const VALUE = {
width: width,
height: height,
ios: Platform.OS === 'ios',
android: Platform.OS === 'android',
};
//src/views/Login/index.js
import React, { Component } from 'react';
import {
StatusBar,
StyleSheet,
Image,
TouchableOpacity,
Button,
View,
Text,
TextInput,
} from 'react-native';
import SimpleLineIcons from 'react-native-vector-icons/SimpleLineIcons';
import { VALUE } from '../../utils/constance';
export default class Login extends Component {
constructor(props) {
super(props);
this.state = { user_text: '', pass_text: '' };
}
onPressButton = () => {
//跳转到home页面
this.props.navigation.navigate('Home');
};
render() {
return (
<View style={styles.container}>
<StatusBar backgroundColor="transparent" translucent barStyle={'dark-content'} />
<Image
source={require('../../assets/images/loginbg.jpeg')}
style={styles.loginBg}
resizeMode="stretch"
/>
<View style={styles.login}>
<View style={styles.InputName}>
<SimpleLineIcons name={'user'} size={21} style={{ lineHeight: 40, color: 'white' }} />
<TextInput
onChangeText={(user_text) => this.setState({ user_text })}
style={styles.Input}
autoComplete={'username'}
underlineColorAndroid={'transparent'}
maxLength={30}
placeholder={'请输入用户名'}
placeholderTextColor={'white'}
/>
</View>
<View style={styles.InputPass}>
<SimpleLineIcons name={'lock'} size={23} style={{ lineHeight: 40, color: 'white' }} />
<TextInput
onChangeText={(pass_text) => this.setState({ pass_text })}
style={styles.Input}
autoComplete={'password'}
secureTextEntry={true}
underlineColorAndroid={'transparent'}
maxLength={16}
placeholder={'请输入密码'}
placeholderTextColor={'white'}
/>
</View>
<TouchableOpacity
activeOpacity={0.9} //点击时的透明度
style={styles.InputBtn}
//点击事件,要记得绑定
onPress={this.onPressButton}
>
<Text style={{ fontSize: 16, color: '#168f48', fontWeight: 'bold' }}>立即登录</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
fontSize: 19,
},
loginBg: {
width: VALUE.width,
height: VALUE.height,
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
zIndex: -1,
},
login: {
paddingLeft: 30,
paddingRight: 30,
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
width: VALUE.width,
height: VALUE.height,
},
InputName: {
flexDirection: 'row',
height: 45,
borderColor: 'white',
borderBottomWidth: 1,
marginBottom: 20,
width: '100%',
paddingBottom: 5,
},
InputPass: {
flexDirection: 'row',
height: 45,
borderColor: 'white',
borderBottomWidth: 1,
width: '100%',
paddingBottom: 5,
},
Input: {
fontSize: 16,
padding: 0,
paddingLeft: 20,
// color: 'white',
},
InputBtn: {
marginTop: 30,
width: '100%',
height: 47,
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center', //显示Text组件居中
borderRadius: 4, //按钮圆角
alignSelf: 'center',
},
});
看点击登陆之后进入home页面效果
有封装轮播哟
//src/views/Home/index.js
import React, { Component } from 'react';
import { ScrollView, StyleSheet, Button, Text, View, Image } from 'react-native';
import { VALUE } from '../../utils/constance';
import PageScrollView from '../../components/PageScrollView';
import mockjsInit from '../../api/mock'; // 添加mockjs拦截请求,模拟返回服务器数据
import api from '../../api/page';
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {
value: '1212',
imageUrl: [
{
uri:
'https://images.pexels.com/photos/2176338/pexels-photo-2176338.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
},
{
uri:
'https://images.pexels.com/photos/2209511/pexels-photo-2209511.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
},
{
uri:
'https://images.pexels.com/photos/2236703/pexels-photo-2236703.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
},
],
};
}
componentDidMount() {
// mockjsInit();
}
onPressButton = () => {
this.setState({
value: JSON.stringify(5656),
});
api
.list()
.then((res) => {
this.setState({
value: JSON.stringify(777),
});
})
.catch((error) => {
alert(error.message);
});
};
render() {
return (
<View style={styles.container}>
<PageScrollView
style={{ width: VALUE.width, height: 210 }}
imageArr={this.state.imageUrl}
infiniteInterval={5000}
pointerColor={['#fff', '#0000', '#fff']}
pointerViewStyle={{ bottom: 10 }}
/>
<Text onPress={this.onPressButton}>{this.state.value}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f2f2f2',
fontSize: 19,
},
scrollStyle: {
height: 210,
width: VALUE.width,
},
});
看封装的轮播代码
//src/components/PageScrollView.js
import React, { Component } from 'react';
import {
View,
ScrollView,
Platform,
Dimensions,
InteractionManager,
Image,
TouchableOpacity,
ImageBackground,
} from 'react-native';
const { width: w, height: h } = Dimensions.get('window');
class PageScrollView extends Component {
constructor(props) {
super(props);
this.initState();
}
//初始化state的值
initState = () => {
this.state = {
//当前滚动到哪一页
currentPage: 0,
//整数形式的currentPage
intCP: -1,
//总共有几页
pageNum: this.props.imageArr.length || this.props.datas.length,
//记录当前是否为手指拖拽
ifTouch: false,
// 当onScroll水平滚动时的滚动大小(x值)的数组
scrollXArr: [],
// 当onScroll垂直滚动时的滚动大小(x值)的数组
scrollYArr: [],
//scrollView是否可以滚动
scrollEnabled: true,
//ScrollView自身View的宽高
viewHeight: 0,
viewWidth: 0,
width: 0,
height: 0,
//记录是否是首次
ifFirst: true,
};
};
static defaultProps = {
//使用官方提供的哪一个内置样式
builtinStyle: null,
//使用内置样式时用户自定义的图片宽高
builtinWH: {},
//设置整个组件View的style样式
style: {},
//轮播图片的数组(该数组存在时使用该数组,datas数组失效)
imageArr: [],
//如果是传入图片数组时,自定义的图片样式(该属性在自定义View时无用)
imageStyle: null,
// ccStyle:null,
//自定义view中对应的数据数组
datas: [],
//每一个自定义View的具体渲染
view: () => {},
//每一个View的宽高(当滚动到当前这个View时的宽高,用于View的宽高会随滚动改变时才用){width:宽度,height:高度}
// contentWH:null,
//速度大于多少时为有向左(右,上,下)翻一页的意图(数值越大,要滑动速度越快(越难)才能到下一页,数值越小,滑动越慢(越容易)可以到下一页,)
goToNextPageSpeed: 3,
//水平还是竖直方向的ScrollView
HorV: 'h',
//是否无限轮播(无限滚动)
ifInfinite: true,
//是否自动轮播
ifAutoScroll: true,
//自动轮播每张切换的时长(毫秒)
infiniteInterval: 2000,
//图片的显示形式
resizeMode: 'cover',
//点击图片时执行的操作(不是自定义View的时候)
dealWithClickImage: null,
//在当前滚动到的页面改变时调用的方法
currentPageChangeFunc: null,
//是否允许用户手动滚动ScrollView
scrollEnabled: true,
//组件加载好后,并且布局好得到相应宽高后的执行的操作
didMount: null,
//当滚动到当前页的大小为正常大小的多大
// sizeLarge:1,
//自定义View时滚动到旁边时的大小为正常大小的多大
sizeSmall: null,
//自定义View时滚动到旁边时的透明度
opacitySmall: null,
//自定义View时滚动到旁边时旋转的角度
rotateDeg: null,
//自定义View时滚动到旁边时的图片的倾斜角度
skewDeg: null,
//是否显示当前图片指示器View(下面的点)
ifShowPointerView: true,
//指示器的的相关颜色.分别为:当前页的颜色,其他页的颜色,边框的颜色
pointerColor: ['#fff', '#0000', '#fff'],
//自定义指示器View的样式(绝对定位的top,bottom...)
pointerViewStyle: null,
//自定义指示器圆点的样式(圆点大小)
pointerStyle: null,
//自定义指示器View
renderPointerView: null,
};
//官方设置的内置样式的各个参数
builtinStyleArgs = {
sizeChangeMode: { sS: 0.7, oS: 0.7, bg: '#999' },
rotateChangeMode: { rS: 45, skewS: 45, oS: 0.5, sS: 0.5, bg: '#999' },
};
//官方设置的内置样式
builtinStyles = {
sizeChangeMode: (index, data, { size, opacity }) => {
let { viewWidth, viewHeight } = this.state;
let { HorV, builtinWH } = this.props;
let isH = HorV === 'h';
let customW = null,
customH = null;
if (builtinWH) {
customW = builtinWH.width;
customH = builtinWH.height;
}
let widimage = customW || w * 0.6,
wid = isH ? widimage : viewWidth,
hei = isH ? viewHeight : customH || (widimage / 16) * 9,
heimage = customH || (widimage / 16) * 9;
return (
<View
style={[
{
width: wid,
height: hei,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#999',
opacity: opacity,
},
]}
onLayout={this.contentLayout}
>
<Image source={data} style={{ width: widimage * size, height: heimage * size }} />
</View>
);
},
rotateChangeMode: (index, data, { rotate, opacity, size }) => {
let isios = Platform.OS === 'ios';
let { rS, sS } = this.builtinStyleArgs['rotateChangeMode'];
let { viewWidth, viewHeight } = this.state;
let { HorV, builtinWH } = this.props;
let Image = ImageBackground || Image;
let isH = HorV === 'h';
let customW = null,
customH = null;
if (builtinWH) {
customW = builtinWH.width;
customH = builtinWH.height;
}
let widimage = customW || (isH ? w * 0.5 : w * 0.7),
wid1 = isH ? widimage : viewWidth,
hei1 = isH ? viewHeight : customH || (widimage / 16) * 9,
heimage = customH || (widimage / 16) * 9,
hei = hei1,
wid = wid1;
let LH = hei,
LW = wid;
if (isH) {
rotate ? (wid = Math.cos(Math.PI * (rotate / 180)) * wid1 * size) : (wid = wid1);
} else {
rotate ? (hei = Math.cos(Math.PI * (rotate / 180)) * hei1 * size) : (hei = hei1);
}
let SH = Math.cos(Math.PI * (rS / 180)) * hei1 * sS,
SW = Math.cos(Math.PI * (rS / 180)) * wid1 * sS;
return (
<View
style={[
{
width: wid,
height: hei,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#999',
opacity: opacity,
transform: [
isH ? { rotateY: rotate + 'deg' } : { rotateX: rotate + 'deg' },
isH
? { skewY: rotate + 'deg' }
: isios
? { skewX: rotate + 'deg' }
: { skewY: -rotate + 'deg' },
],
},
]}
onLayout={(e) => {
!this.distance && this.setDistance1(null, LW, LH, SW, SH);
}}
>
<Image source={data} style={{ width: widimage * size, height: heimage * size }}>
<View
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: '#000',
opacity: 1 - opacity,
}}
/>
</Image>
</View>
);
},
};
render() {
let { style, builtinStyle } = this.props;
let { builtinStyles, builtinStyleArgs } = this;
return (
<View
style={[
style || { flex: 1 },
builtinStyle && { backgroundColor: builtinStyleArgs[builtinStyle].bg },
]}
onLayout={this.viewOnLayout}
>
<ScrollView
// 设置引用名称,让下面可以引用到
ref={(ps) => {
this.scrollView = ps;
}}
style={{ flex: 1 }}
scrollEnabled={this.props.scrollEnabled && this.state.scrollEnabled}
// 是否是水平的scrollView(默认为水平方向的)
horizontal={this.props.HorV === 'h'}
// 是否显示水平方向的滚动条
showsHorizontalScrollIndicator={false}
// 是否显示竖方向的滚动条
showsVerticalScrollIndicator={false}
// 开始拖拽
onScrollBeginDrag={this.onScrollBeginDrag}
// 停止拖拽
onScrollEndDrag={this.onScrollEndDrag}
onScroll={(e) => this.onScroll(e)}
//多少毫秒触发一次上面的onScroll方法
scrollEventThrottle={20}
onLayout={this.scrollViewOnLayout}
>
{/*渲染scrollView*/}
{this.renderScrollView()}
</ScrollView>
{/*渲染下面的指示器*/}
{this.props.ifShowPointerView && this.renderPointer()}
</View>
);
}
//view加载好之后
viewOnLayout = () => {
this.state.ifFirst && this.props.didMount && this.props.didMount();
this.state.ifFirst && (this.state.ifFirst = false);
};
//scrollView加载好后,自身的尺寸
scrollViewOnLayout = (event) => {
let { width, height } = event.nativeEvent.layout;
this.setState({ viewHeight: height, viewWidth: width }, () => {});
};
//图片加载好后的尺寸
imageLayout = (event) => {
this.getContentStyle(event);
};
//每个分页view加载好后的尺寸
contentLayout = (event) => {
this.getContentStyle(event);
};
//获得每一页内容的样式(宽高)
getContentStyle = (event) => {
if (this.distance) {
return;
}
let { width, height } = event.nativeEvent.layout;
this.setDistance(width, height);
};
//设置this.state的宽高和distance
setDistance = (width, height) => {
if (this.distance) {
return;
}
let isH = this.props.HorV === 'h';
this.setState({ width: width, height: height }, () => {
this.distance = isH ? this.state.width : this.state.height;
});
};
//设置this.state的宽高和distance(有旋转,缩放时,即当前滚动到的图片与旁边的图片大小不一样时)
setDistance1 = (event, LargeWidth, LargeHeight, SmallWidth, SmallHeight) => {
if (this.distance) {
return;
}
let isH = this.props.HorV === 'h';
if (event) {
let { width, height } = event.nativeEvent.layout;
this.setDistance(width, height);
} else {
this.setState({ width: LargeWidth, height: LargeHeight }, () => {
this.distance = isH ? SmallWidth : SmallHeight;
});
}
};
//渲染下面的指示器
renderPointer = () => {
let { pointerColor: pc, renderPointView } = this.props;
let viewArr = [];
let currentPage = this.getintCP();
let datas = this.props.imageArr.length ? this.props.imageArr : this.props.datas;
for (let i = 0; i < datas.length; i++) {
let selected = i === currentPage;
viewArr.push(
renderPointView ? (
<View key={i}>{renderPointView(selected)}</View>
) : (
<View
key={i}
style={[
{ width: 8, height: 8, borderRadius: 4, borderColor: pc[2], borderWidth: 1 },
i && { marginLeft: 10 },
selected ? { backgroundColor: pc[0] } : { backgroundColor: pc[1] },
this.props.pointerStyle,
]}
/>
),
);
}
return (
<View
style={[
{
position: 'absolute',
bottom: this.state.viewHeight / 10,
flexDirection: 'row',
width: this.state.viewWidth,
justifyContent: 'center',
},
this.props.pointerViewStyle,
]}
>
{viewArr}
</View>
);
};
//获得整数型的当前滚动页面
getintCP() {
let currentPage = Math.round(this.state.currentPage);
let ifInfinite = this.props.ifInfinite;
ifInfinite && (currentPage %= this.state.pageNum);
return currentPage;
}
//获得整数型滚动页面后的操作
dealWithIntCP() {
let currentPage = this.getintCP();
if (currentPage !== this.state.intCP) {
this.props.currentPageChangeFunc && this.props.currentPageChangeFunc(currentPage);
this.state.intCP = currentPage;
}
}
// 渲染scrollView
renderScrollView = () => {
let {
imageArr,
datas,
ifInfinite,
dealWithClickImage: dealClick,
sizeSmall,
opacitySmall,
rotateDeg,
skewDeg,
imageStyle,
resizeMode,
HorV,
builtinStyle,
} = this.props;
let { viewWidth, width, viewHeight, height, pageNum, currentPage } = this.state;
let { builtinStyles, builtinStyleArgs } = this;
this.dealWithIntCP();
//datas数据
datas = imageArr.length ? imageArr : datas;
ifInfinite && (datas = [...datas, ...datas, ...datas]);
//当滚动到当前页的大小为正常大小的多大
let sL = 1;
//当滚动到旁边时的大小为正常大小的多大
let sS = sizeSmall;
// let sS=0.5;
let oL = 1;
//滚到旁边时的透明度
let oS = opacitySmall;
//滚动到旁边时的旋转角度
let rS = rotateDeg;
//滚动到旁边时的倾斜角度
let skewS = skewDeg;
if (builtinStyle) {
let args = builtinStyleArgs[builtinStyle];
({ sS, oS, rS, skewS } = args);
}
let arr = [];
if (HorV === 'h') {
//当滚动到第一张时的左边空白部分
arr.push(
<View
key={-2}
style={{ width: (viewWidth - width) / 2, height: viewHeight, backgroundColor: '#0000' }}
/>,
);
} else {
//竖直ScrollView时
arr.push(
<View
key={-2}
style={{ width: viewWidth, height: (viewHeight - height) / 2, backgroundColor: '#0000' }}
/>,
);
}
for (let i = 0; i < datas.length; i++) {
let size = 1;
let opacity = 1;
let rotate = 0;
let skew = 0;
let distance;
if (sS || oS || rS || skewS) {
distance = Math.abs(currentPage - i);
if (distance >= 1) {
size = sS;
opacity = oS;
rotate = rS;
skew = skewS;
} else {
size = sL - distance * (sL - sS);
opacity = oL - distance * (oL - oS);
rotate = distance * rS;
skew = distance * skewS;
}
}
if (this.props.imageArr.length) {
let style = imageStyle || { width: viewWidth, height: viewHeight };
if (builtinStyle) {
arr.push(
<TouchableOpacity
activeOpacity={dealClick ? 0.5 : 1}
onPress={() => {
dealClick && dealClick(i % this.pNum);
}}
key={i}
style={[]}
>
{/*<TouchableOpacity activeOpacity={dealClick?0.5:1} onPress={()=>{dealClick&&dealClick(i%this.pNum)}} key={i} style={[]} onLayout={this.contentLayout}>*/}
{builtinStyles[builtinStyle](i % pageNum, datas[i % pageNum], {
size,
opacity,
rotate,
skew,
})}
</TouchableOpacity>,
);
} else {
arr.push(
<TouchableOpacity
activeOpacity={dealClick ? 0.5 : 1}
onPress={() => {
dealClick && dealClick(i % this.pNum);
}}
key={i}
style={style}
onLayout={this.imageLayout}
>
<Image source={datas[i]} style={[style, { resizeMode: resizeMode }]} />
</TouchableOpacity>,
);
}
} else {
arr.push(
<View
key={i}
style={[]}
onLayout={(event) => {
sS || oS || rS || skewS ? this.setDistance1(event) : this.contentLayout(event);
}}
>
{sS || oS || rS || skewS
? this.props.view(i % pageNum, datas[i % pageNum], { size, opacity, rotate, skew })
: this.props.view(i % pageNum, datas[i % pageNum])}
</View>,
);
}
}
if (HorV === 'h') {
//当滚动到最后一张时的右边的空白部分
arr.push(
<View
key={-3}
style={{ width: (viewWidth - width) / 2, height: viewHeight, backgroundColor: '#0000' }}
/>,
);
} else {
//竖直方向
arr.push(
<View
key={-3}
style={{ width: viewWidth, height: (viewHeight - height) / 2, backgroundColor: '#0000' }}
/>,
);
}
return arr;
};
//开始拖拽
onScrollBeginDrag = (e) => {
this.state.ifTouch = true;
this.state.scrollXArr = [];
this.state.scrollYArr = [];
this.stopInfiniteInterval();
};
// 停止拖拽(升级后2)
onScrollEndDrag = (e) => {
this.state.ifTouch = false;
this.props.ifInfinite && this.setState({ scrollEnabled: false });
let speed = this.props.goToNextPageSpeed;
let contentOffset = this.isH ? e.nativeEvent.contentOffset.x : e.nativeEvent.contentOffset.y;
let scrollArr = this.isH ? this.state.scrollXArr : this.state.scrollYArr;
let speed1 = scrollArr[scrollArr.length - 1] - scrollArr[scrollArr.length - 2];
let speed2 = scrollArr[scrollArr.length - 2] - scrollArr[scrollArr.length - 3];
let speed3 = scrollArr[scrollArr.length - 3] - scrollArr[scrollArr.length - 4];
let speed4 = scrollArr[scrollArr.length - 1] - scrollArr[0];
let currentPage;
if (Math.abs(speed1) > speed || Math.abs(speed2) > speed || Math.abs(speed3) > speed) {
// 速度(speed1,2,3)绝对值大于设定值时为有向左(右,上,下)翻一页的意图
//speed4>0向右(上)翻(想去(下)(右)一页的意图)
//speed4<0向左(下)翻(想去(上)(左)一页的意图)
currentPage =
speed4 > 0
? Math.ceil(contentOffset / this.distance)
: Math.floor(contentOffset / this.distance);
} else {
currentPage = Math.round(contentOffset / this.distance);
}
//滚动到相应的界面
this.scrollToPage(currentPage);
//如果设置了自动轮播,则重新开启定时器
this.props.ifAutoScroll && this.setInfiniteInterval();
};
// 当滚动scrollView的时候(升级后)
onScroll = (e) => {
let scrollPage;
if (this.isH) {
// scrollView当前滚动的数值
this.state.scrollXArr.push(e.nativeEvent.contentOffset.x);
scrollPage = e.nativeEvent.contentOffset.x / this.distance;
} else {
// scrollView当前滚动的数值
this.state.scrollYArr.push(e.nativeEvent.contentOffset.y);
scrollPage = e.nativeEvent.contentOffset.y / this.distance;
}
if (
this.props.ifInfinite &&
Math.abs(scrollPage - Math.ceil(scrollPage)) < 0.1 &&
!this.state.ifTouch
) {
//处理无限轮播,自动轮播滚动时的情况
setTimeout(() => {
this.infiniteScroll(Math.ceil(scrollPage));
}, 200);
} else {
this.setState({ currentPage: scrollPage });
}
};
//无限轮播时对滚动的处理
infiniteScroll = (currentPage) => {
if (currentPage < this.pNum || currentPage >= this.pNum * 2) {
currentPage = (currentPage % this.pNum) + this.pNum;
this.scrollToPage(currentPage, false);
}
//更新状态机
this.setState({
//当前页码
currentPage: currentPage,
scrollEnabled: true,
});
};
//根据传入的要滚动到的页面数,滚动到相应的页面
scrollToPage = (currentPage, animated = true) => {
let pageNum = this.props.ifInfinite ? this.pNum * 3 : this.pNum;
if (currentPage > pageNum - 1) {
currentPage = pageNum - 1;
}
if (currentPage < 0) {
currentPage = 0;
}
try {
this.isH
? this.scrollView.scrollTo({ x: currentPage * this.distance, animated: animated })
: this.scrollView.scrollTo({ y: currentPage * this.distance, animated: animated });
} catch (e) {}
};
//父组件中使用ref手动滚动的方法
manualScrollToPage = (currentPage, animated = true) => {
if (this.props.ifInfinite && animated) {
currentPage < this.pNum && (currentPage += this.pNum);
currentPage >= this.pNum * 2 && (currentPage -= this.pNum);
} else {
if (currentPage > this.pNum - 1) {
currentPage = this.pNum - 1;
}
if (currentPage < 0) {
currentPage = 0;
}
}
this.isH
? this.scrollView.scrollTo({ x: currentPage * this.distance, animated: animated })
: this.scrollView.scrollTo({ y: currentPage * this.distance, animated: animated });
};
//设置轮播的定时器
setInfiniteInterval = () => {
let interval = this.props.infiniteInterval < 1000 ? 1000 : this.props.infiniteInterval;
this.timer = setInterval(() => {
let currentPage = Math.round(this.state.currentPage + 1);
!this.props.ifInfinite && currentPage >= this.pNum && (currentPage = 0);
this.scrollToPage(currentPage);
}, interval);
};
//清除轮播定时器
stopInfiniteInterval = () => {
this.timer && clearInterval(this.timer);
};
componentDidMount() {
this.isH = this.props.HorV === 'h';
this.pNum = this.state.pageNum;
this.props.ifAutoScroll && this.setInfiniteInterval();
}
didMount = () => {
if (this.props.ifInfinite) {
let isH = this.props.HorV === 'h';
if (Platform.OS !== 'ios') {
InteractionManager.runAfterInteractions(() => {
this.scrollView.scrollTo(
isH
? { x: this.state.pageNum * this.distance, animated: false }
: { y: this.state.pageNum * this.distance, animated: false },
);
});
} else {
this.scrollView.scrollTo(
isH
? { x: this.state.pageNum * this.distance, animated: false }
: { y: this.state.pageNum * this.distance, animated: false },
);
}
}
};
componentWillUpdate() {}
componentWillUnmount() {
this.stopInfiniteInterval();
}
}
//输出组件类
export default PageScrollView;
固定了底部
///src/router/index.js
import React from 'react';
import {
createStackNavigator,
createAppContainer,
createBottomTabNavigator,
createSwitchNavigator,
} from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import Login from '../views/Login/index';
import Home from '../views/Home/index';
import Mine from '../views/Mine/index';
const BottomNavigator = createBottomTabNavigator(
{
Home: {
screen: Home,
navigationOptions: {
title: '首页',
tabBarIcon: ({ focused, horizontal, tintColor }) => {
return <Ionicons name={'ios-home'} size={25} style={{ color: tintColor }} />;
},
},
},
Mine: {
screen: Mine,
navigationOptions: {
title: '我的',
tabBarIcon: ({ focused, horizontal, tintColor }) => {
return <Ionicons name={'logo-octocat'} size={25} style={{ color: tintColor }} />;
},
},
},
},
{
tabBarOptions: {
activeTintColor: '#168f48',
},
},
);
const AppNavigator = createStackNavigator(
{
Home: {
screen: BottomNavigator,
navigationOptions: () => ({
title: '首页',
headerBackTitle: null,
}),
},
},
{
headerMode: 'none',
},
);
const LoginNavigator = createStackNavigator(
{
Login: {
screen: Login,
navigationOptions: () => ({
title: '登录',
headerBackTitle: null,
}),
},
},
{
headerMode: 'none',
// navigationOptions: {
// headerStyle: {
// backgroundColor: '#f4511e',
// },
// headerTintColor: '#fff',
// headerTitleStyle: {
// fontWeight: 'bold',
// },
// },
// headerLayoutPreset: 'center',
},
);
//路由定义了初始化显示页面
const App = createSwitchNavigator(
{
LoginNavigator,
AppNavigator,
},
{
initialRouteName: 'LoginNavigator',
},
);
//导航注册
export default createAppContainer(App);
home页面中的数据处理很隐蔽
componentDidMount() {
// mockjsInit();
}
onPressButton = () => {
this.setState({
value: JSON.stringify(5656),
});
api
.list()
.then((res) => {
this.setState({
value: JSON.stringify(777),
});
})
.catch((error) => {
alert(error.message);
});
};
//mine页面很神奇啊,它其实没有定义下面的导航切换啊,为啥它有啊
//并没有引入navigation但是却可以用
import React, { Component } from 'react';
import { StyleSheet, ScrollView, Button, Text, View } from 'react-native';
export default class Home extends Component {
render() {
return (
<View style={styles.container}>
<Text>MineScreen Screen</Text>
<Button title="Go to Login" onPress={() => this.props.navigation.navigate('Login')} />
<Button title="Go to Mine" onPress={() => this.props.navigation.navigate('Mine')} />
<Button title="Go back" onPress={() => this.props.navigation.goBack()} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
fontSize: 19,
},
});
//其实我觉得mine中的代码有问题
作者:jser_dimple
-------------------------------------------
个性签名:一个人在年轻的时候浪费自己的才华与天赋是一件非常可惜的事情
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
万水千山总是情,打赏5毛买辣条行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!
微信
支付宝