Search code examples
cssreact-nativescrollviewstyled-components

How to properly fix ScrollView to behave similar to a regular view but with a vertical scroll?


I created a component where I have a number of circles displaying in a container, however when I go past two rows, it breaks and spills out of the container. I tried to remedy this with a scrollview, however even if I put the same style, the scrollView has some strange behaviour. I am at a loss on how to fix this, does anybody have any solutions?

Here is how it is before the scrollview:

const OrderContainer = styled.View`
  flex-direction: row;
  flex-wrap: wrap;
  flex-grow: 1;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 10px;
  background: ${({theme}) => theme.colors.salmon}};
  
`;

enter image description here

Here it is after the scrollView, with the same styling but for some reason it looks so messed up:

const OrderContainer = styled(ScrollView).attrs(() => ({
  contentContainerStyle: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    flexGrow: 1,
    justifyContent: 'center',
  },
}))`
  width: 100%;
  height: 100%;
  padding: 10px;
  background: ${({theme}) => theme.colors.salmon}};
`;

It looks like this and only scrolls down until 15.

enter image description here enter image description here

How do I get it looking like the original view, but just scrolling down?

Here are the other components in the container and the tree:

const OrderTextContainer = styled.View`
  flex-direction: column;
  height: 40%;
  width: 19%;
  padding: 10px;
  background: ${({theme}) => theme.colors.pink}};
  position: relative;
`;

const OrderText = styled(Text).attrs(() => ({
  type: TextTypes.H4,
}))`
  border: ${({theme}) => theme.colors.border}};
  background: ${({theme}) => theme.colors.background}};
  color: ${({theme}) => theme.colors.text};
  text-align: center;
  padding-top: 5px;
  width: 35px;
  height: 35px;
  border-radius: 999px;
  border-width: 3px;
`;


 const displayOrders = () =>
    populateArray(orderCount).map((ORDERS) => (
      <OrderTextContainer>
        <OrderText>{ORDERS}</OrderText>
        {ORDERS <= filledOrders && <CrownIcon />}
      </OrderTextContainer>
    ));

  return (
    // eslint-disable-next-line react/jsx-props-no-spreading
    <Container {...props}>
      <InnerContainer>
        <MainContentContainer>
          <TitleText>{`Unlock ${statusTier} Status`}</TitleText>
          <SubText>{`Just order ${orderCount} times this month.`}</SubText>
          <OrderContainer>{displayOrders()}</OrderContainer>
        </MainContentContainer>
        <FooterContentContainer>
          <BurgerIconContainer>
            <BurgerIcon />
          </BurgerIconContainer>
          <PointsTextContainer>
            <PointsText>
              {`You'll earn `}
              <BoldedPointsText>{`${points} points`}</BoldedPointsText>
              {` per dollar when you unlock ${statusTier} Status.`}
            </PointsText>
          </PointsTextContainer>
        </FooterContentContainer>
      </InnerContainer>
      <IconContainer>
        <LockIcon />
      </IconContainer>
    </Container>
  );
};

Solution

  • Solution to my question:

    The problem here was not with the OrderContainer that I switched to a ScrollView. This was working fine and did not need any adjustments from what I had put in ContentContainerStyle.

    The problem was with the fixed height and width I had set around the circles in the OrderTextContainer. Upon reflection, this is exactly what the problem was.

    In the second picture I posted, there is a huge gap between the elements in the container. They are being displayed correctly in a row, and the row is wrapping, however there is a huge space between rows. This is because the OrderTextContainer is spawning each time and with a height of 40% and width of 19%. The solution is to just remove the height and width percentages and let if fill out by itself as it should due to flex behaviour.

    In reflection, I would tell others to be sure you know how your elements are mapped out, and experiment with every single line of CSS you write, and if there are parts of your code that seem somewhat arbitrary and your code is not behaving expectedly, it's usually the arbitrary code.

    Fixed Code:

    const OrderContainer = styled(ScrollView).attrs(() => ({
      contentContainerStyle: {
        flexDirection: 'row',
        flexWrap: 'wrap',
        flexGrow: 1,
        justifyContent: 'center',
      },
    }))`
      width: 100%;
      height: 100%;
      background: ${({theme}) => theme.colors.background}};
      overflow: hidden;
    `;
    
    const OrderTextContainer = styled.View`
      flex-direction: column;
      padding: 10px;
      background: ${({theme}) => theme.colors.background}};
      position: relative;
    `;