Advertisement
  1. Code
  2. React Native

Common Reagieren Sie auf native App-Layouts: Kalenderseite

Scroll to top
Read Time: 13 min
This post is part of a series called Common React Native App Layouts.
Common React Native App Layouts: Gallery Page

() translation by (you can also view the original English article)

In dieser Serie erfahren Sie, wie Sie mithilfe von React Native Seitenlayouts erstellen können, die häufig in mobilen Apps verwendet werden.  Die Layouts, die Sie erstellen, sind nicht funktional. Stattdessen liegt das Hauptaugenmerk dieser Serie darauf, Ihre Hände schmutzig zu machen, indem Sie Inhalte in Ihren React Native-Apps aufstellen.

Wenn Sie neu mit dem Native React Native-Apps oder dem Styling im Allgemeinen arbeiten, lesen Sie sich mein vorheriges Tutorial durch:

Um dieser Serie zu folgen, fordere ich Sie auf, zuerst jeden Bildschirm einzeln zu erstellen, bevor Sie meine Schritt-für-Schritt-Anleitung im Tutorial lesen.  Sie werden nicht viel von diesem Tutorial profitieren, wenn Sie es lesen!  Versuchen Sie es zuerst, bevor Sie die Antworten hier nachschlagen.  Wenn es Ihnen gelingt, den ursprünglichen Bildschirm so aussehen zu lassen, vergleichen Sie Ihre Implementierung mit meiner.  Entscheide dann selbst, welches besser ist!

In diesem zweiten Teil der Serie erstellen Sie die folgende Kalenderseite:

calendar pagecalendar pagecalendar page

Kalender-Apps werden verwendet, um Ereignisse und Termine zu verfolgen, die vom Benutzer hinzugefügt wurden.  Sie werden verschiedene Variationen in der freien Wildbahn finden, aber die meisten von ihnen werden dieselben Elemente haben wie ein physischer Kalender: der aktuelle Monat und das Jahr, die Tage im Monat und die vom Benutzer hinzugefügten Ereignisse oder Termine.

Hier sind ein paar Beispiele für diese Art von Layout:

google calendargoogle calendargoogle calendar
android calendarandroid calendarandroid calendar

Projektaufbau

Der erste Schritt besteht natürlich darin, ein neues React-Native-Projekt einzurichten:

1
react-native init react-native-common-screens

Sobald das Projekt eingerichtet ist, öffnen Sie die Datei index.android.js und ersetzen Sie den Standardcode durch Folgendes:

1
import React, { Component } from 'react';
2
import {
3
  AppRegistry
4
} from 'react-native';
5
6
import Calendar from './src/pages/Calendar';
7
8
export default class ReactNativeCommonScreens extends Component {
9
10
  render() {
11
    return (
12
      <Calendar />
13
    );
14
  }
15
16
}
17
18
AppRegistry.registerComponent('ReactNativeCommonScreens', () => ReactNativeCommonScreens);

Erstellen Sie einen Ordner src/pages und erstellen Sie darin eine Datei Calendar.js.

Sie benötigen auch das Paket reactive-native-vector-icons. Dies wird speziell für die Navigationssymbole sowie andere Symbole verwendet, die auf der Seite benötigt werden.

1
npm install --save react-native-vector-icons

Öffnen Sie die Datei android/app/build.gradle und fügen Sie einen Verweis auf das Paket hinzu:

1
dependencies {
2
    //rest of the dependencies are here at the top
3
    compile project(':react-native-vector-icons') //add this
4
}

Machen Sie dasselbe mit der android/settings.gradle-Datei, indem Sie unten Folgendes hinzufügen:

1
include ':react-native-vector-icons'
2
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')

Öffnen Sie android/app/src/main/java/com/react-native-common-screens/MainApplication.java und importieren Sie das Paket:

1
import java.util.Arrays;
2
import java.util.List;
3
4
import com.oblador.vectoricons.VectorIconsPackage; //add this

Zuletzt initialisieren Sie das Paket:

1
@Override
2
protected List<ReactPackage> getPackages() {
3
  return Arrays.<ReactPackage>asList(
4
      new MainReactPackage(),
5
      new VectorIconsPackage() //add this

6
  );
7
}

Erstellen der Kalenderseite

Okay, jetzt, wo du versucht hast, das Layout selbst zu programmieren (kein Betrug, richtig?), Zeige ich dir, wie ich meine Implementierung erstellt habe.

Zuerst dachte ich, dies wäre die schwierigste zu implementieren, aber vertrau mir, es ist wirklich nicht so kompliziert, solange du die Grundlagen bereits kennst.  Es gibt hier einige Möglichkeiten, JavaScript-Code zum Rendern zu verwenden.

Fangen Sie mit allen Komponenten und Paketen an, die Sie benötigen:

1
import React, { Component } from 'react';
2
3
import {
4
  StyleSheet,
5
  Text,
6
  View,
7
  ScrollView
8
} from 'react-native';
9
10
import Icon from 'react-native-vector-icons/FontAwesome';
11
import { range } from 'lodash';
12
import Button from '../components/Button';

Dieses Mal gibt es ein neues Paket, das Sie noch nicht installiert haben, und das ist lodash.  Sie brauchen nicht wirklich die ganze Bibliothek, nur die range funktion.  Dies wird verwendet, um ein Zahlenfeld basierend auf einem bestimmten Bereich zu erzeugen.  Sie können nur diese Funktion installieren, indem Sie npm install --save lodash.range auf Ihrem Terminal ausführen.

Fügen Sie den Standardcode für das Erstellen von Seiten hinzu:

1
export default class Calendar extends Component {
2
    render() {
3
      return (
4
			<ScrollView style={styles.container}>
5
			    ...
6
			</ScrollView>

7
		);
8
	}
9
}
10
11
const styles = StyleSheet.create({
12
	container: {
13
		flex: 1
14
	}
15
});

Die Kopfzeile enthält drei Elemente: die Schaltfläche, um zur vorherigen Seite zurückzukehren, den Titel der aktuellen Seite und den Text, der eine benutzerfreundliche Darstellung des aktuell ausgewählten Datums anzeigt.

1
<View style={styles.header}>
2
    <Button 
3
		noDefaultStyles={true}
4
		onPress={this.press.bind(this)} 
5
		styles={{button: styles.header_item}}
6
	>
7
        <View style={styles.header_button}>
8
        	<Icon name="chevron-left" size={30} color="#FFF" />
9
        	<Text style={[styles.header_text]}> Menu</Text>

10
        </View>

11
    </Button>

12
    <View style={styles.header_item}>
13
    	<Text style={[styles.header_text, styles.text_center, styles.bold_text]}>Calendar</Text>

14
    </View>

15
	<View style={styles.header_item}>
16
    	<Text style={[styles.header_text, styles.text_right]}>Today</Text>

17
    </View>

18
</View>
calendar page initial lookcalendar page initial lookcalendar page initial look

header hat eine flexDirection der row, so dass jedes header_item horizontal gestapelt ist.  Jedem von ihnen wird derselbe flex-Wert zugewiesen, so dass sie den gleichen Raum einnehmen.  text_center und text_right werden verwendet, um den Text innerhalb dieser header_items an der Mitte und rechts auszurichten.  Dies geschieht, weil sie standardmäßig auf der linken Seite ihres Containers ausgerichtet sind.

1
header: {
2
    backgroundColor: '#329BCB',
3
	flexDirection: 'row',
4
	padding: 20
5
},
6
header_item: {
7
	flex: 1
8
},
9
header_button: {
10
	flexDirection: 'row'
11
},
12
text_center: {
13
	textAlign: 'center'
14
},
15
text_right: {
16
	textAlign: 'right'
17
},
18
header_text: {
19
	color: '#fff',
20
	fontSize: 20
21
},
22
bold_text: {
23
	fontWeight: 'bold'
24
},

Sobald die Stile hinzugefügt wurden, sollte es nun so aussehen:

calendar page styled headercalendar page styled headercalendar page styled header

Als nächstes folgt der eigentliche Kalender, der in drei Teile unterteilt ist: die Kopfzeile, die Wochentage und die Kalendertage:

1
<View>
2
    <View style={styles.calendar_header}>
3
        ...
4
    </View>

5
    <View style={styles.calendar_weekdays}>
6
        ...
7
    </View>

8
    <View style={styles.calendar_days}>
9
        ...
10
    </View>

11
</View>

Der Kalenderkopf ermöglicht dem Benutzer, Jahr und Monat zu ändern.

Es gibt mindestens zwei Möglichkeiten, dies zu implementieren.  Die erste Methode besteht darin, jedes Element als ein einzelnes Element zu behandeln und justifyContent: 'space-between' auf seinen Container anzuwenden.  Die zweite Methode besteht darin, alle Elemente, die mit dem Jahr zu tun haben, zu gruppieren und diejenigen zu gruppieren, die mit dem Monat zu tun haben.

Die zweite Methode ist die, die unten angewendet wird.  Semantisch gesehen ist dies viel sinnvoller, da die Schaltfläche für die Jahresrückverfolgung, das Jahr selbst und die Schaltfläche für die Navigation alle miteinander verknüpft sind, sodass Sie sie als eine einzige Sache behandeln können, indem Sie sie in denselben Container einfügen.  Das Gleiche gilt für die Monatskontrollen.

1
<View style={styles.calendar_header}>
2
    <View style={styles.calendar_header_item}>
3
        <Button 
4
    		noDefaultStyles={true}
5
    		onPress={this.press.bind(this)}
6
    	>
7
            <Icon name="chevron-left" size={18} color="#333" />
8
        </Button>

9
    	<Text style={styles.calendar_header_text}>2013</Text>

10
    	<Button 
11
    		noDefaultStyles={true}
12
    		onPress={this.press.bind(this)}
13
    	>
14
            <Icon name="chevron-right" size={18} color="#333" />
15
        </Button>

16
    </View>

17
    
18
    <View style={styles.calendar_header_item}>
19
    	<Button 
20
    		noDefaultStyles={true}
21
    		onPress={this.press.bind(this)}
22
    	>
23
            <Icon name="chevron-left" size={18} color="#333" />
24
        </Button>

25
    	<Text style={styles.calendar_header_text}>November</Text>

26
    	<Button 
27
    		noDefaultStyles={true}
28
    		onPress={this.press.bind(this)}
29
    	>
30
            <Icon name="chevron-right" size={18} color="#333" />
31
        </Button>

32
    </View>

33
</View>
calendar page added calendar headercalendar page added calendar headercalendar page added calendar header

Von dort aus können Sie dieselbe Technik auf diese beiden Gruppen von Komponenten in derselben Zeile anwenden.  Um Leerzeichen zwischen den beiden Schaltflächen (zurück und vorwärts) und dem Label hinzuzufügen, verwenden wir justifyContent: 'space-between'.  Wir verwenden alignItems: 'center', um alle Elemente in das Zentrum zu verschieben.  Schließlich fügen wir linkes und rechtes Padding hinzu, um mehr Platz zwischen den zwei Gruppen hinzuzufügen.

1
calendar_header: {
2
    flexDirection: 'row'
3
},
4
calendar_header_item: {
5
	flex: 1,
6
	flexDirection: 'row',
7
	justifyContent: 'space-between',
8
	alignItems: 'center',
9
	paddingTop: 20,
10
	paddingRight: 40,
11
	paddingLeft: 40
12
},
13
calendar_header_text: {
14
	fontWeight: 'bold',
15
	fontSize: 20
16
},
calendar page added calendar header stylescalendar page added calendar header stylescalendar page added calendar header styles

Als nächstes sind die Wochentage.  Wir verwenden eine Funktion, um diese zu rendern, da es am besten ist, einige JavaScript-Code zu verwenden, um alle Elemente zu rendern. 

1
<View style={styles.calendar_weekdays}>
2
    { this.renderWeekDays() }
3
</View>

Anstatt also sieben View- oder Text-Komponenten an jedem Wochentag zu rendern, können Sie einfach ein Array mit den Wochentagen erstellen.  Sie können dann mithilfe der Funktion Array.map() diese Tage durchlaufen.  Rendern Sie für jede Iteration eine Text komponente, die den Tag anzeigt.

1
renderWeekDays() {
2
    let weekdays = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
3
	return weekdays.map((day) => {
4
		return (
5
			<Text key={day} style={styles.calendar_weekdays_text}>{day.toUpperCase()}</Text>

6
		);
7
	});
8
}

Beachten Sie, dass im obigen Code die Funktion toUpperCase() verwendet wird, um alle Buchstaben eines jeden Tages in Großbuchstaben umzuwandeln.  React Native ist nicht mit der CSS-Eigenschaft text-transform versehen. Dies ist die einzige Möglichkeit, um Großbuchstaben zu erhalten, abgesehen von der manuellen Verwendung von Großbuchstaben.

calendar page added calendar week dayscalendar page added calendar week dayscalendar page added calendar week days

Hier ist das Styling für den Kalenderkopf:

1
calendar_weekdays_text: {
2
    flex: 1,
3
	color: '#C0C0C0',
4
	textAlign: 'center'
5
},
calendar page styled calendar week dayscalendar page styled calendar week dayscalendar page styled calendar week days

Die Kalendertage verwenden auch eine Funktion zum Rendern der Tage:

1
<View style={styles.calendar_days}>
2
    { this.renderWeeks() }
3
</View>

Die renderWeeks() - Funktion verwendet die Funktion range() in lodash, um ein Array zu generieren, das die Tage des letzten Monats und die Tage des aktuellen Monats enthält. Diese beiden Arrays werden dann zusammengeführt.

Sie können das resultierende Array jedoch nicht direkt als Datenquelle für die Kalendertage verwenden.  Das liegt daran, dass, wenn Sie einfach die Elemente durchlaufen und eine Textkomponente für jeden Tag ausgeben, es keine Unterscheidung zwischen jeder Woche gibt.  Sie wissen bereits, dass Sie, um jeden Kalendertag inline zu machen, flexDirection: 'row' auf seinen Container anwenden müssen.  Wenn Sie es auf einen einzelnen Container anwenden, werden alle Kalendertage in einer einzigen Zeile angeordnet.

Das bedeutet, dass Sie für jede Woche einen separaten Container benötigen.  Die Frage ist wie.  Auch hier gibt es mindestens zwei Möglichkeiten.

Die erste Methode besteht darin, einen Variablenspeicher zu haben, der angibt, wie viele Tage aktuell ausgegeben werden, und dann eine bedingte Anweisung hinzuzufügen, die jedes Mal, wenn sie 7 ist, ein öffnendes <View> rendert, sobald es 7 ist die Variable 0 enthält, und ein schließendes </View>, setze es auf 0 zurück. Dies ist die einfachste Methode.

Aber ich werde hier eine andere Methode verwenden.  Im Folgenden wird die Funktion getWeeksArray() verwendet, um sie zu implementieren.  Diese Funktion akzeptiert das Array von Tagen und gruppiert sie in Arrays mit jeweils sieben Tagen.  Von dort aus können Sie jedes dieser Arrays durchlaufen, um den Wochencontainer zu rendern.  Wiederholen Sie dann für jede Iteration erneut die Tage innerhalb der Woche, um die Tage zu rendern.  Dies ist, was die renderDays() Funktion tut.

1
renderWeeks() {
2
    let past_month_days = range(27, 31);
3
	let this_month_days = range(1, 30);
4
5
	let days = past_month_days.concat(past_month_days, this_month_days);
6
	let grouped_days = this.getWeeksArray(days);
7
8
	return grouped_days.map((week_days, index) => {
9
		return (
10
			<View key={index} style={styles.week_days}>
11
				{ this.renderDays(week_days) }				
12
			</View>

13
		);
14
	});
15
}

Hier ist die Funktion getWeeksArray():

1
getWeeksArray(days) {
2
    var weeks_r = [];
3
	var seven_days = [];
4
	var count = 0;
5
	days.forEach((day) => {
6
	  count += 1;
7
	  seven_days.push(day);
8
	  if(count == 7){
9
	    weeks_r.push(seven_days)
10
	    count = 0;
11
	    seven_days = [];
12
	  }
13
	});
14
	return weeks_r;
15
}

Und hier ist die renderDays() -Funktion:

1
renderDays(week_days) {
2
    return week_days.map((day, index) => {
3
		return (
4
			<Button 
5
				label={day}
6
				key={index} 
7
				onPress={this.press.bind(this)} 
8
				styles={{button: styles.day, label: styles.day_text}}
9
				noDefaultStyles={true}
10
			/>	

11
		);
12
	});
13
}
calendar page added calendar dayscalendar page added calendar dayscalendar page added calendar days

Fügen Sie das Styling für jede Woche (week_days) und jeden Tag (day und day_text) hinzu:

1
week_days: {
2
    flexDirection: 'row'
3
},
4
day: {
5
	flex: 1,
6
	backgroundColor: '#F5F5F5',
7
	padding: 17,
8
	margin: 2
9
},
10
day_text: {
11
	textAlign: 'center',
12
	color: '#A9A9A9',
13
	fontSize: 25
14
},
calendar page add calendar days stylingcalendar page add calendar days stylingcalendar page add calendar days styling

Weiter ist die Notiz, die vom Benutzer für den aktuell ausgewählten Tag und das ausgewählte Datum und die Uhrzeit hinzugefügt wurde.  Auch hier ist es besser, Elemente nach ihrem Zweck zu gruppieren, anstatt sie auf der Seite zu platzieren.  Sicherlich sind alle diese Elemente verwandt, also werden wir sie in denselben Container legen.  Bei näherem Hinsehen werden Sie jedoch feststellen, dass Sie sie weiter gruppieren können: die eigentliche Notiz und das ausgewählte Datum.  In diesem Sinne, hier ist das Markup, mit dem Sie enden werden:

1
<View style={styles.notes}>
2
    <View style={styles.notes_notes}>
3
		<Text style={styles.notes_text}>Riding my bike around the neighborhood.</Text>

4
	</View>

5
	<View style={[styles.notes_selected_date]}>
6
		<Text style={styles.small_text}>8:23 PM</Text>

7
		<Text style={styles.big_text}>14</Text>

8
		<View style={styles.inline}>
9
			<Icon name="bicycle" size={20} color="#CCC" />
10
			<Text style={styles.small_text}> THURSDAY</Text>

11
		</View>

12
	</View>

13
</View>
calendar page add notescalendar page add notescalendar page add notes

Das ausgewählte Datum nimmt weniger Platz in Anspruch als die Note, daher müssen Sie den Noten einen größeren flex-Wert zuweisen.  In diesem Fall werden flex: 3 und flex: 1 verwendet, was bedeutet, dass die Noten 3/4 des verfügbaren Speicherplatzes verbrauchen und das ausgewählte Datum 1/4 verbraucht.  Sie können auch Dezimalzahlen (0,75 und 0,25) verwenden, wenn dies für Sie sinnvoller ist.  Wichtig ist, einen Standard zu wählen und dabei zu bleiben. alignItems: 'flex-end' wird für notes_selected_date verwendet, sodass alle untergeordneten Elemente nach rechts ausgerichtet sind. Dies ist erforderlich, da sie standardmäßig nach links ausgerichtet sind.

1
notes: {
2
    marginTop: 10,
3
	padding: 20,
4
	borderColor: '#F5F5F5',
5
	borderTopWidth: 1,
6
	borderBottomWidth: 1,
7
	flexDirection: 'row',
8
	backgroundColor: '#FAFAFA'
9
},
10
notes_notes: {
11
	flex: 3
12
},
13
notes_text: {
14
	fontSize: 18
15
},
16
notes_selected_date: {
17
	flex: 1,
18
	alignItems: 'flex-end',
19
	flexDirection: 'column'
20
},
21
small_text: {
22
	fontSize: 15
23
},
24
big_text: {
25
	fontSize: 50,
26
	fontWeight: 'bold'
27
},
28
inline: {
29
	flexDirection: 'row'
30
},
calendar page added styling to logscalendar page added styling to logscalendar page added styling to logs

Zu guter Letzt fügen wir die Logs hinzu, die denen im vorherigen Tutorial sehr ähnlich sind, also überlasse ich es Ihnen, herauszufinden, wie das Layout erreicht wird!

1
<View style={styles.logs}>
2
    <View>
3
		<Text style={styles.log_text}>Create New Entry</Text>

4
		<Text style={styles.log_subtext}>On Thursday, November 14</Text>

5
	</View>

6
	<Button 
7
		noDefaultStyles={true}
8
		onPress={this.press.bind(this)}
9
	>
10
		<Icon name="chevron-right" size={30} color="#CCC" />
11
	</Button>

12
</View>

Hier sind die Stile:

1
logs: {
2
    flexDirection: 'row',
3
	justifyContent: 'space-between',
4
	alignItems: 'center',
5
	padding: 20,
6
	borderColor: '#F5F5F5',
7
	borderBottomWidth: 1
8
},
9
log_text: {
10
	fontSize: 25
11
},
12
log_subtext: {
13
	fontSize: 18
14
}

Fazit

Das ist es!  In diesem Tutorial haben Sie eine Kalenderseite erstellt.  Wir haben ein schönes Kalenderlayout für eine App erstellt und Ihnen gezeigt, wie JavaScript-Code verwendet werden kann, um einige Einschränkungen von Flexbox auszugleichen.

Wie Sie gesehen haben, brauchten wir einen Weg, um die Anzahl der Tage hintereinander auf nur sieben Tage zu begrenzen.  Flexbox hat keine Möglichkeit, dies zu spezifizieren. Daher haben wir JavaScript verwendet, um das ursprüngliche Array von Tagen so zu rekonstruieren, dass sie in Gruppen von jeweils sieben Tagen unterteilt sind.  Von dort mussten wir nur noch jede Gruppe innerhalb einer View umbrechen und dann flexDirection flexDirection: 'row', um jede von ihnen in einer eigenen Zeile rendern zu lassen.

In einem nächsten Tutorial erfahren Sie, wie Sie das Layout implementieren, das häufig in Galerieseiten verwendet wird.  In der Zwischenzeit können Sie einige unserer anderen Tutorials zu React Native und Flexbox lesen.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.