В этой серии вы узнаете, как использовать React Native для создания макетов страниц, обычно используемых в мобильных приложениях. Макеты, которые вы будете создавать, не будут функциональными — вместо этого, основной целью этой серии является то, чтобы вы запачкали руки при размещении контента в ваших приложениях React Native.
Если вы новичок в разработке приложений React Native или стилей в целом, посмотрите мой предыдущий учебник:
Чтобы следовать этой серии, я призываю вас сначала попытаться воссоздать каждый экран самостоятельно, прежде чем вы прочитаете мои пошаговые инструкции в руководстве. Вы действительно не получите много пользы от этого урока, просто прочитав его! Попробуйте сначала, прежде чем искать ответы здесь. Если вам удалось сделать его похожим на исходный экран, сравните вашу реализацию с моей. Тогда решите для себя, какой из них лучше!
В этой первой части серии вы создадите следующую страницу входа в систему:

Страница входа в систему обычно используется в качестве начальной страницы для приложений, которые требуют, чтобы у пользователей была учетная запись.
Вот пара примеров этого типа макета в дикой природе:


Настройка проекта
Первым шагом, конечно же, является создание нового проекта React Native:
|
1
|
react-native init react-native-common-screens
|
После настройки проекта откройте файл index.android.js и замените код по умолчанию следующим index.android.js :
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
import React, { Component } from ‘react’;
import {
AppRegistry
} from ‘react-native’;
import Login from ‘./src/pages/Login’;
export default class ReactNativeCommonScreens extends Component {
render() {
return (
<Login />
);
}
}
AppRegistry.registerComponent(‘ReactNativeCommonScreens’, () => ReactNativeCommonScreens);
|
Создайте папку src/pages и создайте внутри нее файл Login.js .
Вам также понадобится пакет react-native-vector-icons . Это специально используется для отображения значка Facebook для кнопки входа в Facebook.
|
1
|
npm install —save react-native-vector-icons
|
Откройте файл android/app/build.gradle и добавьте ссылку на пакет:
|
1
2
3
4
|
dependencies {
//rest of the dependencies are here at the top
compile project(‘:react-native-vector-icons’) //add this
}
|
Сделайте то же самое с файлом android/settings.gradle , добавив следующее внизу:
|
1
2
|
include ‘:react-native-vector-icons’
project(‘:react-native-vector-icons’).projectDir = new File(rootProject.projectDir, ‘../node_modules/react-native-vector-icons/android’)
|
Откройте android/app/src/main/java/com/react-native-common-screens/MainApplication.java и импортируйте пакет:
|
1
2
3
4
|
import java.util.Arrays;
import java.util.List;
import com.oblador.vectoricons.VectorIconsPackage;
|
Наконец, инициализируйте пакет:
|
1
2
3
4
5
6
7
|
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new VectorIconsPackage() //add this
);
}
|
Создание страницы входа
Хорошо, теперь, когда вы попытались кодировать макет самостоятельно (без обмана, верно?), Я покажу вам, как я построил свою реализацию. Откройте файл src/pages/Login.js и импортируйте то, что вам нужно:
|
01
02
03
04
05
06
07
08
09
10
11
|
import React, { Component } from ‘react’;
import {
StyleSheet,
Text,
View,
TextInput,
ScrollView
} from ‘react-native’;
import Icon from ‘react-native-vector-icons/FontAwesome’;
|
Помимо стандартных компонентов React и react-native-vector-icons , вам также необходимо включить три пользовательских компонента:
|
1
2
3
|
import Container from ‘../components/Container’;
import Button from ‘../components/Button’;
import Label from ‘../components/Label’;
|
Первый — это Container ( src/components/Container.js ), работа которого заключается в добавлении нижнего поля к тому, что он переносит. Это звучит тривиально, и да, вы можете просто использовать View и добавлять одни и те же стили каждый раз, когда захотите его использовать. Преимущество этого предложения в том, что вам не нужно применять одни и те же стили к представлению несколько раз, и это также позволяет вам повторно использовать компонент каждый раз, когда вам нужно добавить нижнее поле к чему-либо.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import React, { Component } from ‘react’;
import {
StyleSheet,
View
} from ‘react-native’;
const Container = (props) => {
return (
<View style={styles.labelContainer}>
{ props.children }
</View>
);
}
const styles = StyleSheet.create({
labelContainer: {
marginBottom: 20
}
});
export default Container;
|
Компонент Button ( src/components/Button.js ), как следует из названия, используется для создания кнопок. Если он присутствует, то он выплевывает любой дочерний компонент, добавленный в него. В противном случае он выводит компонент Text который показывает текст внутри кнопки. Также добавлен стиль по умолчанию, но он не будет использоваться, если в noDefaultStyles присутствует noDefaultStyles . Уникальные стили кнопок, передаваемые из реквизита, также являются необязательными.
|
01
02
03
04
05
06
07
08
09
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
|
import React, { Component } from ‘react’;
import {
StyleSheet,
Text,
TouchableHighlight,
} from ‘react-native’;
const Button = (props) => {
function getContent(){
if(props.children){
return props.children;
}
return <Text style={props.styles.label}>{props.label}</Text>
}
return (
<TouchableHighlight
underlayColor=»#ccc»
onPress={props.onPress}
style={[
props.noDefaultStyles ?
props.styles ?
>
{ getContent() }
</TouchableHighlight>
);
}
const styles = StyleSheet.create({
button: {
alignItems: ‘center’,
justifyContent: ‘center’,
padding: 20
},
});
export default Button;
|
Наконец, есть компонент Label ( src/components/Label.js ), который в основном представляет собой просто Text компонент с некоторым предопределенным стилем.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
import React, { Component } from ‘react’;
import {
StyleSheet,
Text,
} from ‘react-native’;
const Label = (props) => {
return (
<Text
style={props.styles && props.styles.textLabel ?
>
{props.text}
</Text>
);
}
const styles = StyleSheet.create({
textLabel: {
fontSize: 20,
fontWeight: ‘bold’,
fontFamily: ‘Verdana’,
marginBottom: 10,
color: ‘#595856’
}
});
export default Label;
|
Теперь вы можете перейти к реальной странице входа. Внутри метода render() оберните все в компонент ScrollView . Это очень важно, если вы хотите, чтобы ваше приложение могло обслуживать любые размеры устройств и ориентацию экрана.
Чаще всего, независимо от того, насколько малой высоты, по вашему мнению, будет расходовать ваш контент, всегда будет устройство, которое не сможет отобразить его полностью. Таким образом возникает необходимость в полосах прокрутки для прокрутки контента.
|
1
2
3
4
5
6
7
8
9
|
export default class Login extends Component {
render() {
return (
<ScrollView style={styles.scroll}>
…
</ScrollView>
);
}
}
|
Далее инициализируем стили:
|
1
2
3
|
const styles = StyleSheet.create({
});
|
Примените следующие стили к ScrollView . flexDirection является необязательным, но хорошей практикой является его явное определение, чтобы будущие разработчики точно знали, как раскладывается основное содержимое приложения, просто взглянув на код.
|
1
2
3
4
5
|
scroll: {
backgroundColor: ‘#E1D7D8’,
padding: 30,
flexDirection: ‘column’
},
|
Если посмотреть на снимок экрана, сделанный ранее, первым элементом контента, который вы хотите добавить, является тот, что вверху, и это кнопка забытого пароля. Обратите внимание, что реквизиты onPress предоставляются, потому что underlayColor фактически не будет применен, если не будет предоставлена функция для нажатия кнопки.
|
1
2
3
4
5
6
|
<Container>
<Button
label=»Forgot Login/Pass»
styles={{button: styles.alignRight, label: styles.label}}
onPress={this.press.bind(this)} />
</Container>
|
Используемые для этого стили довольно alignSelf: 'flex-end' за исключением alignSelf: 'flex-end' . Это говорит React Native о расположении элемента в самом конце текущей строки. alignSelf является эквивалентом alignItems для определения выравнивания самого элемента, а не его дочерних элементов. Использование flex-end позволяет достичь эффекта, аналогичного эффекту float: right в CSS.
|
1
2
3
4
5
6
7
|
label: {
color: ‘#0d8898’,
fontSize: 20
},
alignRight: {
alignSelf: ‘flex-end’
},
|
Далее идут два текстовых поля вместе с их ярлыками.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
<Container>
<Label text=»Username or Email» />
<TextInput
style={styles.textInput}
/>
</Container>
<Container>
<Label text=»Password» />
<TextInput
secureTextEntry={true}
style={styles.textInput}
/>
</Container>
|
На данный момент страница должна выглядеть следующим образом:

Вот стиль для textInput :
|
1
2
3
4
5
|
textInput: {
height: 80,
fontSize: 30,
backgroundColor: ‘#FFF’
},
|
Теперь вы, возможно, начали замечать, почему компонент Container важен. Это позволяет вам инкапсулировать стили по умолчанию, чтобы не объявлять их заново в каждом файле. Это основной принцип React: вы всегда должны стремиться к повторному использованию компонентов каждый раз, когда видите возможность.
Кнопка входа в Facebook немного отличается от кнопок, которые вы создали ранее. На этот раз в нем есть контент, который отображает значок вместе с текстом. Они добавляются вместо label для дополнительной настройки содержимого кнопки.
|
01
02
03
04
05
06
07
08
09
10
11
12
|
<Container>
<Button
styles={{button: styles.transparentButton}}
onPress={this.press.bind(this)}
>
<View style={styles.inline}>
<Icon name=»facebook-official» size={30} color=»#3B5699″ />
<Text style={[styles.buttonBlueText, styles.buttonBigText]}> Connect </Text>
<Text style={styles.buttonBlueText}>with Facebook</Text>
</View>
</Button>
</Container>
|
Как только это будет добавлено, страница должна выглядеть следующим образом:

Добавьте стили для кнопки входа в Facebook:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
transparentButton: {
marginTop: 30,
borderColor: ‘#3B5699’,
borderWidth: 2
},
buttonBlueText: {
fontSize: 20,
color: ‘#3B5699’
},
buttonBigText: {
fontSize: 20,
fontWeight: ‘bold’
},
inline: {
flexDirection: ‘row’
},
|
Здесь действительно ничего не стоит отметить, за исключением styles.inline , который используется в качестве вспомогательного класса для горизонтального размещения всех элементов внутри него. Это дает эффект, аналогичный использованию <span> в HTML для переноса текста, который вы хотите отобразить встроенным. В CSS это может быть достигнуто с помощью display: inline или display: inline-block .

Последние элементы на этом экране — кнопки « Вход» и « Отмена» . Им нужно больше места над ними, чем над другими элементами, поэтому лучше обернуть их в контейнер ( footer ) и применить к нему marginTop . Это имеет больше смысла, чем объявление нового стиля только для этих кнопок.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<View style={styles.footer}>
<Container>
<Button
label=»Sign In»
styles={{button: styles.primaryButton, label: styles.buttonWhiteText}}
onPress={this.press.bind(this)} />
</Container>
<Container>
<Button
label=»CANCEL»
styles={{label: styles.buttonBlackText}}
onPress={this.press.bind(this)} />
</Container>
</View>
|

Наконец, добавьте стиль для кнопок Вход и Отмена :
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
buttonWhiteText: {
fontSize: 20,
color: ‘#FFF’,
},
buttonBlackText: {
fontSize: 20,
color: ‘#595856’
},
primaryButton: {
backgroundColor: ‘#34A853’
},
footer: {
marginTop: 100
}
|

Наконец, не забудьте определить код, который будет выполняться при нажатии любой из кнопок!
|
1
2
3
|
press() {
//execute any code here
}
|
Вывод
Это оно! В этом руководстве вы успешно создали страницу входа, используя свои знания Flexbox. Кроме того, вы также узнали, как использовать стороннюю библиотеку React Native Vector Icons, чтобы легко добавлять значки в ваше приложение. Как мое решение сравнилось с вашим? Дайте нам знать в дискуссионном форуме ниже.
В следующем уроке из этой серии вы узнаете, как создать экран календаря. А пока ознакомьтесь с другими нашими учебниками по React Native и Flexbox.





