Kurs React Native · Moduł 2: Listy i style

StyleSheet - zaawansowane stylowanie

4 min czytania ·
W tej lekcji4

StyleSheet to podstawa stylowania w React Native. Poznajmy zaawansowane techniki!

Tworzenie stylów

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

export default function StyleExample() {
  return (
    <View style={styles.container}>
      {/* Pojedynczy styl */}
      <Text style={styles.title}>Tytuł</Text>

      {/* Łączenie stylów (array) */}
      <Text style={[styles.text, styles.bold]}>Pogrubiony tekst</Text>

      {/* Style warunkowe */}
      <Text style={[styles.text, isActive && styles.active]}>
        Warunkowy styl
      </Text>

      {/* Inline + StyleSheet */}
      <Text style={[styles.text, { color: 'red' }]}>
        Inline override
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
  },
  text: {
    fontSize: 16,
  },
  bold: {
    fontWeight: 'bold',
  },
  active: {
    color: '#3498db',
  },
});

Flexbox w React Native

Flexbox działa podobnie jak w CSS, ale z kilkoma różnicami:

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

export default function FlexboxExample() {
  return (
    <View style={styles.container}>
      {/* Flex direction - domyślnie column! */}
      <View style={styles.column}>
        <View style={styles.box1} />
        <View style={styles.box2} />
        <View style={styles.box3} />
      </View>

      {/* Row direction */}
      <View style={styles.row}>
        <View style={styles.box1} />
        <View style={styles.box2} />
        <View style={styles.box3} />
      </View>

      {/* Flex grow */}
      <View style={styles.row}>
        <View style={[styles.box1, { flex: 1 }]} />
        <View style={[styles.box2, { flex: 2 }]} />
        <View style={[styles.box3, { flex: 1 }]} />
      </View>

      {/* Justify & Align */}
      <View style={styles.centered}>
        <Text style={styles.text}>Wycentrowany</Text>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    gap: 20,
    backgroundColor: '#1a5276',
  },
  column: {
    flexDirection: 'column', // Domyślne w RN
    gap: 10,
  },
  row: {
    flexDirection: 'row',
    gap: 10,
  },
  centered: {
    flex: 1,
    justifyContent: 'center', // Oś główna
    alignItems: 'center',      // Oś poprzeczna
    backgroundColor: '#2c3e50',
    borderRadius: 12,
  },
  box1: {
    width: 60,
    height: 60,
    backgroundColor: '#e74c3c',
    borderRadius: 8,
  },
  box2: {
    width: 60,
    height: 60,
    backgroundColor: '#2ecc71',
    borderRadius: 8,
  },
  box3: {
    width: 60,
    height: 60,
    backgroundColor: '#3498db',
    borderRadius: 8,
  },
  text: {
    color: '#fff',
    fontSize: 18,
  },
});

Position: absolute

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

export default function PositionExample() {
  return (
    <View style={styles.container}>
      <View style={styles.card}>
        <Text style={styles.cardTitle}>Karta skarbu</Text>

        {/* Badge w prawym górnym rogu */}
        <View style={styles.badge}>
          <Text style={styles.badgeText}>NOWY</Text>
        </View>

        {/* Ikona w lewym dolnym rogu */}
        <View style={styles.icon}>
          <Text>◆</Text>
        </View>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#1a5276',
  },
  card: {
    width: 250,
    height: 150,
    backgroundColor: '#2c3e50',
    borderRadius: 16,
    padding: 20,
    // Parent musi mieć position dla absolute children
  },
  cardTitle: {
    fontSize: 20,
    fontWeight: 'bold',
    color: '#fff',
  },
  badge: {
    position: 'absolute',
    top: -10,
    right: -10,
    backgroundColor: '#e74c3c',
    paddingHorizontal: 10,
    paddingVertical: 4,
    borderRadius: 12,
  },
  badgeText: {
    color: '#fff',
    fontSize: 12,
    fontWeight: 'bold',
  },
  icon: {
    position: 'absolute',
    bottom: 10,
    left: 10,
    width: 40,
    height: 40,
    backgroundColor: '#f39c12',
    borderRadius: 20,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

Cienie (Shadow)

import { View, Text, StyleSheet, Platform } from 'react-native';

export default function ShadowExample() {
  return (
    <View style={styles.container}>
      {/* iOS shadow */}
      <View style={styles.cardIOS}>
        <Text style={styles.text}>iOS Shadow</Text>
      </View>

      {/* Android shadow (elevation) */}
      <View style={styles.cardAndroid}>
        <Text style={styles.text}>Android Elevation</Text>
      </View>

      {/* Cross-platform shadow */}
      <View style={styles.cardCrossplatform}>
        <Text style={styles.text}>Cross-platform</Text>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 30,
    backgroundColor: '#ecf0f1',
  },
  cardIOS: {
    width: 200,
    padding: 20,
    backgroundColor: '#fff',
    borderRadius: 12,
    // iOS only
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 4 },
    shadowOpacity: 0.3,
    shadowRadius: 8,
  },
  cardAndroid: {
    width: 200,
    padding: 20,
    backgroundColor: '#fff',
    borderRadius: 12,
    // Android only
    elevation: 8,
  },
  cardCrossplatform: {
    width: 200,
    padding: 20,
    backgroundColor: '#fff',
    borderRadius: 12,
    // Oba platformy
    ...Platform.select({
      ios: {
        shadowColor: '#000',
        shadowOffset: { width: 0, height: 4 },
        shadowOpacity: 0.3,
        shadowRadius: 8,
      },
      android: {
        elevation: 8,
      },
    }),
  },
  text: {
    textAlign: 'center',
    fontSize: 16,
  },
});
Kod do tej lekcji: App.tsx
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <View style={styles.card}>
        <Text style={styles.emoji}>{'><>'}</Text>
        <Text style={styles.name}>Rybka koralowa</Text>
        <Text style={styles.description}>Mieszkanka raf Atlantydy</Text>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#aed6f1',
  },
  card: {
    width: 220,
    padding: 20,
    backgroundColor: '#fff',
    alignItems: 'center',
    // TODO: dodaj borderRadius: 16, aby zaokrąglić rogi karty
    // TODO: dodaj cień iOS:
    //   shadowColor: '#000',
    //   shadowOffset: { width: 0, height: 4 },
    //   shadowOpacity: 0.25,
    //   shadowRadius: 8,
    // TODO: dodaj cień Android: elevation: 8,
  },
  emoji: {
    fontSize: 48,
    marginBottom: 8,
  },
  name: {
    fontSize: 18,
    fontWeight: '600',
    color: '#2c3e50',
  },
  description: {
    fontSize: 14,
    color: '#7f8c8d',
    marginTop: 4,
  },
});

Hasła z dokumentacji w tej lekcji

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Która wartość justifyContent rozmieszcza elementy równomiernie z równymi odstępami między nimi?

  2. 2. Co robi position: 'absolute' w React Native?

Zadania praktyczne w grze

  • Układanie w pionie

    Uporządkuj wartości justifyContent od najmniejszego do największego odstępu na końcach:

  • Klikanie w kolejności

    Kliknij właściwości cienia w odpowiedniej kolejności (iOS):

  • Edytor kodu

    Uzupełnij style dla karty z efektem cienia.

Przydatne artykuły