Skip to content

RN Lezione 6: Flexbox, Card e Layout avanzati

  • Dominare Flexbox per layout professionali
  • Creare card, griglie, layout a colonne
  • Usare flexWrap per layout responsivi

In React Native tutti i View hanno display: flex di default.

┌─────────────────────────────┐
│ flex: 1 │ ← Occupa 1/3
├─────────────────────────────┤
│ flex: 2 │ ← Occupa 2/3
└─────────────────────────────┘
<View style={{ flex: 1, backgroundColor: 'red' }} />
<View style={{ flex: 2, backgroundColor: 'blue' }} />
// ↑ rosso = 1/3, blu = 2/3 dello spazio

Regola: flex = “quanto spazio prendo rispetto agli altri”


flexDirection: 'column' // Verticale (DEFAULT)
flexDirection: 'row' // Orizzontale
flexDirection: 'column-reverse'
flexDirection: 'row-reverse'
// Riga orizzontale
<View style={{ flexDirection: 'row' }}>
<Text>Uno</Text>
<Text>Due</Text>
<Text>Tre</Text>
</View>
// Output: UnoDueTre (in orizzontale)

justifyContent — allineamento sull’asse principale

Section titled “justifyContent — allineamento sull’asse principale”
flex-start (default) [elemento1][elemento2] │
center ──────[elemento1][elemento2]────── │
flex-end ────────────[elemento1][elemento2] │
space-between [elemento1]───────[elemento2] │
space-around ──[elemento1]───[elemento2]── │
space-evenly ───[elemento1]───[elemento2]─── │

alignItems — allineamento sull’asse secondario

Section titled “alignItems — allineamento sull’asse secondario”
stretch (default) [───────] ← si stira
[───────]
center [───]
[───] ← centrato
flex-start [───] ← in alto
[───]
flex-end [───] ← in basso
[───]

<View style={{ flex: 1, flexDirection: 'row' }}>
<View style={{ flex: 1, backgroundColor: 'red' }} />
<View style={{ flex: 2, backgroundColor: 'green' }} />
<View style={{ flex: 1, backgroundColor: 'blue' }} />
</View>
┌──────┬──────────────────────┬──────┐
│ red │ green │ blue │
│ 1/4 │ 2/4 │ 1/4 │
└──────┴──────────────────────┴──────┘

<View style={{
flexDirection: 'row',
flexWrap: 'wrap', // ← va a capo
justifyContent: 'space-between',
padding: 10,
}}>
<View style={{ width: '48%', height: 100, backgroundColor: 'red' }} />
<View style={{ width: '48%', height: 100, backgroundColor: 'green' }} />
<View style={{ width: '48%', height: 100, backgroundColor: 'blue' }} />
<View style={{ width: '48%', height: 100, backgroundColor: 'orange' }} />
</View>
┌────────┐ ┌────────┐
│ red │ │ green │
└────────┘ └────────┘
┌────────┐ ┌────────┐
│ blue │ │ orange │
└────────┘ └────────┘

4. Pattern: card prodotto con flexDirection row

Section titled “4. Pattern: card prodotto con flexDirection row”
const CardProdotto = ({ nome, prezzo, immagine }) => (
<View style={styles.card}>
<Image source={{ uri: immagine }} style={styles.img} />
<View style={styles.info}>
<Text style={styles.nome}>{nome}</Text>
<Text style={styles.prezzo}>{prezzo.toFixed(2)}</Text>
<TouchableOpacity style={styles.bottone}>
<Text style={styles.bottoneTesto}>Aggiungi</Text>
</TouchableOpacity>
</View>
</View>
);
const styles = StyleSheet.create({
card: {
flexDirection: 'row', // ← orizzontale
backgroundColor: 'white',
borderRadius: 12,
padding: 10,
marginBottom: 10,
elevation: 2,
},
img: {
width: 80,
height: 80,
borderRadius: 8,
marginRight: 12,
},
info: {
flex: 1, // ← occupa spazio rimanente
justifyContent: 'center',
},
nome: {
fontSize: 16,
fontWeight: 'bold',
},
prezzo: {
fontSize: 18,
color: '#2ecc71',
fontWeight: 'bold',
marginVertical: 5,
},
bottone: {
backgroundColor: '#3498db',
paddingHorizontal: 15,
paddingVertical: 8,
borderRadius: 8,
alignSelf: 'flex-start', // ← non si allarga
},
bottoneTesto: {
color: 'white',
fontWeight: '600',
},
});

┌────────────────────────┐
│ Header │ ← flex: 0 (contenuto)
├────────────────────────┤
│ │
│ Content │ ← flex: 1 (si espande)
│ │
├────────────────────────┤
│ Footer │ ← flex: 0
└────────────────────────┘
export default function App() {
return (
<View style={{ flex: 1 }}>
{/* Header */}
<View style={styles.header}>
<Text style={styles.titolo}>La mia App</Text>
</View>
{/* Content (si espande) */}
<View style={styles.content}>
<Text>Contenuto principale...</Text>
</View>
{/* Footer */}
<View style={styles.footer}>
<Text>© 2026</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
header: {
padding: 20,
backgroundColor: '#3498db',
alignItems: 'center',
},
titolo: {
fontSize: 22,
fontWeight: 'bold',
color: 'white',
},
content: {
flex: 1, // ← occupa TUTTO lo spazio rimanente
padding: 20,
},
footer: {
padding: 15,
backgroundColor: '#f0f0f0',
alignItems: 'center',
},
});

// Overlay su un'immagine
<View style={{ width: 200, height: 200 }}>
<Image source={{ uri: '...' }} style={{ width: '100%', height: '100%' }} />
<Text style={{
position: 'absolute',
bottom: 10,
left: 10,
color: 'white',
fontSize: 20,
fontWeight: 'bold',
}}>
Titolo foto
</Text>
</View>

// React Native 0.71+
<View style={{ flexDirection: 'row', gap: 10 }}>
<Item />
<Item />
<Item />
</View>
// In alternativa (pre-0.71)
<View style={{ flexDirection: 'row' }}>
<Item style={{ marginRight: 10 }} />
<Item style={{ marginRight: 10 }} />
<Item />
</View>

ProprietàValori comuniDescrizione
flexnumeroQuanto spazio occupa
flexDirection'column', 'row'Asse principale
justifyContent'center', 'space-between', 'flex-start'Allineamento asse principale
alignItems'center', 'stretch', 'flex-start'Allineamento asse secondario
alignSelf'center', 'flex-start'Allineamento individuale
flexWrap'wrap', 'nowrap'Vai a capo?
gapnumeroSpazio tra elementi
position'relative', 'absolute'Posizionamento

🎯 Esercizio: “Griglia menu ristorante”

Section titled “🎯 Esercizio: “Griglia menu ristorante””

Crea una schermata che mostri un menu usando una griglia 2×N con flexWrap:

  1. Ogni card: immagine in alto, nome sotto, prezzo in basso
  2. Griglia con flexWrap: 'wrap', larghezza ~48%
  3. Header con nome ristorante
  4. Categorie come badge colorati sopra ogni piatto
const MENU = [
{ id: 1, nome: 'Margherita', prezzo: 6.50, categoria: 'Pizza',
img: 'https://picsum.photos/seed/pizza1/200' },
{ id: 2, nome: 'Carbonara', prezzo: 8.00, categoria: 'Pasta',
img: 'https://picsum.photos/seed/pasta1/200' },
{ id: 3, nome: 'Insalata', prezzo: 5.50, categoria: 'Insalate',
img: 'https://picsum.photos/seed/insalata1/200' },
{ id: 4, nome: 'Tiramisù', prezzo: 4.00, categoria: 'Dolci',
img: 'https://picsum.photos/seed/dolce1/200' },
];