W. Robarts
W. Robarts

Reputation: 151

React-native: Absolute positioned components not rendering completely unless a state is changed

I have a screen that has several components, some with relative positioning and some with absolute. When the screen is opened, the absolute positioned components don't go all the way to their final correct position, or size. They appear on the screen, but in the wrong spot and size. Only by changing a state with a button press, do the components finish rendering. Here's a simplified version of the screen below:

enter image description here

The screenshot on the left has the absolutely positioned menu icon (3 horizontal lines at the top right), not all the way in its correct position yet. The screen on the right shows the icon in its final correct position, only after I changed a state by pressing a touchable region.

Here is the code:

import React, {Component} from 'react';
import {View, Text, StyleSheet, Animated, Image, Dimensions, TouchableWithoutFeedback} from 'react-native';
import colors from '../config/colors';
import Icon from 'react-native-vector-icons/Ionicons';
import Orientation from 'react-native-orientation-locker';

const w = (Dimensions.get('window').width);
const h = (Dimensions.get('window').height);
const r = h / w;

if (r > 1.9) {
    mission_font_heading = 14;
    mission_font = 12;
    check_dimension = 14;
    name_font = 10;
} else {
    mission_font_heading = 12;
    mission_font = 10;
    check_dimension = 12;
    name_font = 8;
}

class how_to_play9_screen extends Component {
    constructor (props) {
        super(props);
        this.state = {
            test: 0, //changing this state "fixes" the component's position
        }
    }

    componentDidMount() {
        Orientation.lockToPortrait();
    }

    openMenu() {}

    showMission() {
        this.setState({test: 2}); //this changes the state
    }

    render() {
        return (
            <View>
                <Image
                    style={styles.backgroundImage}
                    source={require('../images/Background.png')}
                >
                </Image>
                <View style={{alignItems: 'center'}}>
                    <TouchableWithoutFeedback onPress={() => this.showMission()}>
                        <View style={styles.missionContainer}>
                            <Text style={styles.missionTitleText}>
                                MISSION TITLE
                            </Text>
                            <Text style={styles.text}>
                                (X VP)
                            </Text>
                            <View style={{flexDirection: 'row'}}>
                                <Image
                                    style={styles.checkBox}
                                    source={require('../images/Checkbox.jpg')}
                                />
                                <Text style={styles.missionReqText}>
                                    Mission Requirement 1
                                </Text>
                            </View>
                        </View>
                    </TouchableWithoutFeedback>
                </View>
                // below is the absolute positioned component
                <View
                    style={{
                        position: 'absolute',
                        top: 5,
                        right: 5,
                    }}
                >
                    <TouchableWithoutFeedback
                        onPress={() => this.openMenu()}
                    >
                        <Icon
                            name='ios-menu'
                            size={(Dimensions.get('window').width) * .08}
                            color={colors.JBDarkTeal}
                        />
                    </TouchableWithoutFeedback>
                </View>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    backgroundImage: {
        width: (Dimensions.get('window').height) * .65,
        height: (Dimensions.get('window').height) * 1.3,
        position: 'absolute',
        left: 0,
        top: 0,
    },
    missionContainer:  {
        backgroundColor: colors.JBTealTrans,
        borderWidth: 2,
        borderColor: colors.JBTan,
        marginVertical: 10,
        paddingVertical: 3,
        paddingRight: 5,
        width: '80%',
    },
    missionTitleText: {
        fontSize: mission_font_heading,
        textAlign: 'center',
        color: colors.JBTan,
        marginVertical: 3,
        marginHorizontal: 5,
    },
    text: {
        fontSize: mission_font,
        textAlign: 'center',
        color: colors.JBTan,
        marginVertical: 3,
    },
    missionReqText: {
        fontSize: 12,
        color: colors.JBTan,
        marginVertical: 3,
        marginLeft: 5,
        marginRight: 5,
    },
    checkBox: {
        width: check_dimension,
        height: check_dimension,
        marginVertical: 3,
        marginLeft: 5,
    },
})

export default how_to_play9_screen;

I want the icon and any other absolute positioned components to go straight to their final position upon screen opening.

Edit: I should also mention that the previous screen locks the orientation to landscape, and this screen locks it back to portrait. I found that if I load this screen from a different screen that is already in portrait, then this one renders correctly, so it seems that it doesn't like me changing the orientation.

Upvotes: 0

Views: 582

Answers (1)

Eliseo
Eliseo

Reputation: 712

The position is not the problem, the problem is size of <Icon /> try to using number instad Dimensions calc, or make this calc on componentDidMount or render

Upvotes: 1

Related Questions