2

I am struggling to understand why flexbox will not constraint itself to the parent component width. I have tried multiple approaches without much luck and my buttons are always overflowing the parent component.

Here is what I have so far: https://snack.expo.io/@mohammedri/smart-bagel enter image description here

and here is what I want instead (top 4 red boxes are buttons, next red box is a text field and the last one is the reset table button): enter image description here

I am using UI kitten for theming, but don't think it should impact the outcome. I have tried resizeMode as well, but it doesn't seem to work. Any help is appreciated.

I have posted majority of my code below:

App.js:

export default function App() {
  const Tab = createBottomTabNavigator();

  return (
    <ApplicationProvider {...eva} theme={eva.light}>
      <SafeAreaView style={styles.container}>
        <NavigationContainer>
            {/* ... More code */}
            <Tab.Screen name="Home" component={HomeScreen} />
            {/* ... More code */}
          </Tab.Navigator>
        </NavigationContainer>
      </SafeAreaView>
    </ApplicationProvider>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
  },
});

HomeScreen.js:

  return (
    <WaterIntakeContext.Provider value={{dayTotalWater, setDayTotalWater}}>
      <View style={styles.container}>
        <View style={styles.statusContainer}>
          <Text style={styles.titleText} category="h3">some text</Text>
          <Text style={styles.subtitleText} category="h6">some text</Text>
          <Text style={styles.statusTextWater} category="p1">some text</Text>
          <Text style={styles.statusTextWR} category="p1">You have gone to the washroom {numTimesDay} times today with each trip being an average of {avgTime} seconds long.</Text>
        <Divider></Divider>
        </View>
        <View style={styles.timerContainer}>
           <Timer setTimerStateChanged={setTimerStateChanged} />
        </View>
        <View style={styles.waterContainer}>
          <Divider></Divider>
          <WaterIntake />
        </View>
      </View>
    </WaterIntakeContext.Provider>
  );
};

const styles = StyleSheet.create({
    container: {
      flex: 1,
      flexDirection: "column",
      justifyContent: "flex-start",
      flexWrap: 'wrap',
      backgroundColor: "#fff",
      paddingRight: 30,
      paddingLeft: 30,
      paddingTop: 20
    },
    statusContainer: {
      borderLeftWidth: 1,
      borderRightWidth: 1,
      borderTopWidth: 1,
      borderBottomWidth: 1,
      flex: 1
    },
    waterContainer: {
      borderLeftWidth: 1,
      borderRightWidth: 1,
      borderTopWidth: 1,
      borderBottomWidth: 1,
      flex: 1,
      width: "100%",
    },
    timerContainer: {
      borderLeftWidth: 1,
      borderRightWidth: 1,
      borderTopWidth: 1,
      borderBottomWidth: 1,
      flex: 2,
      paddingBottom: 10,
    },
    titleText: {
      paddingBottom: 5
    },
    subtitleText: {
      paddingBottom: 20
    },
    statusTextWater: {
      paddingBottom: 10
    },
    statusTextWR: {
      paddingBottom: 20
    }
  });

and finally inside WaterIntake.jsx:

  return (
    <View style={styles.container}>
      <Text category="h6" style={{paddingTop: 20, paddingBottom: 15}}>Water log</Text>
      
      <View style={styles.buttonView}>
        <Button style={styles.button} onPress={async () => {
          await recordWaterIntake(0.25)
        }} >1/4 Cup</Button> 
        <Button style={styles.button} onPress={async () => {
          await recordWaterIntake(0.5)
        }}> 1/2 Cup </Button>
        <Button style={styles.button} onPress={async () => {
          await recordWaterIntake(0.75)
        }}> 3/4 Cup </Button>
        <Button style={styles.button} onPress={async () => {
          await recordWaterIntake(1)
        }}> 1 Cup </Button>
      </View>
      <View style={styles.containerText}>
        <Text>Total water consumed: {dayTotalWater}</Text>

        <Button onPress={resetWaterDb}>Reset table</Button>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    backgroundColor: "#fff",
    justifyContent: "space-between"
  },
  buttonView: {
    flex: 1,
    flexDirection: "row",
    width: "100%",
    resizeMode: 'contain',
  },
  containerText: {
    flex: 2,
    flexDirection: 'column'
  },
  button: {
    margin: 2,
    // width:"22%",
    
  }
});
mr3mo
  • 135
  • 1
  • 10

1 Answers1

1
  1. Wrapping the buttonView div in flex: wrap
    buttonView: {
    flex: 1,
    flexDirection: "row",
    width: "100%",
    resizeMode: 'contain',
    flexWrap: 'wrap'
  },
  1. You can make it as a scrollable:
  buttonView: {
    flex: 1,
    flexDirection: "row",
    width: "100%",
    resizeMode: 'contain',
    overflow: 'auto'
  },

Screenshot: enter image description here

Sam Phillemon
  • 202
  • 3
  • 10
  • Hey @Sam, I have tried this on expo and unfortunately it doesn't work. Please try it in the snack. Specifically you can see that the "Some other text" and "Reset table" component still don't move under the buttons. The expected behaviour is one row of buttons and another row of "Some other text" and finally another row of "Reset Table" – mr3mo Mar 07 '21 at 23:33
  • hi @mr3mo, I have tried this in expo and it is working for me. i have added the screenshot for reference. I hope this is the behaviour you were expecting. – Sam Phillemon Mar 08 '21 at 06:52
  • Hey Sam, so it works well on the Web view as per your screenshot. But it doesn't work on the iOS view – mr3mo Mar 09 '21 at 04:31