Skip to content

Commit

Permalink
make header can scroll along with columns (hoangnm#30)
Browse files Browse the repository at this point in the history
* make header can be scroll along with columns

* move Title to new file

* rename selectedDate to initialDate of Header

* increase value for scrollEventThrottle

* update gif image
  • Loading branch information
hoangnm authored Jun 7, 2020
1 parent 7c1bd84 commit 5f33fd9
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 49 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
## Props
* **`events`** _(Array)_ - Events to display
* **`onEventPress`** _(Function)_ - Callback when event item is clicked
* **`numberOfDays`** _(Number)_ - Set number of days to show in view, can be `1`, `3`, `7`.
* **`numberOfDays`** _(Number)_ - Set number of days to show in view, can be `1`, `3`, `5`, `7`.
* **`formatDateHeader`** _(String)_ - Format for dates of header, default is `MMM D`
* **`selectedDate`** _(Date)_ - Intial date to show week/days in view
* **`onSwipeNext`** _(Function)_ - Callback when calendar is swiped to next week/days
Expand Down
Binary file modified images/gif.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 4 additions & 25 deletions src/Header/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,9 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Text, View } from 'react-native';

import { getFormattedDate, getCurrentMonth, calculateDaysArray } from '../utils';

import { getFormattedDate, calculateDaysArray } from '../utils';
import styles from './Header.styles';

const getFontSizeHeader = (numberOfDays) => {
if (numberOfDays > 1) {
return 12;
}

return 16;
};

const getDayTextStyles = (numberOfDays) => {
const fontSize = numberOfDays === 7 ? 12 : 14;
return {
Expand Down Expand Up @@ -59,37 +50,25 @@ const Columns = ({
);
};

const Title = ({ numberOfDays, selectedDate, textColor }) => { // eslint-disable-line react/prop-types
return (
<View style={styles.title}>
<Text
style={{ color: textColor, fontSize: getFontSizeHeader(numberOfDays) }}
>
{getCurrentMonth(selectedDate)}
</Text>
</View>
);
};

const WeekViewHeader = ({
numberOfDays,
selectedDate,
initialDate,
formatDate,
style,
textColor,
}) => {
const columns = calculateDaysArray(selectedDate, numberOfDays);
const columns = calculateDaysArray(initialDate, numberOfDays);
return (
<View style={[styles.container, style]}>
<Title numberOfDays={numberOfDays} selectedDate={selectedDate} textColor={textColor} />
{columns && <Columns format={formatDate} columns={columns} numberOfDays={numberOfDays} textColor={textColor} />}
</View>
);
};

WeekViewHeader.propTypes = {
numberOfDays: PropTypes.oneOf([1, 3, 5, 7]).isRequired,
selectedDate: PropTypes.instanceOf(Date).isRequired,
initialDate: PropTypes.string.isRequired,
formatDate: PropTypes.string,
style: PropTypes.object,
textColor: PropTypes.string,
Expand Down
7 changes: 0 additions & 7 deletions src/Header/Header.styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,6 @@ const styles = StyleSheet.create({
flex: 1,
justifyContent: 'space-between',
},
title: {
justifyContent: 'center',
alignItems: 'center',
width: 60,
borderColor: '#fff',
borderTopWidth: 1,
},
columns: {
flex: 1,
flexDirection: 'row',
Expand Down
39 changes: 39 additions & 0 deletions src/Title/Title.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { Text, View } from 'react-native';
import PropTypes from 'prop-types';

import { getCurrentMonth } from '../utils';
import styles from './Title.styles';

const getFontSizeHeader = (numberOfDays) => {
if (numberOfDays > 1) {
return 12;
}
return 16;
};

const Title = ({
style,
numberOfDays,
selectedDate,
textColor,
}) => {
return (
<View style={[styles.title, style]}>
<Text
style={{ color: textColor, fontSize: getFontSizeHeader(numberOfDays) }}
>
{getCurrentMonth(selectedDate)}
</Text>
</View>
);
};

Title.propTypes = {
numberOfDays: PropTypes.oneOf([1, 3, 5, 7]).isRequired,
selectedDate: PropTypes.instanceOf(Date).isRequired,
style: PropTypes.object,
textColor: PropTypes.string,
};

export default React.memo(Title);
13 changes: 13 additions & 0 deletions src/Title/Title.styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
title: {
justifyContent: 'center',
alignItems: 'center',
width: 60,
borderColor: '#fff',
borderTopWidth: 1,
},
});

export default styles;
68 changes: 55 additions & 13 deletions src/WeekView/WeekView.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import {
View,
ScrollView,
Dimensions,
Animated,
} from 'react-native';
import moment from 'moment';
import memoizeOne from 'memoize-one';

import Event from '../Event/Event';
import Events from '../Events/Events';
import Header from '../Header/Header';
import Title from '../Title/Title';
import Times from '../Times/Times';
import styles from './WeekView.styles';
import {
Expand All @@ -31,19 +33,24 @@ export default class WeekView extends Component {
};
this.eventsGrid = null;
this.verticalAgenda = null;
setLocale(props.locale);

this.header = null;
this.pagesLeft = 2;
this.pagesRight = 2;
this.currentPageIndex = 2;
this.totalPages = this.pagesLeft + this.pagesRight + 1;
this.eventsGridScrollX = new Animated.Value(0);

setLocale(props.locale);
}

componentDidMount() {
requestAnimationFrame(() => {
this.eventsGrid.scrollTo({ y: 0, x: 2 * (SCREEN_WIDTH - 60), animated: false });
this.scrollToAgendaStart();
});
this.eventsGridScrollX.addListener((position) => {
this.header.scrollTo({ x: position.value, animated: false });
});
}

componentDidUpdate(prevprops) {
Expand All @@ -57,12 +64,8 @@ export default class WeekView extends Component {
this.eventsGrid.scrollTo({ y: 0, x: 2 * (SCREEN_WIDTH - 60), animated: false });
}

scrollToAgendaStart = () => {
if (this.verticalAgenda) {
const { startHour, hoursInDisplay } = this.props;
const startHeight = startHour * CONTAINER_HEIGHT / hoursInDisplay;
this.verticalAgenda.scrollTo({ y: startHeight, x: 0, animated: false });
}
componentWillUnmount() {
this.eventsGridScrollX.removeAllListeners();
}

calculateTimes = memoizeOne((hoursInDisplay) => {
Expand All @@ -79,6 +82,14 @@ export default class WeekView extends Component {
return times;
});

scrollToAgendaStart = () => {
if (this.verticalAgenda) {
const { startHour, hoursInDisplay } = this.props;
const startHeight = startHour * CONTAINER_HEIGHT / hoursInDisplay;
this.verticalAgenda.scrollTo({ y: startHeight, x: 0, animated: false });
}
}

scrollEnded = (event) => {
const { nativeEvent: { contentOffset, contentSize } } = event;
const { x: position } = contentOffset;
Expand Down Expand Up @@ -113,6 +124,10 @@ export default class WeekView extends Component {
this.verticalAgenda = ref;
}

headerRef = (ref) => {
this.header = ref;
};

calculatePagesDates = memoizeOne((currentMoment, numberOfDays) => {
const initialDates = [];
for (let i = -this.pagesLeft; i <= this.pagesRight; i += 1) {
Expand Down Expand Up @@ -176,14 +191,32 @@ export default class WeekView extends Component {
const eventsByDate = this.sortEventsByDate(events);
return (
<View style={styles.container}>
<View style={styles.header}>
<Header
<View style={styles.headerContainer}>
<Title
style={headerStyle}
textColor={headerTextColor}
formatDate={formatDateHeader}
selectedDate={currentMoment}
numberOfDays={numberOfDays}
selectedDate={currentMoment}
textColor={headerTextColor}
/>
<ScrollView
horizontal
pagingEnabled
scrollEnabled={false}
automaticallyAdjustContentInsets={false}
ref={this.headerRef}
>
{initialDates.map(date => (
<View key={date} style={styles.header}>
<Header
style={headerStyle}
textColor={headerTextColor}
formatDate={formatDateHeader}
initialDate={date}
numberOfDays={numberOfDays}
/>
</View>
))}
</ScrollView>
</View>
<ScrollView
ref={this.verticalAgendaRef}
Expand All @@ -195,6 +228,15 @@ export default class WeekView extends Component {
pagingEnabled
automaticallyAdjustContentInsets={false}
onMomentumScrollEnd={this.scrollEnded}
scrollEventThrottle={32}
onScroll={Animated.event([{
nativeEvent: {
contentOffset: {
x: this.eventsGridScrollX,
},
},
},
], { useNativeDriver: false })}
ref={this.eventsGridRef}
>
{initialDates.map(date => (
Expand Down
9 changes: 8 additions & 1 deletion src/WeekView/WeekView.styles.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { StyleSheet } from 'react-native';
import { StyleSheet, Dimensions } from 'react-native';

const { width: SCREEN_WIDTH } = Dimensions.get('window');

const styles = StyleSheet.create({
container: {
Expand All @@ -7,10 +9,15 @@ const styles = StyleSheet.create({
scrollViewContent: {
flexDirection: 'row',
},
headerContainer: {
flexDirection: 'row',
},
header: {
flex: 1,
height: 50,
justifyContent: 'center',
alignItems: 'center',
width: SCREEN_WIDTH - 60,
},
});

Expand Down
3 changes: 1 addition & 2 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,5 @@ export const calculateDaysArray = (date, numberOfDays) => {
const currentDate = moment(date).add(i, 'd');
dates.push(currentDate);
}

return dates;
}
};

0 comments on commit 5f33fd9

Please sign in to comment.