Search code examples
iosreact-nativeandroid-studioios-simulatorstyled-components

React-native: Positioning element based on different simulator


I have created one Button component by using styled component and typescript. I have used my button in different places. I am currently testing my app into different simulator. I have an issue with positioning the button. In iPhone-8 it looks as expected but in iPhone-11 the position of the button is different. I have not tested my app in android yet but I am pretty sure it will look different in Android simulator. I used css properties top for positioning. I don't know is there any better way I can position the button component where it looks same in every simulator.

This is my button component

import React from 'react';
import styled from 'styled-components/native';

import { ButtonText } from '../texts';
import { TouchableOpacityProps } from 'react-native';

type Props = TouchableOpacityProps & {
  title: string;
  onPress: () => void;
  disabled?: boolean;
  endTitle?: string;
  color?: string;
};

const Container = styled.TouchableOpacity<Props>`
  background-color: ${({ theme, disabled, color }) =>
    disabled
      ? theme.colors.greyGradient[500]
      : color ?? theme.colors.primaryGradient[900]};
  padding: 20px;
  align-items: center;
  justify-content: ${({ endTitle }) =>
    endTitle ? 'space-between': 'center'};
  flex-direction: row;
`;

const TitleText = styled(ButtonText)`
  color: ${({ theme }) => theme.colors.white};
`;

const Button = ({
  title,
  onPress,
  disabled = false,
  endTitle,
  color
}: Props) => {
  return (
    <Container
      {...{ title, onPress, disabled, color }}
    >
      <TitleText>{title}</TitleText>
      {endTitle && <TitleText>{endTitle}</TitleText>}
    </Container>
  );
};

export default Button;
 

This is the screen where I am using my button component

import React from 'react';
import styled from 'styled-components/native';
import { useNavigation } from '@react-navigation/native';


import Button from './Button';

const Container = styled.View`
  flex: 1;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  background-color: white;
`;

const TitleText = styled.Text`
  padding-top: 20px;
  padding-horizontal: 20px;
  text-align: center;
`;

const DescriptionText = styled.Text`
  text-align: center;
  padding: 20px;
`;

const MenuContainer = styled.View`
  width: 100%;
  top: 23%; // this is the position which is shows me different position in different simulator
`;

const Login = () => {
  const navigation = useNavigation();

  return (
    <Container>
      <TitleText>login</TitleText>
      <DescriptionText>Create an account</DescriptionText>
      <MenuContainer>
        <Button
          title="create a new acount"
          onPress={() => navigation.navigate('register')}
        />
      </MenuContainer>
    </Container>
  );
};

export default Login;

Solution

  • Using % based values on positioning should be avoided since it can cause unforeseen issues on devices with different dimenions.

    Instead, you should use flex: 1 to make an element take up the entire remaining space, so that the element other than this one will get pushed to the edges.

    So what you can do is create a new view which has the code for the expandable element.

    Like this

    const Center = styled.View`
        flex: 1;
        justify-content: center;
        align-items: center;
    `;
    

    And put your title and description inside this. Now since I gave it a flex: 1, it will try to take as much vertical space as possible.

    Now, since your button is below this Center element, it will automatically be pushed as much to the bottom as possible.

    Check this snack for full code.