TigerCow.Door


이전글

리액트 네이티브 #4_ 인스타그램(Instagram) UI 무작정 따라하기 (1)

리액트 네이티브 #5_ 인스타그램(Instagram) UI 무작정 따라하기 (2)

리액트 네이티브 #6_ 인스타그램(Instagram) UI 무작정 따라하기 (3)

리액트 네이티브 #7_ 인스타그램(Instagram) UI 무작정 따라하기 (4)


Github

https://github.com/doorBW/INSTA-by-react-native



안녕하세요. 문범우입니다.

지난 포스팅을 통해 우리는 인스타그램에서 프로필화면의 상단부까지 UI를 따라해보았습니다.


이번 포스팅에서는, 프로필화면에서 하단 네개의 버튼을 구성하고, 네개의 버튼중 두개에 대해서 화면구성을 완성해보도록 하겠습니다.


제가 1편에서 소개해드렸던 영상의 강의는 해당 포스팅까지 입니다.

이후로 지속되는 인스타그램 UI따라하기는, 제가 개인적으로 공부하면서 정리하여 올릴 생각입니다.

영상을 참고했던 이전의 내용들보다 구성이나, 완성도가 떨어질 수 있으나 최선을 다해보도록 하겠습니다 :)


오늘 포스팅을 통해 완성되는 화면은 다음과 같습니다.




그럼 먼저 프로필 화면의 하단을 구현하기전에 간단히 살펴보면, 4가지 버튼이 있는 View와 그 아래 각 버튼에 따라 내용이 나타나는 View로 나누어볼 수 있습니다.

그럼 먼저 버튼을 구성하는 View를 만들어 보도록 하겠습니다.


기존의 Content 태그 내에서 지난번에 작성이 완료된 View 밖에 새로운 View를 만들고, 그 내부에 2개의 View를 만듭니다. (하나는 버튼이 있는 View, 하나는 내용이 있는 View)

먼저 첫번째 View를 아래와 같이 채워줍니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet,
    Image
    } from 'react-native';
import { Icon, Container, Content, Header, Left, Body, Right, Button } from 'native-base';
class ProfileTab extends Component{
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='person' style={{color:tintColor}} />
        )
    }
 
    render(){
        return (
            <Container style={{flex:1, backgroundColor:'white'}}>
                <Header>
                    <Left style={{flexDirection:'row', alignItems:'center'}}>
                        <Text style={{fontWeight:'bold', fontSize:17}}>tigercow.door</Text>
                        <Icon name='caret-down' type='FontAwesome' style={{paddingLeft:10, fontSize:14}}/>
                    </Left>
                    <Right style={{flexDirection:'row', alignItems:'center'}}>
                        <Icon name='back-in-time' type='Entypo' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='user-plus' type='Feather' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='dots-vertical' type='MaterialCommunityIcons' style={{fontSize:23}}/>
                    </Right>
                </Header>
                <Content>
                    <View style={{paddingTop:10}}>
                        <View style={{flexDirection:'row'}}>
                            <View style={{flex:1, alignItems:'center'}}>
                                <Image source={require('../../assets/beomwoo.jpeg')}
                                style={{width:75, height:75, borderRadius:37.5}}/>
                            </View>
                            <View style={{flex:3}}>
                                <View style={{flexDirection:'row', justifyContent:'space-around'}}>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>167</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>게시물</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>346</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로워</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>192</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로잉</Text>
                                    </View>
                                </View>
                                <View style={{flexDirection:'row'}}>
                                    <Button bordered dark
                                    style={{flex:1, justifyContent:'center', height:30, marginHorizontal:10, marginTop:10}}>
                                        <Text>프로필 수정</Text>
                                    </Button>
                                </View>
                            </View>
                        </View>
                        <View style={{paddingHorizontal:10, paddingVertical:10}}>
                            <Text style={{fontWeight:'bold'}}>범우[25:?]</Text>
                            <Text> React-Native로</Text>
                            <Text> Instagram UI 따라하기!!!</Text>
                        </View>
                    </View>
 
                    {/* 하단 */}
                    <View>
                        <View style={{flexDirection:'row', justifyContent:'space-around', borderTopWidth:1,borderTopColor:'#eae5e5'}}>
                            <Button transparent><Icon name='ios-apps-outline'/></Button>
                            <Button transparent><Icon name='ios-list-outline'/></Button>
                            <Button transparent><Icon name='ios-people-outline'/></Button>
                            <Button transparent><Icon name='ios-bookmark-outline'/></Button>
                        </View>
                        <View>
 
                        </View>
                    </View>
                </Content>
            </Container>
        );
    }
}
export default ProfileTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    }
})
cs


69번줄 ~ 74번줄을 보시면 첫번째 View태그 내부에 4개의 버튼이 들어간 것을 볼 수 있습니다. 또한 해당 View 태그에 대해 몇가지 속성을 추가하였습니다.

추가적으로 각 버튼을 눌렀을때, 눌린 버튼이 하이라이팅 되는 효과를 추가해보도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet,
    Image
    } from 'react-native';
import { Icon, Container, Content, Header, Left, Body, Right, Button } from 'native-base';
class ProfileTab extends Component{
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='person' style={{color:tintColor}} />
        )
    }
    constructor(props){
        super(props)
 
        this.state = {
            activeIndex: 0
        };
    }
 
    segmentClicked=(index)=>{
        this.setState({
            activeIndex: index
        })
    }
    
    render(){
        return (
            <Container style={{flex:1, backgroundColor:'white'}}>
                <Header>
                    <Left style={{flexDirection:'row', alignItems:'center'}}>
                        <Text style={{fontWeight:'bold', fontSize:17}}>tigercow.door</Text>
                        <Icon name='caret-down' type='FontAwesome' style={{paddingLeft:10, fontSize:14}}/>
                    </Left>
                    <Right style={{flexDirection:'row', alignItems:'center'}}>
                        <Icon name='back-in-time' type='Entypo' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='user-plus' type='Feather' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='dots-vertical' type='MaterialCommunityIcons' style={{fontSize:23}}/>
                    </Right>
                </Header>
                <Content>
                    <View style={{paddingTop:10}}>
                        <View style={{flexDirection:'row'}}>
                            <View style={{flex:1, alignItems:'center'}}>
                                <Image source={require('../../assets/beomwoo.jpeg')}
                                style={{width:75, height:75, borderRadius:37.5}}/>
                            </View>
                            <View style={{flex:3}}>
                                <View style={{flexDirection:'row', justifyContent:'space-around'}}>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>167</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>게시물</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>346</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로워</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>192</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로잉</Text>
                                    </View>
                                </View>
                                <View style={{flexDirection:'row'}}>
                                    <Button bordered dark
                                    style={{flex:1, justifyContent:'center', height:30, marginHorizontal:10, marginTop:10}}>
                                        <Text>프로필 수정</Text>
                                    </Button>
                                </View>
                            </View>
                        </View>
                        <View style={{paddingHorizontal:10, paddingVertical:10}}>
                            <Text style={{fontWeight:'bold'}}>범우[25:?]</Text>
                            <Text> React-Native로</Text>
                            <Text> Instagram UI 따라하기!!!</Text>
                        </View>
                    </View>
 
                    {/* 하단 */}
                    <View>
                        <View style={{flexDirection:'row', justifyContent:'space-around', borderTopWidth:1,borderTopColor:'#eae5e5'}}>
                            <Button transparent onPress={()=>this.segmentClicked(0)} active={this.state.activeIndex == 0}>
                                <Icon name='ios-apps-outline' style={[this.state.activeIndex == 0 ? {} : {color:'grey'}]}/>
                            </Button>
                            <Button transparent onPress={()=>this.segmentClicked(1)} active={this.state.activeIndex == 1}>
                                <Icon name='ios-list-outline' style={[this.state.activeIndex == 1 ? {} : {color:'grey'}]}/>
                            </Button>
                            <Button transparent onPress={()=>this.segmentClicked(2)} active={this.state.activeIndex == 2}>
                                <Icon name='ios-people-outline' style={[this.state.activeIndex == 2 ? {} : {color:'grey'}]}/>
                            </Button>
                            <Button transparent onPress={()=>this.segmentClicked(3)} active={this.state.activeIndex == 3}>
                                <Icon name='ios-bookmark-outline' style={[this.state.activeIndex == 3 ? {} : {color:'grey'}]}/>
                            </Button>
                        </View>
                        <View>
 
                        </View>
                    </View>
                </Content>
            </Container>
        );
    }
}
export default ProfileTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    }
})
cs


react 자체적인 문법이 약간 사용되는데, 크게 어렵지 않으니 이해하실 수 있을 것 입니다. 먼저 15번줄 ~ 27번줄을 보시면 constructor와 하나의 함수가 정의되어 있습니다. 먼저 constructor에서 state에 activeIndex라는 요소를 지정해주었고 그 초기값은 0으로 두었습니다. 그리고 segmentClicked 함수에서는 클릭되는 요소의 인덱스에 따라서 activeIndex를 바꾸어주는 함수입니다.


그리고 각 버튼을 다시 확인해보면, onPress와 active 속성을 추가해주었습니다. 해당 버튼이 눌렸을때 해당 인덱스를 함수로 전달하여 activeIndex를 변하게끔하고 해당 버튼이 눌려있을때 그 activeIndex값을 유지하도록 합니다.

그리고 내부의 아이콘에 style을 추가해주는데, 현재의 activeIndex와 일치할때는 본래의 색을 내지만 그것이 아닐때는 회색을 갖도록 하였습니다.


이제 4개의 버튼 하단에 있는 내용에 대해서 구성해보도록 하겠습니다.

해당 내용은 단순히 고정된 정보를 보여주는 것이 아니라, 방금 저희가 구현한 4개의 버튼에서 어떤 것이 선택되어 있는지에 따라 보여지는 것이 다릅니다.

따라서 이 또한 함수를 이용해서 내용을 보여주도록 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet,
    Image
    } from 'react-native';
import { Icon, Container, Content, Header, Left, Body, Right, Button } from 'native-base';
class ProfileTab extends Component{
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='person' style={{color:tintColor}} />
        )
    }
    constructor(props){
        super(props)
 
        this.state = {
            activeIndex: 0
        };
    }
 
    segmentClicked=(index)=>{
        this.setState({
            activeIndex: index
        })
    }
 
    renderSection = () =>{
        if (this.state.activeIndex == 0){
            return(
                <View><Text>this is first section</Text></View>
            )
        }
    }
    
    render(){
        return (
            <Container style={{flex:1, backgroundColor:'white'}}>
                <Header>
                    <Left style={{flexDirection:'row', alignItems:'center'}}>
                        <Text style={{fontWeight:'bold', fontSize:17}}>tigercow.door</Text>
                        <Icon name='caret-down' type='FontAwesome' style={{paddingLeft:10, fontSize:14}}/>
                    </Left>
                    <Right style={{flexDirection:'row', alignItems:'center'}}>
                        <Icon name='back-in-time' type='Entypo' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='user-plus' type='Feather' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='dots-vertical' type='MaterialCommunityIcons' style={{fontSize:23}}/>
                    </Right>
                </Header>
                <Content>
                    <View style={{paddingTop:10}}>
                        <View style={{flexDirection:'row'}}>
                            <View style={{flex:1, alignItems:'center'}}>
                                <Image source={require('../../assets/beomwoo.jpeg')}
                                style={{width:75, height:75, borderRadius:37.5}}/>
                            </View>
                            <View style={{flex:3}}>
                                <View style={{flexDirection:'row', justifyContent:'space-around'}}>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>167</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>게시물</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>346</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로워</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>192</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로잉</Text>
                                    </View>
                                </View>
                                <View style={{flexDirection:'row'}}>
                                    <Button bordered dark
                                    style={{flex:1, justifyContent:'center', height:30, marginHorizontal:10, marginTop:10}}>
                                        <Text>프로필 수정</Text>
                                    </Button>
                                </View>
                            </View>
                        </View>
                        <View style={{paddingHorizontal:10, paddingVertical:10}}>
                            <Text style={{fontWeight:'bold'}}>범우[25:?]</Text>
                            <Text> React-Native로</Text>
                            <Text> Instagram UI 따라하기!!!</Text>
                        </View>
                    </View>
 
                    {/* 하단 */}
                    <View>
                        <View style={{flexDirection:'row', justifyContent:'space-around', borderTopWidth:1,borderTopColor:'#eae5e5'}}>
                            <Button transparent onPress={()=>this.segmentClicked(0)} active={this.state.activeIndex == 0}>
                                <Icon name='ios-apps-outline' style={[this.state.activeIndex == 0 ? {} : {color:'grey'}]}/>
                            </Button>
                            <Button transparent onPress={()=>this.segmentClicked(1)} active={this.state.activeIndex == 1}>
                                <Icon name='ios-list-outline' style={[this.state.activeIndex == 1 ? {} : {color:'grey'}]}/>
                            </Button>
                            <Button transparent onPress={()=>this.segmentClicked(2)} active={this.state.activeIndex == 2}>
                                <Icon name='ios-people-outline' style={[this.state.activeIndex == 2 ? {} : {color:'grey'}]}/>
                            </Button>
                            <Button transparent onPress={()=>this.segmentClicked(3)} active={this.state.activeIndex == 3}>
                                <Icon name='ios-bookmark-outline' style={[this.state.activeIndex == 3 ? {} : {color:'grey'}]}/>
                            </Button>
                        </View>
                        <View>
                            {this.renderSection()}
                        </View>
                    </View>
                </Content>
            </Container>
        );
    }
}
export default ProfileTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    }
})
cs


먼저, 105번줄을 보시면 해당 내용은 renderSection()이라는 함수를 통해서 보여지도록 하고 있습니다.

그리고 29번줄 ~ 35번줄을 보시면 renderSection() 함수에 대해서 나와 있습니다.

우리가 위에서 어떤 버튼이 눌려있는지 activeIndex를 통해서 확인했기 때문에, 동일하게 해당 값을 통해서 어떤 버튼이 눌려있는지 확인하고 그에 맞는 내용을 반환하도록 할 것 입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet,
    Image,
    Dimensions
    } from 'react-native';
import { Icon, Container, Content, Header, Left, Body, Right, Button } from 'native-base';
 
var images=[
    require('../../assets/1.jpg'),
    require('../../assets/2.jpg'),
    require('../../assets/3.jpg'),
    require('../../assets/4.jpg'),
    require('../../assets/5.jpg'),
    require('../../assets/6.jpeg'),
    require('../../assets/7.jpg'),
    require('../../assets/beomwoo.jpeg'),
    require('../../assets/deep_learning.png'),
    require('../../assets/python.jpg')
]
 
var {width,height} = Dimensions.get('window')
class ProfileTab extends Component{
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='person' style={{color:tintColor}} />
        )
    }
    constructor(props){
        super(props)
 
        this.state = {
            activeIndex: 0
        };
    }
 
    segmentClicked=(index)=>{
        this.setState({
            activeIndex: index
        })
    }
 
    renderSectionOne = () => {
        return images.map((image,index) => {
            return (
                <View key={index} style={[{width:(width)/3}, {height:(width)/3}]}>
                    <Image style={{flex:1, width:undefined, height:undefined}}
                    source = {image}
                    />
                </View>
            )
        })
    }
 
    renderSection = () =>{
        if (this.state.activeIndex == 0){
            return(
                <View style={{flexDirection:'row', flexWrap:'wrap'}}>
                    {this.renderSectionOne()}
                </View>
            )
        }
    }
 
    
    
    render(){
        return (
            <Container style={{flex:1, backgroundColor:'white'}}>
                <Header>
                    <Left style={{flexDirection:'row', alignItems:'center'}}>
                        <Text style={{fontWeight:'bold', fontSize:17}}>tigercow.door</Text>
                        <Icon name='caret-down' type='FontAwesome' style={{paddingLeft:10, fontSize:14}}/>
                    </Left>
                    <Right style={{flexDirection:'row', alignItems:'center'}}>
                        <Icon name='back-in-time' type='Entypo' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='user-plus' type='Feather' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='dots-vertical' type='MaterialCommunityIcons' style={{fontSize:23}}/>
                    </Right>
                </Header>
                <Content>
                    <View style={{paddingTop:10}}>
                        <View style={{flexDirection:'row'}}>
                            <View style={{flex:1, alignItems:'center'}}>
                                <Image source={require('../../assets/beomwoo.jpeg')}
                                style={{width:75, height:75, borderRadius:37.5}}/>
                            </View>
                            <View style={{flex:3}}>
                                <View style={{flexDirection:'row', justifyContent:'space-around'}}>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>167</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>게시물</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>346</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로워</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>192</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로잉</Text>
                                    </View>
                                </View>
                                <View style={{flexDirection:'row'}}>
                                    <Button bordered dark
                                    style={{flex:1, justifyContent:'center', height:30, marginHorizontal:10, marginTop:10}}>
                                        <Text>프로필 수정</Text>
                                    </Button>
                                </View>
                            </View>
                        </View>
                        <View style={{paddingHorizontal:10, paddingVertical:10}}>
                            <Text style={{fontWeight:'bold'}}>범우[25:?]</Text>
                            <Text> React-Native로</Text>
                            <Text> Instagram UI 따라하기!!!</Text>
                        </View>
                    </View>
 
                    {/* 하단 */}
                    <View>
                        <View style={{flexDirection:'row', justifyContent:'space-around', borderTopWidth:1,borderTopColor:'#eae5e5'}}>
                            <Button transparent onPress={()=>this.segmentClicked(0)} active={this.state.activeIndex == 0}>
                                <Icon name='ios-apps-outline' style={[this.state.activeIndex == 0 ? {} : {color:'grey'}]}/>
                            </Button>
                            <Button transparent onPress={()=>this.segmentClicked(1)} active={this.state.activeIndex == 1}>
                                <Icon name='ios-list-outline' style={[this.state.activeIndex == 1 ? {} : {color:'grey'}]}/>
                            </Button>
                            <Button transparent onPress={()=>this.segmentClicked(2)} active={this.state.activeIndex == 2}>
                                <Icon name='ios-people-outline' style={[this.state.activeIndex == 2 ? {} : {color:'grey'}]}/>
                            </Button>
                            <Button transparent onPress={()=>this.segmentClicked(3)} active={this.state.activeIndex == 3}>
                                <Icon name='ios-bookmark-outline' style={[this.state.activeIndex == 3 ? {} : {color:'grey'}]}/>
                            </Button>
                        </View>
                        <View>
                            {this.renderSection()}
                        </View>
                    </View>
                </Content>
            </Container>
        );
    }
}
export default ProfileTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    }
})
cs


renderSection에서 첫번째 버튼이 눌렸을때 보여주고자 하는 것은 다수의 이미지 입니다. 먼저 이러한 이미지를 위해 11번줄 ~ 22번줄과 같이 여러개의 이미지를 불러왔습니다. 그리고 각각의 이미지를 알맞게 보여주도록하기 위해 새로운 renderSectionOne 함수를 만들었습니다.

45번줄 ~ 55번줄을 보시면 해당 함수에 대해서 코드가 작성되어 있습니다.

map함수를 통해 images에 있는 각각의 이미지에 대해 모두 처리하도록 하여 많은 이미지를 보다 쉽게 설정할 수 있습니다.

각각의 이미지의 크기는 사용자의 핸드폰 화면의 1/3 정도의 크기를 가지는데 이를 위해서 최상단에 Dimensions라는 것을 Import하여 24번줄과 같이 사용자의 화면 크기를 받아왔고, 이를 통해 각 이미지의 가로, 세로를 설정하였습니다.


마지막으로, 각 이미지간에 존재하는 약간의 경계를 설정하고, 두번째 버튼을 눌렀을때 나오는 화면을 구성해보도록 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet,
    Image,
    Dimensions
    } from 'react-native';
import { Icon, Container, Content, Header, Left, Body, Right, Button } from 'native-base';
import CardCompnent from '../CardComponent';
 
var images=[
    require('../../assets/1.jpg'),
    require('../../assets/2.jpg'),
    require('../../assets/3.jpg'),
    require('../../assets/4.jpg'),
    require('../../assets/5.jpg'),
    require('../../assets/6.jpeg'),
    require('../../assets/7.jpg'),
    require('../../assets/beomwoo.jpeg'),
    require('../../assets/deep_learning.png'),
    require('../../assets/python.jpg')
]
 
var {width,height} = Dimensions.get('window')
class ProfileTab extends Component{
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='person' style={{color:tintColor}} />
        )
    }
    constructor(props){
        super(props)
 
        this.state = {
            activeIndex: 0
        };
    }
 
    segmentClicked=(index)=>{
        this.setState({
            activeIndex: index
        })
    }
 
    renderSectionOne = () => {
        return images.map((image,index) => {
            return (
                <View key={index} style={[{width:(width)/3}, {height:(width)/3}, index % 3 !== 0 ? {paddingLeft:2}:{paddingLeft:0},{marginBottom:2}]}>
                    <Image style={{flex:1, width:undefined, height:undefined}}
                    source = {image}
                    />
                </View>
            )
        })
    }
 
    renderSection = () =>{
        if (this.state.activeIndex == 0){
            return(
                <View style={{flexDirection:'row', flexWrap:'wrap'}}>
                    {this.renderSectionOne()}
                </View>
            )
        }
        else if(this.state.activeIndex == 1){
            return(
                <View>
                <CardCompnent imageSource='1' likes='100'/>
                <CardCompnent imageSource='2' likes='36'/>
                <CardCompnent imageSource='3' likes='240'/>
                </View>
            )
        }
    }
 
    
    
    render(){
        return (
            <Container style={{flex:1, backgroundColor:'white'}}>
                <Header>
                    <Left style={{flexDirection:'row', alignItems:'center'}}>
                        <Text style={{fontWeight:'bold', fontSize:17}}>tigercow.door</Text>
                        <Icon name='caret-down' type='FontAwesome' style={{paddingLeft:10, fontSize:14}}/>
                    </Left>
                    <Right style={{flexDirection:'row', alignItems:'center'}}>
                        <Icon name='back-in-time' type='Entypo' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='user-plus' type='Feather' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='dots-vertical' type='MaterialCommunityIcons' style={{fontSize:23}}/>
                    </Right>
                </Header>
                <Content>
                    <View style={{paddingTop:10}}>
                        <View style={{flexDirection:'row'}}>
                            <View style={{flex:1, alignItems:'center'}}>
                                <Image source={require('../../assets/beomwoo.jpeg')}
                                style={{width:75, height:75, borderRadius:37.5}}/>
                            </View>
                            <View style={{flex:3}}>
                                <View style={{flexDirection:'row', justifyContent:'space-around'}}>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>167</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>게시물</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>346</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로워</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>192</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로잉</Text>
                                    </View>
                                </View>
                                <View style={{flexDirection:'row'}}>
                                    <Button bordered dark
                                    style={{flex:1, justifyContent:'center', height:30, marginHorizontal:10, marginTop:10}}>
                                        <Text>프로필 수정</Text>
                                    </Button>
                                </View>
                            </View>
                        </View>
                        <View style={{paddingHorizontal:10, paddingVertical:10}}>
                            <Text style={{fontWeight:'bold'}}>범우[25:?]</Text>
                            <Text> React-Native로</Text>
                            <Text> Instagram UI 따라하기!!!</Text>
                        </View>
                    </View>
 
                    {/* 하단 */}
                    <View>
                        <View style={{flexDirection:'row', justifyContent:'space-around', borderTopWidth:1,borderTopColor:'#eae5e5'}}>
                            <Button transparent onPress={()=>this.segmentClicked(0)} active={this.state.activeIndex == 0}>
                                <Icon name='ios-apps-outline' style={[this.state.activeIndex == 0 ? {} : {color:'grey'}]}/>
                            </Button>
                            <Button transparent onPress={()=>this.segmentClicked(1)} active={this.state.activeIndex == 1}>
                                <Icon name='ios-list-outline' style={[this.state.activeIndex == 1 ? {} : {color:'grey'}]}/>
                            </Button>
                            <Button transparent onPress={()=>this.segmentClicked(2)} active={this.state.activeIndex == 2}>
                                <Icon name='ios-people-outline' style={[this.state.activeIndex == 2 ? {} : {color:'grey'}]}/>
                            </Button>
                            <Button transparent onPress={()=>this.segmentClicked(3)} active={this.state.activeIndex == 3}>
                                <Icon name='ios-bookmark-outline' style={[this.state.activeIndex == 3 ? {} : {color:'grey'}]}/>
                            </Button>
                        </View>
                        <View>
                            {this.renderSection()}
                        </View>
                    </View>
                </Content>
            </Container>
        );
    }
}
export default ProfileTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    }
})
cs


49번줄의 style을 보시면, paddingLeft는 요소가 몇번째에 위치해있는지에 따라 값을 주거나, 안주는 것으로 설정하였고 marginBottom은 모든 이미지에게 2라는 값을 주었습니다.


이렇게되면 첫번째 버튼을 눌렀을때의 화면이 잘 나오고, 두번째 버튼은 우리가 지난번에 만든 CardComponent를 이용하여 66번줄 ~ 74번줄과 같이 작성하면 완성됩니다.


블로그 이미지

Tigercow.Door

Web Programming / Back-end / Database / AI / Algorithm / DeepLearning / etc

댓글을 달아 주세요


지난글

리액트 네이티브 #4_ 인스타그램(Instagram) UI 무작정 따라하기 (1)

리액트 네이티브 #5_ 인스타그램(Instagram) UI 무작정 따라하기 (2)

리액트 네이티브 #6_ 인스타그램(Instagram) UI 무작정 따라하기 (3)


Github

https://github.com/doorBW/INSTA-by-react-native



안녕하세요. 문범우입니다.

지난 포스팅에서는 인스타그램 메인 화면 상단에 있는 스토리바를 추가해보았습니다.

이번 포스팅에서는 프로필창의 상단부분을 완성시켜보도록 합니다.

이번 포스팅을 통해 나오는 결과물은 다음과 같습니다.

(강의에서 진행되는 내용과 약간의 차이가 존재합니다.)



1. 상단 네비게이션바 수정


먼저 현재의 프로필 탭을 눌러보면 다음과 같은 화면이 나옵니다.


첫번째로 수정해야 하는 항목은 상단 네비게이션입니다.

우리가 HomeTab에서의 기준으로 상단바를 만들었는데, 사실상 프로필탭에서는 상단바가 다릅니다.

따라서, MainScreen.js에 있는 상단 네비게이션 바를 없애고 아래와 같이 수정합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet,
    Platform
    } from 'react-native';
 
import { Icon } from 'native-base';
import { createTabNavigator } from 'react-navigation';
 
import HomeTab from './AppTabNavigator/HomeTab';
import SearchTab from './AppTabNavigator/SearchTab';
import AddMediaTab from './AppTabNavigator/AddMediaTab';
import LikesTab from './AppTabNavigator/LikesTab';
import ProfileTab from './AppTabNavigator/ProfileTab';
 
class MainScreen extends Component{
 
    static navigationOptions = {
        header: null
    }
 
    render() {
        return (
            <AppTabNavigator />
        );
    }
}
export default MainScreen;
 
const AppTabNavigator = createTabNavigator({
    HomeTab:{
        screen: HomeTab
    },
    Search:{
        screen: SearchTab
    },
    AddMedia:{
        screen: AddMediaTab
    },
    Likes:{
        screen: LikesTab
    },
    Profile:{
        screen: ProfileTab
    }
}, {
    animationEnabled: true,
    swipeEnabled: true,
    tabBarPosition: "bottom",
    tabBarOptions: {
        style: {
            ...Platform.select({
                android:{
                    backgroundColor:'white'
                }
            })
        },
        activeTintColor: '#000',
        inactiveTintColor: '#d1cece',
        showLabel: false,
        showIcon: true,
    }
})
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    }
})
cs


21번줄을 보시면 이전에 있던 헤더를 모두 없애고 단순히 null 값을 주었습니다.


이제 HomeTab.js에서 헤더를 추가해야합니다.

헤더를 만들기 위해 필요한, Header, Left, Right, Body를 native base에서 import하고 아래와 같이 코드를 작성합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet,
    ScrollView
    } from 'react-native';
import { Icon, Container, Content, Thumbnail, Header, Left, Right, Body } from 'native-base';
 
import CardComponent from '../CardComponent';
 
class HomeTab extends Component{
 
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='ios-home' style={{color:tintColor}} />
        )
    }
 
    render(){
        return (
            <Container style = {style.container}>
                <Header>
                    <Left><Icon name='ios-camera-outline' style={{paddingLeft:10}}/></Left>
                    <Body><Text style={{fontWeight:'900'}}>Instagram</Text></Body>
                    <Right><Icon name='ios-send-outline' style={{paddingRight:10}}/></Right>
                </Header>
                <Content>
                    <View style={{height:100}}>
                        <View style={{flex:1, flexDirection:'row', justifyContent:'space-between', alignItems:'center', paddingHorizontal:7}}>
                            <Text style={{fontWeight:'bold'}}>스토리</Text>
                            <View style={{flexDirection:'row', alignItems:'center'}}>
                                <Icon name='md-play' style={{fontSize:14}}/>
                                <Text style={{fontWeight:'bold'}}>모두 보기</Text>
                            </View>
                        </View>
                        <View style={{flex:3}}>
                            <ScrollView 
                                horizontal={true}
                                showsHorizontalScrollIndicator={false}
                                contentContainerStyle={{
                                    alignItems:'center',
                                    paddingStart:5,
                                    paddingEnd:5
                                }}
                            >
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/beomwoo.jpeg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/1.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/2.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/3.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/4.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/5.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/6.jpeg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/7.jpg')}/>
                                
                            </ScrollView>
                        </View>
                    </View>
                    <CardComponent imageSource='1' likes='2324'/>
                    <CardComponent imageSource='2' likes='46'/>
                    <CardComponent imageSource='3' likes='208'/>
                </Content>
            </Container>
        );
    }
}
export default HomeTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: 'white'
    }
})
cs


23번줄 ~ 27번줄을 보시면 헤더가 추가된 코드를 확인하실 수 있습니다.

이렇게 하면 HomeTab에서만 상단 바가 나타나고 다른 화면에서는 나타나지 않는 것을 확인할 수 있습니다.



2. 프로필창 상단 구성하기


그럼 이제 프로필창으로 넘어와서 상단 네비게이션 바와, 프로필 사진, 팔로워 수 등을 구성해보도록 하겠습니다.

먼저 전체적인 구성에 필요할 요소들을 import 합니다.

native base로 부터, Container, Content, Header, Left, Body, Right, Button을 import 합니다.


이제 프로필창 상단에 있는 네비게이션 바를 구성합니다.

(해당 부분은 강의 영상과 약간의 차이가 있습니다.)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet
    } from 'react-native';
import { Icon, Container, Content, Header, Left, Body, Right, Button } from 'native-base';
class ProfileTab extends Component{
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='person' style={{color:tintColor}} />
        )
    }
 
    render(){
        return (
            <Container>
                <Header>
                    <Left style={{flexDirection:'row', alignItems:'center'}}>
                        <Text style={{fontWeight:'bold', fontSize:17}}>tigercow.door</Text>
                        <Icon name='caret-down' type='FontAwesome' style={{paddingLeft:10, fontSize:14}}/>
                    </Left>
                    <Right style={{flexDirection:'row', alignItems:'center'}}>
                        <Icon name='back-in-time' type='Entypo' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='user-plus' type='Feather' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='dots-vertical' type='MaterialCommunityIcons' style={{fontSize:23}}/>
                    </Right>
                </Header>
            </Container>
        );
    }
}
export default ProfileTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    }
})
cs


18번줄 ~ 28번줄까지 프로필창의 헤더를 구성하였습니다. HomeTab에서의 구성과 거의 비슷하지만 Body가 없고 Left와 Right에 2개이상의 요소가 들어갑니다.


이제 이어서 프로필 사진과 그 옆의 요소들을 구성해보도록 하겠습니다.


먼저, 사진과 게시물, 팔로워, 팔로잉 수를 나타내는 요소를 구성하였습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet,
    Image
    } from 'react-native';
import { Icon, Container, Content, Header, Left, Body, Right, Button } from 'native-base';
class ProfileTab extends Component{
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='person' style={{color:tintColor}} />
        )
    }
 
    render(){
        return (
            <Container>
                <Header>
                    <Left style={{flexDirection:'row', alignItems:'center'}}>
                        <Text style={{fontWeight:'bold', fontSize:17}}>tigercow.door</Text>
                        <Icon name='caret-down' type='FontAwesome' style={{paddingLeft:10, fontSize:14}}/>
                    </Left>
                    <Right style={{flexDirection:'row', alignItems:'center'}}>
                        <Icon name='back-in-time' type='Entypo' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='user-plus' type='Feather' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='dots-vertical' type='MaterialCommunityIcons' style={{fontSize:23}}/>
                    </Right>
                </Header>
                <Content>
                    <View>
                        <View style={{flexDirection:'row'}}>
                            <View style={{flex:1}}>
                                <Image source={require('../../assets/beomwoo.jpeg')}
                                style={{width:75, height:75, borderRadius:37.5}}/>
                            </View>
                            <View style={{flex:3}}>
                                <View style={{flexDirection:'row', justifyContent:'space-around'}}>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>167</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>게시물</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>346</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로워</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>192</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로잉</Text>
                                    </View>
                                </View>
                            </View>
                        </View>
                    </View>
                </Content>
            </Container>
        );
    }
}
export default ProfileTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    }
})
cs


많은 View태그로 묶여있어서 헷갈릴 수도 있지만 하나씩 살펴보도록 하겠습니다.

31번줄에서 첫번째 View태그로 시작되어 프로필창을 전체적으로 묶어주고 있습니다.

이후 다음 32번줄의 View태그에서는 상단 태그를 묶어주는 것으로써 상단의 요소들이 가로로 정렬되기 때문에 flexDirection도 함께 설정하였습니다.

그리고 33번의 View태그에서는 사진을 담고 있으며, 37번의 View태그에서는 사진 우측의 요소들을 담고 있습니다.

그리고 우측 요소들 중에, 게시글, 팔로워, 팔로잉을 나타내는 요소들을 각각 View태그로 묶어서 구성하였습니다.


이제 그 요소들 아래에 버튼을 추가하고, 그 하단에 이름과 내용을 작성해봅니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet,
    Image
    } from 'react-native';
import { Icon, Container, Content, Header, Left, Body, Right, Button } from 'native-base';
class ProfileTab extends Component{
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='person' style={{color:tintColor}} />
        )
    }
 
    render(){
        return (
            <Container style={{flex:1, backgroundColor:'white'}}>
                <Header>
                    <Left style={{flexDirection:'row', alignItems:'center'}}>
                        <Text style={{fontWeight:'bold', fontSize:17}}>tigercow.door</Text>
                        <Icon name='caret-down' type='FontAwesome' style={{paddingLeft:10, fontSize:14}}/>
                    </Left>
                    <Right style={{flexDirection:'row', alignItems:'center'}}>
                        <Icon name='back-in-time' type='Entypo' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='user-plus' type='Feather' style={{paddingRight:10, fontSize:23}}/>
                        <Icon name='dots-vertical' type='MaterialCommunityIcons' style={{fontSize:23}}/>
                    </Right>
                </Header>
                <Content>
                    <View style={{paddingTop:10}}>
                        <View style={{flexDirection:'row'}}>
                            <View style={{flex:1, alignItems:'center'}}>
                                <Image source={require('../../assets/beomwoo.jpeg')}
                                style={{width:75, height:75, borderRadius:37.5}}/>
                            </View>
                            <View style={{flex:3}}>
                                <View style={{flexDirection:'row', justifyContent:'space-around'}}>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>167</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>게시물</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>346</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로워</Text>
                                    </View>
                                    <View style={{alignItems:'center'}}>
                                        <Text style={{fontSize:17, fontWeight:'bold'}}>192</Text>
                                        <Text style={{fontSize:12, color:'gray'}}>팔로잉</Text>
                                    </View>
                                </View>
                                <View style={{flexDirection:'row'}}>
                                    <Button bordered dark
                                    style={{flex:1, justifyContent:'center', height:30, marginHorizontal:10, marginTop:10}}>
                                        <Text>프로필 수정</Text>
                                    </Button>
                                </View>
                            </View>
                        </View>
                        <View style={{paddingHorizontal:10, paddingVertical:10}}>
                            <Text style={{fontWeight:'bold'}}>범우[25:?]</Text>
                            <Text> React-Native로</Text>
                            <Text> Instagram UI 따라하기!!!</Text>
                        </View>
                    </View>
                </Content>
            </Container>
        );
    }
}
export default ProfileTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    }
})
cs


53번 ~ 56번줄에서 버튼을 추가했습니다.

그리고 지금까지 구성한 요소들을 묶는 View태그에서 벗어나 60번 줄에서 새로운 View태그를 만들어 그 안에 사용자의 이름과 내용을 넣어주었습니다.


이렇게 하여 나온 결과는 다음과 같습니다.



블로그 이미지

Tigercow.Door

Web Programming / Back-end / Database / AI / Algorithm / DeepLearning / etc

댓글을 달아 주세요


지난글

리액트 네이티브 #4_ 인스타그램(Instagram) UI 무작정 따라하기 (1)

리액트 네이티브 #5_ 인스타그램(Instagram) UI 무작정 따라하기 (2)


Github

https://github.com/doorBW/INSTA-by-react-native



안녕하세요. 문범우입니다. 

지난 포스팅에서는 Home 화면에 피드를 추가하는 과정까지 진행해보았습니다.


이번 포스팅에서는 Home 화면에서 상단에 있는 스토리바를 추가해보도록 하겠습니다.

해당 포스트를 통해서 나오는 결과물은 아래와 같습니다.



1. 스토리바 만들기


우리는 스토리바를 추가하기 위해 HomeTab.js 에서 작업을 진행합니다.

이전 포스팅을 통해 현재 HomeTab.js의 코드는 아래와 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet
    } from 'react-native';
import { Icon, Container, Content } from 'native-base';
 
import CardComponent from '../CardComponent';
 
class HomeTab extends Component{
 
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='ios-home' style={{color:tintColor}} />
        )
    }
 
    render(){
        return (
            <Container style = {style.container}>
                <Content>
                    <CardComponent imageSource='1' likes='2324'/>
                    <CardComponent imageSource='2' likes='46'/>
                    <CardComponent imageSource='3' likes='208'/>
                </Content>
            </Container>
        );
    }
}
export default HomeTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: 'white'
    }
})
cs


이제 스토리바를 추가해 볼건데, 먼저 스토리바의 위치와 형태를 잡아보도록 하겠습니다.

스토리바는 Content 태그 안에 위치하며 CardComponent보다 위에 존재합니다.

따라서 위의 코드에서 22번줄과 23번줄 사이에 코드를 작성하는 것으로 시작합니다.

<View> 태그로 기준을 잡고, '스토리' 와 '모두 보기' 텍스트를 아래와 같이 넣어줍니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet
    } from 'react-native';
import { Icon, Container, Content } from 'native-base';
 
import CardComponent from '../CardComponent';
 
class HomeTab extends Component{
 
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='ios-home' style={{color:tintColor}} />
        )
    }
 
    render(){
        return (
            <Container style = {style.container}>
                <Content>
                    <View>
                        <Text>스토리</Text>
                        <Text>모두 보기</Text>
                    </View>
                    <CardComponent imageSource='1' likes='2324'/>
                    <CardComponent imageSource='2' likes='46'/>
                    <CardComponent imageSource='3' likes='208'/>
                </Content>
            </Container>
        );
    }
}
export default HomeTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: 'white'
    }
})
cs


위의 코드를 보시면 23번줄 ~ 26번줄에 View태그로 감싸져 있는 것을 볼 수 있고 내부에 Text태그로 '스토리'와 '모두 보기' 두개가 입력된 것을 볼 수 있습니다.


조금 더 구조를 세분화해보도록 하겠습니다.



위와 같이 검은색 테두리로 된 스토리바를 현재 추가하려고 하는데, 이는 또 두개의 View로 나눌 수 있습니다.

현재 두개의 텍스트를 넣어준 파란색 테두리와, 스토리를 올린 사람들의 사진이 보일 빨간색 테두리로 나눌 수 있습니다.

따라서, 우리가 위에서 작성한 두개의 텍스트 태그를 또 다른 View 태그로 묶어주고, 그 아래에 다른 View 태그를 만들어줍니다.

그리고 스토리바 전체를 묶고 있는, 검은색 테두리의 View 태그는 높이를 100으로 지정해주며, 파란색 테두리의 View 태그에 필요한 속성도 설정해줍니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet
    } from 'react-native';
import { Icon, Container, Content } from 'native-base';
 
import CardComponent from '../CardComponent';
 
class HomeTab extends Component{
 
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='ios-home' style={{color:tintColor}} />
        )
    }
 
    render(){
        return (
            <Container style = {style.container}>
                <Content>
                    <View style={{height:100}}>
                        <View style={{flex:1, flexDirection:'row', justifyContent:'space-between', alignItems:'center', paddingHorizontal:7}}>
                            <Text>스토리</Text>
                            <Text>모두 보기</Text>
                        </View>
                        <View>
 
                        </View>
                    </View>
                    <CardComponent imageSource='1' likes='2324'/>
                    <CardComponent imageSource='2' likes='46'/>
                    <CardComponent imageSource='3' likes='208'/>
                </Content>
            </Container>
        );
    }
}
export default HomeTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: 'white'
    }
})
cs


24번줄의 View 태그가 파란색 테두리로써 '스토리' 와 '모두 보기' 텍스트를 감싸고 있습니다. 이들의 flex는 1로 지정해주고, 가로로 정렬되게 하며 space-between 속성으로 서로 양쪽끝에 오도록 합니다.


이제 빨간색 테두리의 형태를 잡아보도록 하겠습니다.

빨간색 테두리 View는 파란색 테두리보다 커야합니다.

따라서 flex는 3으로 지정합니다. 또한 빨간색 테두리 내부에 들어가는 스토리의 사진들은 가로로 스크롤할 수 있기 때문에, 이를 위해 ScrollView 를 import에 추가해주어야 합니다. 그리고 ScrollView 내부에는 Thumbnail 을 통해 여러개의 이미지를 넣어줍니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet,
    ScrollView
    } from 'react-native';
import { Icon, Container, Content, Thumbnail } from 'native-base';
 
import CardComponent from '../CardComponent';
 
class HomeTab extends Component{
 
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='ios-home' style={{color:tintColor}} />
        )
    }
 
    render(){
        return (
            <Container style = {style.container}>
                <Content>
                    <View style={{height:100}}>
                        <View style={{flex:1, flexDirection:'row', justifyContent:'space-between', alignItems:'center', paddingHorizontal:7}}>
                            <Text>스토리</Text>
                            <Text>모두 보기</Text>
                        </View>
                        <View style={{flex:3}}>
                            <ScrollView>
                                <Thumbnail source={require('../../assets/beomwoo.jpeg')}/>
                                <Thumbnail source={require('../../assets/1.jpg')}/>
                                <Thumbnail source={require('../../assets/2.jpg')}/>
                                <Thumbnail source={require('../../assets/3.jpg')}/>
                                <Thumbnail source={require('../../assets/4.jpg')}/>
                                <Thumbnail source={require('../../assets/5.jpg')}/>
                                <Thumbnail source={require('../../assets/6.jpeg')}/>
                                <Thumbnail source={require('../../assets/7.jpg')}/>
                            </ScrollView>
                        </View>
                    </View>
                    <CardComponent imageSource='1' likes='2324'/>
                    <CardComponent imageSource='2' likes='46'/>
                    <CardComponent imageSource='3' likes='208'/>
                </Content>
            </Container>
        );
    }
}
export default HomeTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: 'white'
    }
})
cs


29번줄을 보시면 빨간색 테두리 View의 flex를 3으로 설정해준것을 확인할 수 있습니다.

그리고 그 다음에 ScrollView를 사용하기 위해 6번줄과 같이 ScrollView를 import에 추가해주었으며 ScrollView에 여러개의 Thumbnail을 통해 사진을 넣어 주었습니다.

이렇게 하고 시뮬레이터를 확인해보면, 스토리바 위치에 사진들이 여러개 있지만, 사진들이 세로로 정렬되어 있어 이상한 것을 확인할 수 있습니다.

각각의 썸네일의 스타일도 수정해보고, 스토리바의 속성도 설정해보겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet,
    ScrollView
    } from 'react-native';
import { Icon, Container, Content, Thumbnail } from 'native-base';
 
import CardComponent from '../CardComponent';
 
class HomeTab extends Component{
 
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='ios-home' style={{color:tintColor}} />
        )
    }
 
    render(){
        return (
            <Container style = {style.container}>
                <Content>
                    <View style={{height:100}}>
                        <View style={{flex:1, flexDirection:'row', justifyContent:'space-between', alignItems:'center', paddingHorizontal:7}}>
                            <Text>스토리</Text>
                            <Text>모두 보기</Text>
                        </View>
                        <View style={{flex:3}}>
                            <ScrollView 
                                horizontal={true}
                                showsHorizontalScrollIndicator={false}
                                contentContainerStyle={{
                                    alignItems:'center',
                                    paddingStart:5,
                                    paddingEnd:5
                                }}
                            >
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/beomwoo.jpeg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/1.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/2.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/3.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/4.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/5.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/6.jpeg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/7.jpg')}/>
                                
                            </ScrollView>
                        </View>
                    </View>
                    <CardComponent imageSource='1' likes='2324'/>
                    <CardComponent imageSource='2' likes='46'/>
                    <CardComponent imageSource='3' likes='208'/>
                </Content>
            </Container>
        );
    }
}
export default HomeTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: 'white'
    }
})
cs


먼저, 30번줄 ~ 38번줄을 보시면 ScrollView에서 몇가지 속성을 설정한 것을 확인할 수 있습니다. 내부의 Thumbnail들이 가로로 정렬하도록 horizontal 을 true로 설정하였고, 스크롤 바가 보이지 않도록 설정하였으며 내부 아이템들의 스타일또한 설정하였습니다.

그리고 각각의 Thumbnail에 모두 동일하게, margin 값을 5로 설정하며 사진의 테두리에 빨간색 선이 있도록 설정해주었습니다.


이렇게까지 하면 어느정도 자리잡은 스토리바의 형태가 보입니다.

마무리로 약간의 수정을 해보도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import React, { Component } from 'react';
import { 
    View,
    Text,
    StyleSheet,
    ScrollView
    } from 'react-native';
import { Icon, Container, Content, Thumbnail } from 'native-base';
 
import CardComponent from '../CardComponent';
 
class HomeTab extends Component{
 
    static navigationOptions = {
        tabBarIcon: ({ tintColor }) => (
            < Icon name='ios-home' style={{color:tintColor}} />
        )
    }
 
    render(){
        return (
            <Container style = {style.container}>
                <Content>
                    <View style={{height:100}}>
                        <View style={{flex:1, flexDirection:'row', justifyContent:'space-between', alignItems:'center', paddingHorizontal:7}}>
                            <Text style={{fontWeight:'bold'}}>스토리</Text>
                            <View style={{flexDirection:'row', alignItems:'center'}}>
                                <Icon name='md-play' style={{fontSize:14}}/>
                                <Text style={{fontWeight:'bold'}}>모두 보기</Text>
                            </View>
                        </View>
                        <View style={{flex:3}}>
                            <ScrollView 
                                horizontal={true}
                                showsHorizontalScrollIndicator={false}
                                contentContainerStyle={{
                                    alignItems:'center',
                                    paddingStart:5,
                                    paddingEnd:5
                                }}
                            >
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/beomwoo.jpeg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/1.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/2.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/3.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/4.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/5.jpg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/6.jpeg')}/>
                                <Thumbnail style={{marginHorizontal:5, borderColor:'red', borderWidth:2}} source={require('../../assets/7.jpg')}/>
                                
                            </ScrollView>
                        </View>
                    </View>
                    <CardComponent imageSource='1' likes='2324'/>
                    <CardComponent imageSource='2' likes='46'/>
                    <CardComponent imageSource='3' likes='208'/>
                </Content>
            </Container>
        );
    }
}
export default HomeTab;
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: 'white'
    }
})
cs


수정된 것은 26번줄 ~ 30번줄 입니다.

먼저, 27번줄 ~ 30번줄을 보시면 하나의 View태그가 추가되어 아까 있던 '모두 보기' 텍스트와 새롭게 Icon 텍스트를 감싸고 있는 것을 볼 수 있습니다.

인스타그램의 모두보기 옆에 아이콘이 있기 때문에 이를 추가해주었고 해당 아이콘과 '모두보기'텍스트를 하나의 View태그로 묶어주면서, 가로정렬 등의 스타일을 수정하였습니다.

또한 각각의 텍스트가 두껍게 보이도록 bold 속성을 추가해주었습니다.


이렇게 하여 만들어진 스토리바를 확인해보면 다음과 같습니다.



블로그 이미지

Tigercow.Door

Web Programming / Back-end / Database / AI / Algorithm / DeepLearning / etc

댓글을 달아 주세요


안녕하세요.

해당 카테고리에서는 리액트 네이티브(React Native)를 이용한 모바일 어플리케이션 만들기에 대한 내용을 이야기해볼까 합니다.

과거에 약간 해보다가 다른 공부를 하느라 놓게 되었는데, 최근 모바일 어플리케이션을 개발해야 할 일이 생겨서 다시 공부하게 되었습니다.


무엇보다 리액트 네이티브는 iOS와 Android 어플을 동시개발할 수 있다는 점 때문에 유명하기도 하고, 인기가 좋기도 합니다.

facebook에서 개발하였고, 실제로 facebook iOS어플리케이션을 비롯해, 인스타그램, 에어비앤비, 우버 등이 리액트 네이티브를 이용해 어플리케이션을 제작한 것으로 알고 있습니다.


리액트 네이티브에 대한 자세한 점은 직접 구현해보면서 체험하는 걸로 내려놓고.. :)
이번 포스팅에서는 그 시작으로, 리액트 네이티브를 통한 어플리케이션 개발을 위해 기본적인 환경셋팅을 해보도록 하겠습니다.



1. Expo


기본적으로 우리는 Expo를 이용합니다.

뭐랄까, 엑스포는 리액트 네이티브를 기반으로 만들어진 플랫폼인데 우리가 리액트 네이티브로 어플리케이션을 개발하면서 테스팅 해볼때 iOS와 Android 시뮬레이터 모두를 지원해줍니다.

또한 실제로 핸드폰에서 단순히 QR코드를 인식시켜주면 우리가 개발하고 있는 어플리케이션을 테스트 해볼 수 있고, 로컬에서 코드를 수정하면 그것이 실시간으로 업데이트 되면서 반영됩니다.


저는 현재 맥OS를 사용중이기에 윈도우보다는 맥OS에 초점을 둘 것 같지만, 윈도우를 사용하시는 분들은 설치할 때 자신의 운영체제에만 잘 맞춰서 따라오시면 될 것 같습니다.



Expo xde


먼저 Expo xde를 아래사이트에서 다운받습니다.


https://docs.expo.io/versions/latest/introduction/installation


위의 사이트에 들어가서, 빨간색 밑줄친 부분을 확인하고 자신의 운영체제에 맞는 것을 다운받아서 Expo xde를 설치합니다.



Expo xde란 쉽게말해서, 그냥 우리가 Expo를 사용하게 해주는 툴? 정도로 생각하시면 됩니다.



설치받은 Expo xde를 실행시키고 expo에 가입해서 로그인하면 위와 같은 화면이 나옵니다.



2. Text aditor


두번째로 설치해야하는 것은 텍스트 에디터입니다.

VS code, atom, sublime 무엇이든 여러분이 좋아하고, 익숙한 것을 고르시면 될 것 같고 선택을 못하겠다 하시는 분들께서는 제가 앞으로 사용할 VS code를 설치해주시면 됩니다.


VS code는 아래 사이트에서 설치가 가능합니다.


https://code.visualstudio.com/



3. iOS simulator (선택 사항)


우리가 앞으로 어플을 개발하면, 중간중간 실제로 잘 동작하는지 눈으로 확인해봐야 하는데, 그럴때 사용하는 것이 simulator입니다.

꼭 simulator를 설치하지 않더라도 여러분이 갖고 계신 핸드폰에 Expo 어플리케이션을 설치하여 이후 QR코드를 인식시켜주면서 확인할 수도 있습니다.


그래도 컴퓨터로 바로바로 코드를 작성하면서 확인하는 것이 제 생각에는 편리하기 때문에 시뮬레이터 설치를 추천드립니다...만..

iOS 시뮬레이터는 윈도우 환경에서 설치 및 구동이 불가능 합니다.

맥을 이용하시는 분들께서는 Xcode를 최신버전으로 업그레이드 해주시고 아래 명령어를 터미널에 입력합니다.


sudo xcode-select -s /Applications/Xcode.app


그리고 xcode 를 실행시키면 무언가 설치해야 된다고 뜰텐데 그걸 설치해주시면 됩니다.



4. Android simulator (선택 사항)


하지만! 안드로이드 시뮬레이터는 맥, 윈도우 상관없이 설치하고 구동이 가능합니다. 다만 몇가지 설치해야할 것들이 있는데 천천히 설명드리도록 하겠습니다.


먼저 아래 사이트에서 안드로이드 스튜디오를 설치합니다.


https://developer.android.com/studio/index.html?hl=ko


설치파일을 실행하면 처음에, standard말고 custom으로 선택해주시고 이후에는 체크되어 있는 그대로 진행하시면 됩니다.


이후 설치가 완료되면 안드로이드 스튜디오를 실행하여 새로운 프로젝트를 만듭니다. 추가적으로 설정할 것은 없습니다.


이후 프로젝트가 생성되면 상단 메뉴들 중에서


Tools > AVD manager 를 들어갑니다.



그럼 위와 같은 화면이 뜰텐데 위와 같이 기본적으로 가상 기기가 있으신 분들은 그대로 두시면 되고, 없으신 분들은 좌측하단에서 새로운 디바이스를 추가해줘야 합니다.

이후 안드로이드 에뮬레이터를 사용할때는 위와 같은 창을 띄우고 기기의 오른쪽에 있는 재생버튼을 눌러서 에뮬레이터를 실행시키고 난 후에 사용하시면 됩니다.



블로그 이미지

Tigercow.Door

Web Programming / Back-end / Database / AI / Algorithm / DeepLearning / etc

댓글을 달아 주세요