用React-native写一个卡的要死的日历选择器
需求背景:有一天,设计给了一个比较漂亮的日历选择页面,要用RN实现。个人感觉是用不了什么巧妙的方法了,只能是用FlatList去一个个的实现。实现出来后呢,发现很卡(在Android上基本不能跑,想control + C的同学看到这里可以撤了,因为这个用不了)。
先上个别人家的效果图:

然后是自己家的效果图:

我拍胸脯保证,别人家的一定是用原生的实现的......
实现思路
需求:实现一个自当日起,往前一年的日期选择器,显示12个月的日期。选择完毕后,返回两个日期,按照时间早晚的顺序装入数组中返回。
思路逻辑:
1、需要计算出月份的范围。(当前月回溯12个月)
2、需要计算出每个月有几周的跨度。
- 7 * 4 的情况
- 7 * 5 的情况(最常见)
- 7 * 6 的情况
3、 将计算好的数据,放入到一个以周为单位的二维数组中,即日历表为一个7 * N的矩阵。(为了方便期间,我们以月为单位,每个月为一个矩阵数组,然后将月放入到年的数组里)
布局思路:
1、利用FlatList进行布局。
2、日期的头部悬浮单独制作。
思路完了我们来撸代码
首先,创建数据管理类
Calendar.js
定义数据:
// 定义“日”的结构
type DateDay = {
dateValue: number,
weekDay : number,
isToday : boolean,
notCurrentMonth: boolean,
}
// 定义日历的结构
/**
* 定义日历结构接口
*/
type Calendar = {
year: number,
month: number,
totalWeeks: number,
firstWeek: [],
secondWeek: [],
thirdWeek: [],
forthWeek: [],
fifthWeek: [], // 只有在二月份28天且二月1号在周日的情况下,没有第五周
sixthWeek: [], // 极少数情况会有第六周
}
定义类:
class CalendarManager {
static weeks = ['日','一','二','三','四','五','六'];// 静态的日历角标
year: number; // 年
month: number; // 月
date: number; // 日(当前日期)
timeSp: Date; // 当前日期对象
weekDay: number; // 当前的星期数
// readonly currentMonthData: Calendar; // 当前月份的数据,暂时没有用到
constructor(){
this.timeSp = new Date();
this.year = this.timeSp.getFullYear();
this.month = this.timeSp.getMonth() + 1;
this.date = this.timeSp.getDate();
this.weekDay = this.timeSp.getDay();
// this.currentMonthData = this.calculateCalendarData();
}
}
在初始化的时候,就确定当前的年月日,然后计算的时候,按照当前的年月日来走。
接下来,就开始给CalendarManager这个类里面,添加方法。
首先,我们需要一个根据当前月份计算日期的方法
// 需要一个根据当前月份计算日期的方法
// 日历表为7*5矩阵,即为一个二维数组,每次调整当前类的数据时,自动计算当月的日历(有7*4和7*6的情况)
calculateCalendarData = (year, month) => {
if (!year) {
year = this.year;
}
if (!month) {
month = this.month - 1;
} else {
month = month - 1;
}
const tempDate = new Date(year, month, 0); // 首先找出上个月的最后一天
const day = tempDate.getDay();// 上个月最后一天的week数
const lastMonthLastDayDate = tempDate.getDate();
const isFeb = month == 1;// 判断是否是二月
const isFirstDaySat = day == 6;
// 初始化接口类型的数据,默认weeks数为5
let result: Calendar = {
year: year,
month: month + 1,
totalWeeks: 5,
firstWeek: [],
secondWeek: [],
thirdWeek: [],
forthWeek: []
};
// 开始填充数据
for (let weeksNum = 0; weeksNum < 6; weeksNum += 1) {
let endDate = new Date(year, month + 1, 0).getDate();
// 第一周的情况
if (weeksNum == 0) {
let startDate = 1;
if (day !== 6) {
// 填充第一周的空白天数
for (let spaceDays = 0; spaceDays <= day; spaceDays += 1) {
const last_date = lastMonthLastDayDate - (day - spaceDays); // 计算日期
const dayData: DateDay = {dateValue: last_date, weekDay: day - spaceDays, notCurrentMonth: true}
result.firstWeek.push(dayData);
}
}
// 填充第一周的剩余天数
for (let startDay = result.firstWeek.length; startDay < 7; startDay += 1) {
const dayData: DateDay = {dateValue: startDate, weekDay: startDay, notCurrentMonth: false}
if (this.date == startDate && this.month == month && this.year == year) {
dayData.isToday = true;
}
result.firstWeek.push(dayData);
startDate += 1;
}
}
// 二到四的情况
if (weeksNum !== 0 && weeksNum !== 4) {
let everyDate = result.firstWeek[6].dateValue + 1;
if (weeksNum == 2) {
everyDate = result.secondWeek[6].dateValue + 1;
}
if (weeksNum == 3) {
everyDate = result.thirdWeek[6].dateValue + 1;
}
for (let startDay = 0; startDay < 7; startDay += 1) {
const dayData: DateDay = {dateValue: everyDate, weekDay: startDay, notCurrentMonth: false};
if (this.date == everyDate && this.month == month && this.year == year) {
dayData.isToday = true;
}
switch (weeksNum) {
case 1:
result.secondWeek.push(dayData);
break;
case 2:
result.thirdWeek.push(dayData);
break;
case 3:
result.forthWeek.push(dayData);
}
everyDate += 1;
}
result.totalWeeks = 4;
}
// 第五周的情况
if (weeksNum === 4 && !(isFeb && isFirstDaySat && endDate === 28)) {
let everyDate = result.forthWeek[6].dateValue + 1;
let lastDayNum = endDate - result.forthWeek[6].dateValue;
result.fifthWeek = [];
if (lastDayNum <= 7) {
for (let startDay = 0; startDay < lastDayNum; startDay += 1) {
const dayData: DateDay = {dateValue: everyDate, weekDay: startDay, notCurrentMonth: false};
if (this.date == everyDate && this.month == month && this.year == year) {
dayData.isToday = true;
}
result.fifthWeek.push(dayData);
everyDate += 1;
}
for (let nextDay = 0; nextDay < 7 - lastDayNum; nextDay += 1) {
const dayData: DateDay = {
dateValue: nextDay + 1,
weekDay: lastDayNum + nextDay + 1,
notCurrentMonth: true
};
result.fifthWeek.push(dayData);
}
result.totalWeeks = 5;
break; // 打断循环即可
} else {
for (let startDay = 0; startDay < 7; startDay += 1) {
const dayData: DateDay = {dateValue: everyDate, weekDay: startDay, notCurrentMonth: false};
if (this.date == everyDate && this.month == month && this.year == year) {
dayData.isToday = true;
}
result.fifthWeek.push(dayData);
everyDate += 1;
}
}
}
if (weeksNum === 5 && result.fifthWeek) {
let everyDate = result.fifthWeek[6].dateValue + 1;
let lastDayNum = endDate - result.fifthWeek[6].dateValue;
result.sixthWeek = [];
for (let startDay = 0; startDay < lastDayNum; startDay += 1) {
const dayData: DateDay = {dateValue: everyDate, weekDay: startDay, notCurrentMonth: false};
if (this.date == everyDate && this.month == month && this.year == year) {
dayData.isToday = true;
}
result.sixthWeek.push(dayData);
everyDate += 1;
}
for (let nextDay = 0; nextDay < 7 - lastDayNum; nextDay += 1) {
const dayData: DateDay = {
dateValue: nextDay + 1,
weekDay: lastDayNum + nextDay + 1,
notCurrentMonth: true
};
result.sixthWeek.push(dayData);
}
result.totalWeeks = 6;
}
}
return result;
}
其次,我们...也没有什么需要的了(皮这一下我很开心)
接下来,开始撸Item(月份的显示),创建一个CalendarItemView.js
开始撸界面:
先导入该导入的,
import React, { Component } from 'react';
import PropType from 'prop-types';
import {
View,
Text,
TouchableOpacity,
StyleSheet,
ART,
} from 'react-native';
import { observer } from 'mobx-react/native';
import { observable, runInAction } from 'mobx';
import CalenderManager from './Calendar';
import D, { W } from './Demissions';
const { Surface, Shape, Path } = ART;
写常量:
const _MarginHor = 15;
const _titleHeight = W(60);
const _weekItemHeight = W(136);
const _itemBackground = '#f5f5f5';
const _itemRadius = W(35);
// row index text相关内容常量
const contentWidth = D.ScreenW - (2 * _MarginHor);
const dateView_B_Width = (_itemRadius * 2) + ((contentWidth - 15 - (14 * _itemRadius)) / 6);
const tempWidth = (_itemRadius * 2) + ((contentWidth - 15 - (14 * _itemRadius)) / 12); // 间隙的一半
const selectedStyle = { borderRadius: _itemRadius, backgroundColor: '#0084bf' };
const inSelectedStyle = { backgroundColor: '#cce6f2' };
写样式:
const CalenderItemStyle = StyleSheet.create({
container: {
flex: 0,
width: contentWidth,
marginHorizontal: _MarginHor,
minHeight: (_weekItemHeight * 4) + _titleHeight,
// maxHeight: (_weekItemHeight * 5) + _titleHeight,
// height: (_weekItemHeight * 5) + _titleHeight,
backgroundColor: _itemBackground,
},
itemTitleView: {
flex: 0,
height: _titleHeight,
backgroundColor: _itemBackground,
justifyContent: 'center',
alignItems: 'center',
},
weekItemView: {
flex: 0,
height: W(136),
width: contentWidth,
paddingHorizontal: 7.5, // 记得计算多余的宽度
backgroundColor: '#fff',
// borderTopColor: '#f0f0f0',
// borderTopWidth: W('minPix') * 2,
justifyContent: 'space-between',
alignItems: 'center',
flexDirection: 'row',
},
weekDayBackGroundView: {
flex: 0,
height: _itemRadius * 2,
width: dateView_B_Width,
backgroundColor: '#fff',
// paddingHorizontal: 5,
// width: _itemRadius * 2,
justifyContent: 'center',
alignItems: 'center',
},
weekDayView: {
flex: 0,
// marginHorizontal: 5,
width: _itemRadius * 2,
height: _itemRadius * 2,
justifyContent: 'center',
alignItems: 'center',
},
weekDayText: {
textAlign: 'center',
fontSize: 14,
},
SAndEBackView: {
position: 'absolute',
flex: 0,
height: _itemRadius * 2,
width: dateView_B_Width / 2,
top: 0,
backgroundColor: '#cce6f2',
},
});
撸界面:
@observer
class CalendarItemView extends Component {
static propTypes = {
year: PropType.number.isRequired,
month: PropType.number.isRequired,
startDate: PropType.number,
endDate: PropType.number,
allSelect: PropType.bool,
onRowItemPress: PropType.func,
selectedOk: PropType.bool,
}
static defaultProps = {
startDate: -1,
endDate: -1,
allSelect: false,
onRowItemPress: (dateInfo) => {
// console.log(`点击了${dateInfo.year}/${dateInfo.month}/${dateInfo.date}`);
},
selectedOk: false,
}
constructor(props) {
super(props);
this.calenderManager = new CalenderManager();
// this.calenderData = this.calenderManager.calculateCalendarData(this.props.year, this.props.month);
this.selectedOK = this.props.selectedOk;
}
componentWillReceiveProps(nextProps) {
// if (nextProps.selectedOk !== this.props.selectedOk || nextProps.startDate !== this.props.startDate || nextProps.endDate !== this.props.endDate || nextProps.allSelect !== this.props.allSelect) {
// runInAction(() => {
// this.calenderData = this.calenderManager.calculateCalendarData(nextProps.year, nextProps.month);
// this.selectedOK = this.props.selectedOk;
// });
// }
runInAction(() => {
this.calenderData = this.calenderManager.calculateCalendarData(nextProps.year, nextProps.month);
this.selectedOK = this.props.selectedOk;
});
}
shouldComponentUpdate(nextProps, nextState) {
return (nextProps.selectedOk !== this.props.selectedOk || nextProps.startDate !== this.props.startDate || nextProps.endDate !== this.props.endDate || nextProps.allSelect !== this.props.allSelect);
}
calenderManager = null;
@observable calenderData = null;
@observable selectedOK = false;
pressDateRowItem = (dateValue: number) => {
if (this.props.onRowItemPress) {
const dateInfo = {
year: this.props.year,
month: this.props.month,
date: dateValue,
};
/**
* 传回选择数据
*/
this.props.onRowItemPress(dateInfo);
}
}
renderTitle = () => {
const year = this.calenderData ? this.calenderData.year : this.props.year;
const month = this.calenderData ? this.calenderData.month : this.props.month;
const title = `${year}-${month}`;
return (
<View style={CalenderItemStyle.itemTitleView}>
<Text>{title}</Text>
</View>
);
}
/**
* 计算每一个月份怎么显示
* @param obj: 每一个月份的信息
* @param index 当前周的星期数
* @returns {*}
*/
renderRowText = (obj, index) => {
// 计算边界的宽度布局
let frontierStyle = {};
if (index === 0) {
frontierStyle = {
borderTopLeftRadius: _itemRadius,
borderBottomLeftRadius: _itemRadius,
width: tempWidth,
alignItems: 'flex-start',
};
} else if (index === 6) {
frontierStyle = {
borderBottomRightRadius: _itemRadius,
borderTopRightRadius: _itemRadius,
width: tempWidth,
alignItems: 'flex-end',
};
}
// 如果不是当月的日子,直接返回空视图。
if (obj.notCurrentMonth) {
return (
<View
key={`other_date@${this.props.month}-${obj.dateValue}`}
style={[CalenderItemStyle.weekDayBackGroundView, frontierStyle]}
/>
);
}
let needFrontierBackView = false;
let EAndSStyle = {};
let _style = {};
let _backgroundStyle = {};
if (this.props.startDate === obj.dateValue || this.props.endDate === obj.dateValue) {
_style = selectedStyle;
}
const isStartExist = this.props.startDate !== -1;
const isEndExist = this.props.endDate !== -1;
const isGreaterThanStart = (isStartExist && this.props.startDate < obj.dateValue);
const isLessThanEnd = (isEndExist && this.props.endDate > obj.dateValue);
if (this.props.allSelect) {
_backgroundStyle = inSelectedStyle;
} else if (!isEndExist && isGreaterThanStart) {
_backgroundStyle = inSelectedStyle;
} else if (!isStartExist && isLessThanEnd) {
_backgroundStyle = inSelectedStyle;
} else if (isGreaterThanStart && isLessThanEnd) {
_backgroundStyle = inSelectedStyle;
}
if (obj.dateValue === this.props.startDate) {
EAndSStyle = {
right: 0,
};
needFrontierBackView = true;
} else if (obj.dateValue === this.props.endDate) {
EAndSStyle = {
left: 0,
};
needFrontierBackView = true;
}
return (
<TouchableOpacity
key={`date@${this.props.month}-${obj.dateValue}`}
style={[CalenderItemStyle.weekDayBackGroundView, this.selectedOK ? _backgroundStyle : null, frontierStyle]}
onPress={() => { this.pressDateRowItem(obj.dateValue); }}
activeOpacity={0.80}
>
{needFrontierBackView && this.selectedOK ? <View style={[CalenderItemStyle.SAndEBackView, EAndSStyle]} /> : null}
<View style={[CalenderItemStyle.weekDayView, _style]}>
<Text style={CalenderItemStyle.weekDayText}>{obj.notCurrentMonth ? '' : obj.dateValue}</Text>
</View>
</TouchableOpacity>
);
}
renderRow = (weekData: Array) => {
if (typeof weekData === 'undefined' || weekData.length === 0) {
return <View />;
}
const listCom = [];
weekData.forEach((obj, index) => {
listCom.push(this.renderRowText(obj, index));
});
const _width = D.ScreenW - (2 * _MarginHor);
const path = new Path().moveTo(15, 0).lineTo(_width - 15, 0);
return (
<View style={CalenderItemStyle.weekItemView}>
<Surface width={_width} height={1} style={{ position: 'absolute', top:0, left: 0 }}>
<Shape d={path} strokeWidth={1.5} stroke={'#f0f0f0'} />
</Surface>
{listCom}
</View>
);
};
renderCalendarContent = () => {
if (!this.calenderData) { return <View/> }
const firstWeek = this.renderRow(this.calenderData.firstWeek);
const secondWeek = this.renderRow(this.calenderData.secondWeek);
const thirdWeek = this.renderRow(this.calenderData.thirdWeek);
const forthWeek = this.renderRow(this.calenderData.forthWeek);
const fifthWeek = this.renderRow(this.calenderData.fifthWeek);
const sixthWeek = this.renderRow(this.calenderData.sixthWeek);
return (
<View style={{ flex:1, backgroundColor: '#fff', alignItems: 'center' }}>
{firstWeek}
{secondWeek}
{thirdWeek}
{forthWeek}
{fifthWeek}
{sixthWeek}
</View>
);
};
render() {
return (
<View style={CalenderItemStyle.container}>
{this.renderTitle()}
{this.renderCalendarContent()}
</View>
);
}
}
敲黑板,划重点了
这里实现item渲染的思路是,每个item都有一个startdata和enddata的检测机制,渲染startdata和enddata的之间的item样式。都在,都渲染,在区间外,则不渲染。
然后把放到FlatList即可。
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
FlatList,
} from 'react-native';
import { persist } from 'mobx-persist';
import { observer } from 'mobx-react/native';
import { observable, action, runInAction, toJS, autoRun, computed } from 'mobx';
import D, { W } from './Demissions';
import CalendarItemView from './CalendarItemView';
import CalendarManager from './Calendar';
import CalendarDataStore from './CalendarDataStore';
const _MarginHor = 15;
const _MarginTop = 22.5;
const _ContainerBackgroundColor = '#f5f5f5';
const SelectedDateStyle = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start',
alignItems: 'center',
backgroundColor: _ContainerBackgroundColor,
},
headerStyle: {
flex: 0,
marginHorizontal: _MarginHor,
marginTop: _MarginTop,
height: W(150),
width: D.ScreenW - (2 * _MarginHor),
backgroundColor: '#fff',
// alignItems: 'center',
},
selectTitleViewStyle: {
flex: 0,
height: W(90),
width: D.ScreenW - (2 * _MarginHor),
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 15,
},
selectTitle: {
flex: 0,
fontSize: 16,
fontWeight: '500',
color: '#000',
},
dayTitleViewStyle: {
flex: 0,
width: D.ScreenW - (4 * _MarginHor),
height: W(60),
flexDirection: 'row',
justifyContent: 'space-between',
// paddingHorizontal: _MarginHor,
alignItems: 'center',
borderTopWidth: W('minPix') * 2,
borderTopColor: '#f0f0f0',
alignSelf: 'center',
},
cancelBtnStyle: {
flex: 0,
height: W(90),
minWidth: W(90),
position: 'absolute',
top: 0,
left: 0,
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: _MarginHor,
},
cancelText: {
fontSize: 16,
color: '#000',
},
flatListStyle: {
flex: 1,
},
});
/**
* 处理选择页面的数据逻辑
*/
class SelectedDateModel {
constructor() {
this.calendarManager = new CalendarManager();
}
calendarManager: CalendarManager = null;
@observable years;
@observable calendarDataArr = [];
@observable selectDateArr = [];
@computed get selectedOK() {
return this.selectDateArr >= 2;
}
@action createData = () => {
if (CalendarDataStore.calendarDataArr.length !== 0 && CalendarDataStore.calendarDataArr[11].month === this.calendarManager.month) {
this.originDataArr = toJS(CalendarDataStore.calendarDataArr);
this.calendarDataArr = toJS(CalendarDataStore.calendarDataArr);
return;
}
// 生成当年的数据
for (let i = 11; i >= 0; i -= 1) {
// 年、月的计算,push顺序
let _month = this.calendarManager.month - i;
if (_month <= 0) {
_month = 12 - _month;
}
const tempObj = {
month: _month,
year: this.calendarManager.month - i - 1 < 0 ? this.calendarManager.year - 1 : this.calendarManager.year,
isSelectedAll: false,
startDate: -1,
endDate: -1,
};
this.calendarDataArr.push(tempObj);
}
this.originDataArr = toJS(this.calendarDataArr);
CalendarDataStore.calendarDataArr = this.calendarDataArr;
}
originDataArr = [];
@action onItemPress = (dateInfo) => {
this.selectedDate(dateInfo.year, dateInfo.month, dateInfo.date);
}
@action selectedDate = (year, month, day) => {
const time = new Date(year, month - 1, day);
if (this.selectDateArr.length >= 2) {
this.pressCancel();
}
if (this.selectDateArr.length === 0) {
this.selectDateArr.push(time.valueOf());
} else if (time.valueOf() !== this.selectDateArr[0]) {
this.selectDateArr.push(time.valueOf());
// console.log(toJS(this.selectDateArr));
this.selectDateArr = toJS(this.selectDateArr).sort(function (a, b) {
return a - b;
}); // 排序
// console.log(toJS(this.selectDateArr));
}
this.changeUI();
}
@action changeUI = () => {
if (this.calendarDataArr.length === 0) return;
let tepStart = null;
let startMonth = -1;
let startYear = -1;
let startDay = -1;
if (this.selectDateArr.length === 1) {
tepStart = this.selectDateArr[0];
if (tepStart) {
const startDate = new Date(tepStart);
startMonth = startDate.getMonth() + 1;
startYear = startDate.getFullYear();
startDay = startDate.getDate();
const tempObj = {
month: startMonth,
year: startYear,
isSelectedAll: false,
startDate: startDay,
endDate: -1,
};
const monthNum = this.calendarManager.month - startMonth;
const tempArr = toJS(this.calendarDataArr);
if (monthNum >= 0) {
tempArr[11 - monthNum] = tempObj;
} else {
tempArr[-monthNum - 1] = tempObj;
}
this.calendarDataArr = toJS(tempArr);
}
} else if (this.selectDateArr.length === 2) {
let tepStart = this.selectDateArr[0];
let startMonth = -1;
let startYear = -1;
let startDay = -1;
let tepEnd = this.selectDateArr[1];
let endMonth = -1;
let endYear = -1;
let endDay = -1;
if (tepStart) {
const startDate = new Date(tepStart);
startMonth = startDate.getMonth() + 1;
startYear = startDate.getFullYear();
startDay = startDate.getDate();
}
if (tepEnd) {
const endDate = new Date(tepEnd);
endMonth = endDate.getMonth() + 1;
endDay = endDate.getDate();
endYear = endDate.getFullYear();
}
if (endMonth === startMonth) {
const tempObj = {
month: startMonth,
year: startYear,
isSelectedAll: false,
startDate: startDay,
endDate: endDay,
};
const monthNum = this.calendarManager.month - startMonth;
const tempArr = toJS(this.calendarDataArr);
const month_index = monthNum >= 0 ? 11 - monthNum : -monthNum - 1;
tempArr[month_index] = tempObj;
this.calendarDataArr = toJS(tempArr);
} else {
const tempObj_start = {
month: startMonth,
year: startYear,
isSelectedAll: false,
startDate: startDay,
endDate: -1,
};
const tempObj_end = {
month: endMonth,
year: endYear,
isSelectedAll: false,
startDate: -1,
endDate: endDay,
};
const start_monthNum = this.calendarManager.month - startMonth;
const end_monthNum = this.calendarManager.month - endMonth;
const tempArr = toJS(this.calendarDataArr);
const start_index = start_monthNum >= 0 ? 11 - start_monthNum : -start_monthNum - 1;
const end_index = end_monthNum >= 0 ? 11 - end_monthNum : -end_monthNum - 1;
tempArr[start_index] = tempObj_start;
tempArr[end_index] = tempObj_end;
if (Math.abs(start_monthNum - end_monthNum) > 1) {
for (let i = start_index + 1; i < end_index; i += 1) {
tempArr[i] = {
month: tempArr[i].month,
year: tempArr[i].year,
isSelectedAll: true,
startDate: -1,
endDate: -1,
};
}
}
this.calendarDataArr = toJS(tempArr);
}
}
}
@action pressCancel = () => {
this.selectDateArr = [];
if (this.originDataArr.length !== 0) {
this.calendarDataArr = this.originDataArr;
}
}
}
@observer
class SelectedDatePage extends Component {
static navigatorStyle = {
tabBarHidden: true,
};
model: ?SelectedDateModel = null;
@observable showFlatList = false;
constructor(props) {
super(props);
this.model = new SelectedDateModel();
}
componentDidMount() {
// 延迟创建,(Android端的渲染有点问题,需要进一步处理下)
this.model.createData();
runInAction(() => {
this.showFlatList = true;
});
}
keyExtractor = (item, index) => {
return `calendarKey@${index}`;
}
/**
* 返回ListItem
*/
renderItem = (row) => {
const item = row.item;
return (
<CalendarItemView
year={item.year}
month={item.month}
startDate={item.startDate}
endDate={item.endDate}
allSelect={item.isSelectedAll}
selectedOk={this.model.selectedOK}
onRowItemPress={this.model.onItemPress}
/>
);
}
/**
* 返回日期头部视图
* @returns {*}
*/
renderHeaderView = () => {
const titleArr = ['日', '一', '二', '三', '四', '五', '六'];
const listCom = [];
titleArr.forEach((obj, index) => {
listCom.push(
<Text
key={`key@${obj}`}
style={{ flex: 0, textAlign: 'center', width: W(40), fontSize: 14 }}
>
{obj}
</Text>
);
});
return (
<View style={SelectedDateStyle.headerStyle}>
<View style={SelectedDateStyle.selectTitleViewStyle}>
<TouchableOpacity style={SelectedDateStyle.cancelBtnStyle} onPress={this.model.pressCancel}>
<Text style={SelectedDateStyle.cancelText}>取消</Text>
</TouchableOpacity>
<Text style={SelectedDateStyle.selectTitle}>选择日期</Text>
</View>
<View style={SelectedDateStyle.dayTitleViewStyle}>
{listCom}
</View>
</View>
);
}
renderFlatList = () => {
return (
<FlatList
style={SelectedDateStyle.flatListStyle}
data={toJS(this.model.calendarDataArr)}
renderItem={this.renderItem}
keyExtractor={this.keyExtractor}
extraData={[this.model.selectDateArr, this.model.selectedOK]}
/>
);
}
render() {
return (
<View style={SelectedDateStyle.container}>
{this.renderHeaderView()}
{this.renderFlatList()}
</View>
);
}
}
OK, 这样就完成了一个卡的要死的日历。
关于为什么在Android上会卡,我的初步推测是,每次选择日历,都要遍历所有item进行渲染,一年有365天,就有365个item的样式需要去重绘。
但是总觉的对于计算机的运行速度而言,365这个数量级,也是个毫秒级的处理。但为什么在Android上会卡呢??
我把锅甩给了RN,各位读者有什么高见的话,欢迎在评论取留言回复。