Search code examples
iosreactjsreact-nativeexponentjs

React Native, iOS - ScrollView doesn't work on device


ScrollView works on iOS Simulator but it doesn't work when it is actually run on Exponent on device. It goes back to the top after touch release. I'm not sure if this is the problem with my code or it is a bug on React Native or Exponent side. Here are the details of my environment:

React Native Version: 0.41

Exponent Version: 14

Link to Exponent application:

https://exp.host/@prez/hairapp

presentation of working ScrollView on iOS Simulator:

https://www.youtube.com/watch?v=3VH-6a-sMok

main.js

import Exponent from 'exponent';
import React from 'react';
import {AppRegistry, Text, Button, View, ScrollView} from 'react-native';
import {StackNavigator} from 'react-navigation';
import Calendar from './modules/calendar';

class CalendarView extends React.Component {
    static navigationOptions = {
        title: 'Calendar'
    }
    render() {
        return (
            <ScrollView>
                <Calendar/>
            </ScrollView>
        )
    }
}

const SimpleApp = StackNavigator({
    Home: {
        screen: CalendarView
    }
});

Exponent.registerRootComponent(SimpleApp);

./modules/calendar/index.js

import React, {Component} from 'react';
import {Text, View, StyleSheet} from 'react-native';
import moment from 'moment';

export default class Calendar extends Component {
    state = {
        reservations: [
            {
                hour: '2017-02-17 00:00',
                duration: 120
            }, {
                hour: '2017-02-17 02:00',
                duration: 60
            }, {
                hour: '2017-02-17 03:00',
                duration: 120
            }, {
                hour: '2017-02-17 05:00',
                duration: 180
            }, {
                hour: '2017-02-17 08:00',
                duration: 120
            }
        ]
    }

    generateIntervalHours() {
        let hours = [];
        // interval has been imported from database configuration, set in minutes
        const interval = 60;
        // current set day, date set only for test purposes
        let it = moment('2017-02-17').hours(0).minutes(0);
        const itEnd = moment(it).hours(23).minutes(59);
        while (it < itEnd) {
            hours.push(moment(it));
            it.add(interval, 'minutes');
        }
        return hours;
    }

    // Function to display hours next to lines/events. Displaying hours and events must be
    // seperated because the line starts in the middle of the hour text and ends in the
    // middle of the next hours text so it would be not possible to display hour and event/line
    // as a single row. Former event block would have to overlay next block to reach middle of the text.
    displayHours = () => (this.generateIntervalHours().map(item => (
        <View key={item.format('HH:mm')} style={styles.hours}>
            <Text style={{
                color: '‎rgb(107, 108, 109)',
                fontSize: 12
            }}>{item.format('HH:mm')}</Text>
        </View>
    )))

    // Function to display lines/events next to hours
    displayTimetable = () => (this.generateIntervalHours().map(hour => {
        const {reservations} = this.state;
        // test current hour if there is reservation
        // that start or lasts during this hour
        const slot = reservations.find(res => {
            const startH = moment(res.hour, 'YYYY-MM-DD HH:mm');
            const endH = moment(startH).add(res.duration, 'minutes');
            return (hour >= startH && hour < endH);
        });
        // no reservation starting with the hour tested
        // no reservation that lasts during the hour tested
        // View with upper border line will be displayed
        // what says that nothing is scheduled for this hour
        if (typeof slot == 'undefined') {
            return (<View key={hour.format('HH:mm')} style={[
                styles.timetable, {
                    height: 60
                }
            ]}/>);
            // reservation found that lasts during the tested hour
            // nothing to display
        } else if (hour.format('YYYY-MM-DD HH:mm') != slot.hour) {
            return null;
            // reservation found with starting hour as tested hour
            // View with height set to duration will be displayed
        } else {
            return <View key={hour.format('HH:mm')} style={[
                styles.timetable, {
                    height: slot.duration,
                    backgroundColor: '‎rgb(32, 127, 227)'
                }
            ]}/>
        };
    }))

    render() {
        return (
            <View style={styles.container}>
                <View>
                    {this.displayHours()}
                </View>
                <View style={styles.timetablePadding}>
                    {this.displayTimetable()}
                </View>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        marginLeft: 10,
        marginTop: 10,
        marginRight: 10,
        flexDirection: 'row'
    },
    timetablePadding: {
        flex: 1,
        paddingTop: 10
    },
    hours: {
        marginBottom: 40,
        // borderWidth: 1,
        // borderRadius: 2,
        // borderColor: '#ddd',
        marginRight: 10,
        height: 20,
        width: 50,
        justifyContent: 'center'
    },
    timetable: {
        flexDirection: 'row',
        //borderWidth: 1,
        borderRadius: 2,
        //borderColor: '#ddd',
        borderTopColor: '‎rgb(238, 239, 240)',
        borderTopWidth: 1,
        borderBottomWidth: 1,
        borderBottomColor: 'white'
    },
    line: {
        flex: 1,
        height: 1,
        backgroundColor: 'black'
    }
});

Solution

  • It worked after reinstalling Exponent on a device. Same version before and after reinstallation.