Skip to content

RN Lezione 7: FlatList e TouchableOpacity

  • Usare FlatList per liste performanti
  • Usare TouchableOpacity per elementi cliccabili
  • Gestire eventi long-press
  • Aggiungere e rimuovere elementi da una lista

FlatList renderizza solo gli elementi visibili (virtualizzazione). È MOLTO meglio di un array di View dentro ScrollView per liste lunghe.

import { FlatList, View, Text, StyleSheet } from 'react-native';
const DATA = [
{ id: '1', nome: 'Mario', eta: 17 },
{ id: '2', nome: 'Sofia', eta: 16 },
{ id: '3', nome: 'Luca', eta: 17 },
];
export default function App() {
const renderItem = ({ item }) => (
// ↑ item = elemento corrente
<View style={styles.item}>
<Text style={styles.nome}>{item.nome}</Text>
<Text style={styles.eta}>{item.eta} anni</Text>
</View>
);
return (
<FlatList
data={DATA} // Array di dati
renderItem={renderItem} // Come renderizzare
keyExtractor={item => item.id} // Chiave unica per ogni item
/>
);
}
ScrollView: [item1][item2][item3]...[item100] ← TUTTI renderizzati
FlatList: [item1][item2][item3] ← SOLO quelli visibili
[item4] ← quando scrolli

Per liste con +20 elementi, usa sempre FlatList!

ProprietàDescrizione
dataArray di dati
renderItem({ item, index, separators }) => JSX
keyExtractorEstrae la chiave unica (item => item.id)
ListHeaderComponentComponente in testa
ListFooterComponentComponente in fondo
ListEmptyComponentComponente se lista vuota
ItemSeparatorComponentSeparatore tra elementi
horizontalLista orizzontale
numColumnsGriglia a N colonne

2. TouchableOpacity — elementi cliccabili

Section titled “2. TouchableOpacity — elementi cliccabili”

TouchableOpacity rende qualsiasi elemento cliccabile con feedback visivo (opacità quando premuto).

import { TouchableOpacity, Text } from 'react-native';
<TouchableOpacity
style={styles.bottone}
onPress={() => console.log('click!')}
onLongPress={() => console.log('long press!')}
activeOpacity={0.7} // ← quanto diventa trasparente (default: 0.2)
disabled={false}
>
<Text style={styles.testo}>Cliccami</Text>
</TouchableOpacity>
const renderItem = ({ item }) => (
<TouchableOpacity
style={styles.card}
onPress={() => Alert.alert('Selezionato', item.nome)}
onLongPress={() => {/* elimina */}}
>
<Text style={styles.nome}>{item.nome}</Text>
</TouchableOpacity>
);

import { View, Text, FlatList, TouchableOpacity, Alert, TextInput, StyleSheet } from 'react-native';
import { useState } from 'react';
export default function App() {
const [nome, setNome] = useState('');
const [tel, setTel] = useState('');
const [contatti, setContatti] = useState([
{ id: '1', nome: 'Mario Rossi', tel: '345 1234567' },
{ id: '2', nome: 'Sofia Bianchi', tel: '345 7654321' },
]);
const [prossimoId, setProssimoId] = useState(3);
const aggiungi = () => {
if (!nome || !tel) {
Alert.alert('Errore', 'Compila tutti i campi');
return;
}
setContatti([
...contatti,
{ id: String(prossimoId), nome, tel }
]);
setProssimoId(prossimoId + 1);
setNome('');
setTel('');
};
const elimina = (id) => {
setContatti(contatti.filter(c => c.id !== id));
};
const confermaElimina = (item) => {
Alert.alert(
'Elimina contatto',
`Eliminare ${item.nome}?`,
[
{ text: 'Annulla', style: 'cancel' },
{ text: 'Elimina', onPress: () => elimina(item.id), style: 'destructive' },
]
);
};
const renderItem = ({ item }) => (
<TouchableOpacity
style={styles.card}
onPress={() => Alert.alert(item.nome, `Tel: ${item.tel}`)}
onLongPress={() => confermaElimina(item)}
>
<View style={styles.avatar}>
<Text style={styles.iniziale}>{item.nome[0]}</Text>
</View>
<View style={styles.info}>
<Text style={styles.nome}>{item.nome}</Text>
<Text style={styles.tel}>{item.tel}</Text>
</View>
<Text style={styles.chevron}></Text>
</TouchableOpacity>
);
return (
<View style={styles.container}>
<Text style={styles.titolo}>📞 Rubrica</Text>
{/* Form aggiunta */}
<View style={styles.form}>
<TextInput
style={styles.input}
placeholder="Nome"
value={nome}
onChangeText={setNome}
/>
<TextInput
style={styles.input}
placeholder="Telefono"
value={tel}
onChangeText={setTel}
keyboardType="phone-pad"
/>
<TouchableOpacity style={styles.aggiungiBtn} onPress={aggiungi}>
<Text style={styles.aggiungiTesto}>+ Aggiungi</Text>
</TouchableOpacity>
</View>
{/* Lista */}
<FlatList
data={contatti}
renderItem={renderItem}
keyExtractor={item => item.id}
ListEmptyComponent={
<Text style={styles.vuoto}>Nessun contatto</Text>
}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 50,
paddingHorizontal: 15,
backgroundColor: '#f0f4f8',
},
titolo: {
fontSize: 28,
fontWeight: 'bold',
marginBottom: 15,
},
form: {
backgroundColor: 'white',
padding: 15,
borderRadius: 12,
marginBottom: 15,
elevation: 2,
},
input: {
borderWidth: 1,
borderColor: '#ddd',
padding: 10,
borderRadius: 8,
marginBottom: 8,
fontSize: 16,
},
aggiungiBtn: {
backgroundColor: '#3498db',
padding: 12,
borderRadius: 8,
alignItems: 'center',
},
aggiungiTesto: {
color: 'white',
fontWeight: 'bold',
fontSize: 16,
},
card: {
flexDirection: 'row',
backgroundColor: 'white',
padding: 15,
borderRadius: 12,
marginBottom: 8,
alignItems: 'center',
elevation: 1,
},
avatar: {
width: 45,
height: 45,
borderRadius: 22.5,
backgroundColor: '#3498db',
justifyContent: 'center',
alignItems: 'center',
marginRight: 12,
},
iniziale: {
color: 'white',
fontSize: 18,
fontWeight: 'bold',
},
info: {
flex: 1,
},
nome: {
fontSize: 16,
fontWeight: 'bold',
},
tel: {
fontSize: 14,
color: 'grey',
},
chevron: {
fontSize: 24,
color: '#ccc',
},
vuoto: {
textAlign: 'center',
color: 'grey',
marginTop: 50,
fontSize: 16,
},
});

Per dati raggruppati:

import { SectionList } from 'react-native';
const DATA = [
{
title: 'Amici',
data: ['Mario', 'Sofia'],
},
{
title: 'Famiglia',
data: ['Anna', 'Luigi'],
},
];
<SectionList
sections={DATA}
renderItem={({ item }) => <Text>{item}</Text>}
renderSectionHeader={({ section }) => (
<Text style={styles.sectionHeader}>{section.title}</Text>
)}
keyExtractor={(item, index) => index}
/>

<FlatList
data={DATA}
renderItem={renderItem}
ItemSeparatorComponent={() => (
<View style={{ height: 1, backgroundColor: '#eee', marginLeft: 55 }} />
)}
/>

ComponenteCodiceUso
FlatList<FlatList data={d} renderItem={fn} />Liste virtualizzate
SectionList<SectionList sections={s} ... />Liste con sezioni
TouchableOpacity<TouchableOpacity onPress={fn}>Elementi cliccabili
Alert.alertAlert.alert('Titolo','Msg', btns)Dialoghi nativi

Crea un’app che:

  1. Campo input per nome elemento + quantità
  2. Bottone “Aggiungi” → aggiunge alla FlatList
  3. TouchableOpacity su ogni elemento → segna come “comprato” (barrato)
  4. Long-press → elimina con conferma Alert
  5. ListEmptyComponent quando la lista è vuota
  6. Separatore tra gli elementi
// Stato per lista
const [lista, setLista] = useState([]);
// Elemento tipo:
{ id: 1, nome: 'Pane', qta: 2, comprato: false }
// Segna come comprato:
const toggle = (id) => {
setLista(lista.map(item =>
item.id === id
? { ...item, comprato: !item.comprato }
: item
));
};