본문 바로가기

React + React Native + Expo

[React native] 기초 다지기 - view / 버튼 / Image / flex 세로 가로 설정 / 정렬 등 CSS

반응형

<SafeAreaView> 

only for ios (해당 요소들을 핸드폰의 구조, 메뉴에 닿지않게 padding을 자동으로 넣어줌) 

ios vs android 

android 의 경우에는 자동으로padding 넣어주기 

import { 
  StyleSheet,  // CSS
  Text, 
  TouchableWithoutFeedback,  // 효과없음
  TouchableOpacity,    // 투명도 0되었다가 복구됨
  TouchableHighlight,  // 하이라이트됨
  TouchableNativeFeedback, // 클릭한 곳으로부터 파장
  View, // div와 같은 기능
  Image, 
  SafeAreaView,
  Button,
  Alert,
  Platform, // padding 주기 위해 
  StatusBar,
} from 'react-native';

Platform 가져와서 -> user가 어떤 플팻폼으로 앱을 사용하는지 쳌 

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    paddingTop:Platform.OS === 'android' ? 20 : 0, 
  },
});

그리고 StatusBar 사용해보기 

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    paddingTop:Platform.OS === 'android' ? StatusBar.currentHeight : 0, 
  },
});

 

 

 

 

버튼 

  return (
    <SafeAreaView style={styles.container}>
      <Button 
        color="orange" // iphone은 글자색이, 안드로이드는 백그라운드 색이 바뀜 
        title="Click me" onPress={()=>console.log('clicked')} />
    </SafeAreaView>
  );

버튼 alert 

  return (
    <SafeAreaView style={styles.container}>
      <Button 
        title="Click me"
        onPress={()=>Alert.alert("My title", "My msg", [
          {text:"Yes", onPress:()=>console.log('Yes')},
          {text:"No", onPress:()=>console.log('No')},
        ])}  
      />
    </SafeAreaView>
  );

 

버튼 prompt   (현재 ios에서만 가능)

  return (
    <SafeAreaView style={styles.container}>
      <Button 
        title="Click me"
        onPress={()=>
          Alert.prompt("My title", "My msg", text => console.log(text))
        }
      />
    </SafeAreaView>
  );

 

 

StyleSheet 으로 빼서 css 사용하면 좋은 점 (css 는 아니고js임!) 

-> 오타가 있을 때 알려준다.! 

 

 

 

CSS 섞어서 함꼐 쓰기 

  return (
    <SafeAreaView style={[styles.container,containerStyle]}>
      <Button 
        title="Click me"
        onPress={()=>console.log("button clicked")}
      />
    </SafeAreaView >
  );
}

const containerStyle = {backgroundColor:"orange"};

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

{[   1   ,    2   ]} 요렇게도 쓰면 합쳐진다 

 

 

styles는 해당 component 아래에 코드를 드대로 두는게 나을 수 있다. 모듈로 뺴고 하면 왔다갔다 하는 번거로움이 있다.

 

 

 

 


 

 

 

Dimensions

 

density-independent Pixels = Dips 

physical Pixels = DIPs x Scale Factor 

숫자에 연연할 필요 없대 

export default function App() {
  console.log(Dimensions.get("screen"))
  // window vs screen -> ios는 같고 오직 android에서만 다름 window가 조금더 작다 
  return (
    <SafeAreaView style={styles.container}>
      <View style={{
        backgroundColor:'dodgerblue',
        width:'50%',  
        height:70,
      }}></View>
    </SafeAreaView >
  );
}

 

 

 

 

Detecting Orientation Changes 

resizing according to components 

돌아가게 만들기 

 

app.json

    "orientation": "portrait",   // potrait   vs    landscape   vs  default (support both)
    "icon": "./assets/icon.png",
    "splash": {

터미널 hooks API 설치

npm i @react-native-community/hooks

app.js 에 import 

import { useDimensions } from '@react-native-community/hooks';

console.log 찍어보기 

import { useDimensions, useDeviceOrientation } from '@react-native-community/hooks';

export default function App() {

  console.log(useDimensions())
  console.log(useDeviceOrientation())
  // window vs screen -> ios는 같고 오직 android에서만 다름 window가 조금더 작다 
  return (
    <SafeAreaView style={styles.container}>
      <View style={{

 

위의 useDeviceOrientation() API를 사용해서 height: 를 정해줄 것임 ! -> 폰을 옆으로 볼 때 파란 부분 (보통 동영상 볼 떄) 이 100% height으로 되도록 ! 

import { useDimensions, useDeviceOrientation } from '@react-native-community/hooks';

export default function App() {
    
  const {landscape} = useDeviceOrientation();
  // window vs screen -> ios는 같고 오직 android에서만 다름 window가 조금더 작다 
  return (
    <SafeAreaView style={styles.container}>
      <View style={{
        backgroundColor:'dodgerblue',
        width:'100%',
        height: landscape ? "100%" : "30%"
      }}></View>
    </SafeAreaView >
  );
}

 

 

 

 

Flex Box 

import React from 'react';
import {
  StyleSheet,  // CSS
  Text,
  TouchableWithoutFeedback,  // 효과없음
  TouchableOpacity,    // 투명도 0되었다가 복구됨
  TouchableHighlight,  // 하이라이트됨
  TouchableNativeFeedback, // 클릭한 곳으로부터 파장
  View, // div와 같은 기능
  Image,
  SafeAreaView,
  Button,
  Alert,
  Platform, // padding 주기 위해 
  StatusBar,
  Dimensions,
} from 'react-native';
import { useDimensions, useDeviceOrientation } from '@react-native-community/hooks';

export default function App() {

  return(
    <View 
      style={{
        backgroundColor:"#fff",
        flex:1,
      }}
    >
      <View 
        style={{
          backgroundColor:"dodgerblue",
          flex:2,
        }}
      /> 
      <View 
        style={{
          backgroundColor:"gold",
          flex:1,
        }}
      /> 
      <View 
        style={{
          backgroundColor:"silver",
          flex:1,
        }}
      /> 

    </View>
  );
}

const containerStyle = { backgroundColor: "orange" };

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,
  },
});

 

 

 

FlexDirection

export default function App() {

  return(
    <View 
      style={{
        backgroundColor:"#fff",
        flex:1,
      }}
    >
      <View 
        style={{
          backgroundColor:"dodgerblue",
          // flex:1,
          width:100,
          height:100,
        }}
      /> 
      <View 
        style={{
          backgroundColor:"gold",
          // flex:1,
          width:100,
          height:100,
        }}
      /> 
      <View 
        style={{
          backgroundColor:"tomato",
          // flex:1,
          width:100,
          height:100,
        }}
      /> 

    </View>
  );
}

-> 3개의 Views를 감싸고 있는 View에  flexDirection : "row" 를 주면 된다.

export default function App() {

  return(
    <View 
      style={{
        backgroundColor:"#fff",
        flex:1,
        flexDirection:"row",
      }}
    >
flexDirection:"row"                  수평으로 왼쪽 붙기 
flexDirection:"row-reverse"        수평으로 오른쪽 붙기
flexDirection:"column"              default
flexDirection:"column-reverse"    왼쪽 아래로 떨어진

 

 

 

LINING : jstifyContent, alignitems and alignSelf (box 가운데 넣기 ) 

row center 

  return(
    <View 
      style={{
        backgroundColor:"#fff",
        flex:1,
        flexDirection:"row",
        justifyContent:"center",
      }}
    >

column center

  return(
    <View 
      style={{
        backgroundColor:"#fff",
        flex:1,
        flexDirection:"column",
        justifyContent:"center",
      }}
    >
justifyContent:"flex-start"           왼쪽에 붙기
justifyContent:"flex-end"            오른쪽에 붙기 
justifyContent:"flex-center"         중간으로 
justifyContent:"space-around"     각 요소 따로따로
justifyContent:"space-evenly"      넓이 동일하게
justifyContent:"space-between"   양쪽 끝에 붙도록 

 

alignItems

  return(
    <View 
      style={{
        backgroundColor:"#fff",
        flex:1,
        flexDirection:"row",
        justifyContent:"center",
        alignItems:"cneter",
      }}
    >
  return(
    <View 
      style={{
        backgroundColor:"#fff",
        flex:1,
        flexDirection:"row",
        justifyContent:"center",
        alignItems:"baseline",
      }}
    >
      <View 
        style={{
          backgroundColor:"dodgerblue",
          // flex:1,
          width:100,
          height:300,
        }}
      /> 
      <View 
        style={{
          backgroundColor:"gold",
          // flex:1,
          width:100,
          height:200,
        }}
      />
alignItems:"center"      // 가운데 정렬 
alignItems:"baseline"   //요소 끝 부분 맞추기 
alignItems:"flex-end"   // 요소 bottom에서부터 시작 
alignItems:"flex-start"  // 요소 top으로부터 시작 
alignItems:"stretch"    // 쭉 늘리기 

 

첫 번째 파랑색만 위에서부터 시작하기 

alignItems -> container 

alignSelf -> indivisual item

alignSelf : "flex-start"

  return(
    <View 
      style={{
        backgroundColor:"#fff",
        flex:1,
        flexDirection:"row",
        justifyContent:"center",
        alignItems:"center",
      }}
    >
      <View 
        style={{
          backgroundColor:"dodgerblue",
          // flex:1,
          width:100,
          height:300,
          alignSelf:"flex-start"                  //
        }}   
      />

 

 

 

 

 

FlexWrap and alignContent

export default function App() {

  return(
    <View 
      style={{
        backgroundColor:"#fff",
        flex:1,
        flexDirection:"row",
        justifyContent:"center",
        alignItems:"center",
      }}
    >
      <View 
        style={{
          backgroundColor:"dodgerblue",
          width:100,
          height:100,
        }}
      /> 
      <View 
        style={{
          backgroundColor:"gold",
          width:100,
          height:100,
        }}
      /> 
      <View 
        style={{
          backgroundColor:"tomato",
          width:100,
          height:100,
        }}
      /> 
      <View 
        style={{
          backgroundColor:"grey",
          width:100,
          height:100,
        }}
      /> 
      <View 
        style={{
          backgroundColor:"yellow",
          width:100,
          height:100,
        }}
      /> 

    </View>
  );
}

container View 에 flexWrap:"wrap"을 주면 두번째 사진처럼 된다. 

  return(
    <View 
      style={{
        backgroundColor:"#fff",
        flex:1,
        flexDirection:"row",
        justifyContent:"center",
        alignItems:"center",
        flexWrap:"wrap",
      }}

alignItems:'center'의 의미는 가운데인데 어떤 요소들이 존재할 때의 가운데임

View 1, 4 번의 height를 높여보면 세번째 사진처럼 됨 (center가 맞긴 하다)

 

 

모든걸 수직에서 가운데에 놓고 싶다면 다른 property를 사용한다. => alignContent

 

  return(
    <View 
      style={{
        backgroundColor:"#fff",
        flex:1,
        flexDirection:"row",
        justifyContent:"center",
        alignItems:"center",
        alignContent:"center",
        flexWrap:"wrap",
      }}
    >

* alignItems: 각 line의 content 정렬

* alignContent 전체 content 들 정렬 / 꼭 Wrap 이 있어야 가능 

 

 

 

FlexBasis, FlexFrow and FlexShrink 

      <View 
        style={{
          backgroundColor:"dodgerblue",
          flexBasis:100, // width: or height
          flexGrow:1,
          width:100,
          height:100,
        }}
      />

 

flexBasis : width & height 둘 다 가능 

flexGrow : 1,   --> 전체 비율 100% 까지 내용이 차게됨     == flex 와 동일하나 flex:1을 주었을 떄는 자동으로 고쳐지지않고 rr  새로고침을 해야함 

flexGros   <->  flexShrink 

 

 

Absolute and Relative Positioning

 

      <View 
        style={{
          backgroundColor:"gold",
          width:100,
          height:100,
          left:20
        }}
      />
left:20 
right:20
top:20
bottom:20

각 20px 씩 움직임 

 

abolute = absolute position value 

left: absolute     right : relative 

      <View 
        style={{
          backgroundColor:"gold",
          width:100,
          height:100,
          top:20,
          left:20,
          position:"absolute",
        }}

absolute 는 해당 요소가 절대 값을 가짐

relative 는 다른 요소들은 그대로고 해당 요소만 그 자리에서 값 이동이 됨 

 

 

 

Image

const Main = ()=>{
    return(
        <>
            <SafeAreaView style={styles.container}>
                <Text>I am Main</Text>
                <Image source={require('../assets/cat.jpg')}></Image>
            </SafeAreaView>
        </>
    )
}

인터넷에서 가져오는 image 첨부 방법 

두 개 합친 것 

 

 

Exercises

요 스크린들을 만들어 보기 

 

 

 

왼쪽 -> 오른쪽 되려면 justifyContent:'flex-end' 를 넣어야 한다 ! (두 개 감싸고 있는 곳에!) 

1) 배경 이미지 넣기 / button 두 개 추가 

App.js 에 연결된 welcomeScreen.jsx 

import React from 'react'
import { ImageBackground, StyleSheet, View } from 'react-native'

const WelcomeScreen = (props) => {
    return (
        <>
            <ImageBackground 
                style={styles.background}
                source={require('../assets/cat.jpg')}
            >
                <View style={styles.loginButton}></View>
                <View style={styles.registerButton}></View>
            </ImageBackground>

        </> 
    )
}

const styles = StyleSheet.create({
    background:{
        flex:1,
        justifyContent:'flex-end'   // 요 하나 추가하면 loginbutton 을 아래로 보냄 
    },
    loginButton:{
        width:'100%',
        height:70,
        backgroundColor:'#fc5c65',
        
    },
    registerButton:{
        width:'100%',
        height:70,
        backgroundColor:'#4ecdc4',
    }
})

export default WelcomeScreen

2) 아이콘 추가 

지금 justifyContent:'flex-end' 이므로 안에 아이콘을 넣어도 아래에 붙게 됨 -> position:absolute 로 이동시키기 

import React from 'react'
import { ImageBackground, StyleSheet, View, Image } from 'react-native'

const WelcomeScreen = (props) => {
    return (
        <>
            <ImageBackground 
                style={styles.background}
                source={require('../assets/cat.jpg')}
            >
                <Image source={require('../assets/favicon.png')} style={styles.logo}></Image>
                <View style={styles.loginButton}></View>
                <View style={styles.registerButton}></View>
            </ImageBackground>

        </> 
    )
}

const styles = StyleSheet.create({
    background:{
        flex:1,
        justifyContent:'flex-end',  
        alignItems:'center',           // 로고 중앙정렬 
    },
    loginButton:{
        width:'100%',
        height:70,
        backgroundColor:'#fc5c65',
        
    },
    registerButton:{
        width:'100%',
        height:70,
        backgroundColor:'#4ecdc4',
    },
    logo:{
        width:100,
        height:100,
        position:'absolute',
        top:70,                  // logo absolute로 위에서 70px 만큼 띄우고 
                                  // 중앙 정렬은 요 element의 부모 ele에 가서 alignItems:'center'
    }
})

export default WelcomeScreen

 

3) Test 추가 -> 아이콘 Image + Text를 함께 View tag 에 놓고 중앙 정렬

import React from 'react'
import { ImageBackground, StyleSheet, View, Image, Text } from 'react-native'

const WelcomeScreen = (props) => {
    return (
        <>
            <ImageBackground
                style={styles.background}
                source={require('../assets/cat.jpg')}
            >
                <View style={styles.logoContainer}>
                    <Image source={require('../assets/favicon.png')} style={styles.logo}></Image>
                    <Text>Sell what you don't need</Text>
                </View>
                <View style={styles.loginButton}></View>
                <View style={styles.registerButton}></View>
            </ImageBackground>

        </>
    )
}

const styles = StyleSheet.create({
    background: {
        flex: 1,
        justifyContent: 'flex-end',
        alignItems: 'center',
    },
    loginButton: {
        width: '100%',
        height: 70,
        backgroundColor: '#fc5c65',

    },
    registerButton: {
        width: '100%',
        height: 70,
        backgroundColor: '#4ecdc4',
    },
    logo: {
        width: 100,
        height: 100,
 
    },
    logoContainer:{
        position: 'absolute',
        top: 70,       
        alignItems:'center',
    }
})

export default WelcomeScreen

4) ViewImageScreen 두 번째 Screen 만들기 

app.jsx에 ViewImageScreen.jsx import and return 

import React from 'react';
import {Image, StyleSheet} from 'react-native';

function viewImageScreen(props) {
    return (
        <Image source={require('../assets/me.jpg')} style={styles.image}></Image>
    );
}


const styles = StyleSheet.create({
    image:{
        width:'100%',
        height:'100%',
    }
})

export default viewImageScreen;

width, height : 100% 으로 해도 사진이 짤린다 -> resize mode 때문! 

 

function viewImageScreen(props) {
    return (
        <Image 
            resizeMode="contain"
            source={require('../assets/me.jpg')} 
            style={styles.image}>    
        </Image>
    );
}

resizeMode="contain"을 하면 오른쪽 처럼 이미지 전체가 나온다. 

배경 검정색으로 만들기 - > 새로운 View로 감싸고 styles 추가 , flex = 1 으로 전체 감싸기 

import React from 'react';
import { Image, StyleSheet, View } from 'react-native';

function viewImageScreen(props) {
    return (
        <View style={styles.container}>

            <Image
                resizeMode="contain"
                source={require('../assets/me.jpg')}
                style={styles.image}>
            </Image>
        </View>
    );
}


const styles = StyleSheet.create({

    container: {
        backgroundColor:'black',
        flex:1,
    },
    image: {
        width: '100%',
        height: '100%',
    }
})

export default viewImageScreen;

5) 버튼 만들기 

import React from 'react';
import { Image, StyleSheet, View } from 'react-native';

function viewImageScreen(props) {
    return (
        <View style={styles.container}>
            <View style={styles.closeIcon}></View>
            <View style={styles.deleteIcon}></View>
            <Image
                resizeMode="contain"
                source={require('../assets/me.jpg')}
                style={styles.image}>
            </Image>
        </View>
    );
}


const styles = StyleSheet.create({
    closeIcon:{
        width:50,
        height:50,
        backgroundColor:'#fc5c65',
        position:'absolute',
        top:40,
        left:30,
    },
    deleteIcon:{
        width:50,
        height:50,
        backgroundColor:'#4ecdc4',
        position:'absolute',
        top:40,
        right:30,
    },
    container: {
        backgroundColor:'black',
        flex:1,
    },
    image: {
        width: '100%',
        height: '100%',
    }
})

export default viewImageScreen;

6) 색상들 담은 파일로 따로 빼기 

config 폴더 생성 > colors.js 파일 생성 

export default {
    primary:'#fc5c65',
    secondary:'#4ecdc4',
    black : '#000'
}

ViewImageScreen.js 에서 해당 색상 사용하기 -> 코드가 깔끔해짐 / 기억할 때 좋을 듯 

import React from 'react';
import { Image, StyleSheet, View } from 'react-native';
import colors from '../config/colors'

function viewImageScreen(props) {
    return (
        <View style={styles.container}>
            <View style={styles.closeIcon}></View>
            <View style={styles.deleteIcon}></View>
            <Image
                resizeMode="contain"
                source={require('../assets/me.jpg')}
                style={styles.image}>
            </Image>
        </View>
    );
}


const styles = StyleSheet.create({
    closeIcon:{
        width:50,
        height:50,
        backgroundColor:colors.primary,
        position:'absolute',
        top:40,
        left:30,
    },
    deleteIcon:{
        width:50,
        height:50,
        backgroundColor:colors.secondary,
        position:'absolute',
        top:40,
        right:30,
    },
    container: {
        backgroundColor:colors.black,
        flex:1,
    },
    image: {
        width: '100%',
        height: '100%',
    }
})

export default viewImageScreen;

 

 

 

 

references

https://www.youtube.com/watch?v=0-S5a0eXPoc&t=6024s 

 

반응형