Cámara y galería en React Native
Clase 21 de 23 • Curso de Fundamentos de React Native
Contenido del curso
- 5

Uso de constantes y condicionales en archivos TSX de React Native
10:36 - 6

Componentes reutilizables en React Native
14:50 - 7

StyleSheet y Flexbox en React Native
11:24 - 8

Paleta de colores con hooks en React Native
13:07 - 9

useState para interfaces dinámicas en React Native
12:12 - 10

Estado interactivo en React Native con useCallback
13:24 - 11

Pressable vs TouchableOpacity en React Native
09:37
- 12

Crear un carrusel con ScrollView horizontal
10:51 - 13

Diferencias entre ScrollView y FlatList para listas grandes
09:47 - 14

Instalación de Async Storage para persistencia de datos en React Native
14:54 - 15

Context y Provider para estado global de hábitos
12:08 - 16

AsyncStorage context para persistir hábitos
13:19 - 17

React Native: Provider de animación con confetti
11:58 - 18

Cómo crear una ExploreCard específica para iOS y Android
09:48 - 19

Implementación del tab Explore con FlatList y carga asíncrona
12:49 - 20

Contexto de perfil con persistencia y avatar aleatorio usando IA
12:32 - 21

Cámara y galería en React Native
16:01
Integra la cámara y la galería del sistema operativo para crear un perfil completo con avatar, persistencia local y generación con IA. Aquí verás cómo estructurar el componente de avatar, manejar estados con contexto, solicitar permisos y guardar datos de forma segura en el dispositivo. Todo con un flujo claro y práctico.
¿Cómo se integra la librería de cámara y galería del sistema?
Usa una librería que accede a la cámara y a la galería nativas. Se importa como ImagePicker, se configuran opciones como la calidad (por ejemplo, 0.8) y se manejan los casos de cancelación. Además, se validan permisos de cámara y se muestran alertas cuando no han sido otorgados. El ejemplo se apoya en el esquema del sistema operativo, en este caso iOS, sin soluciones externas.
¿Qué opciones y permisos se configuran?
- Importar las funciones de ImagePicker en la parte superior.
- Definir calidad entre 0 y 1: 0.8 recomendado para equilibrio.
- Comprobar si el usuario canceló: no actualizar el estado.
- Solicitar y validar permisos de cámara.
- Mostrar una alerta si no hay permisos.
// importación en la parte superior
import * as ImagePicker from 'image-picker';
// elegir desde galería
const chooseFromGallery = async () => {
const result = await ImagePicker.launchImageLibraryAsync({
// tipo de imagen según librería.
quality: 0.8,
});
if (result.canceled) return;
setAvatar(result.assets?.[0]?.uri);
};
// tomar foto con cámara
const takePhoto = async () => {
const { status } = await ImagePicker.requestCameraPermissionsAsync();
if (status !== 'granted') {
alert('otorga permisos de cámara');
return;
}
const result = await ImagePicker.launchCameraAsync({ quality: 0.8 });
if (result.canceled) return;
setAvatar(result.assets?.[0]?.uri);
};
¿Cómo elegir desde galería o tomar foto?
- Galería: abrir el selector nativo y actualizar el avatar si no se cancela.
- Cámara: solicitar permisos, lanzar la cámara y guardar el resultado si continúa.
- Fallback: si no hay imagen elegida, mantener el avatar actual.
¿Cómo se construye el componente avatar reutilizable?
Se exporta un componente que recibe tamaño, nombre, url y un onPress. Usa Image con la prop source para la URL, estilos con borderRadius para el círculo perfecto y un util para mostrar iniciales cuando no hay imagen. El botón reutilizable envuelve el contenido para permitir pulsar y abrir la galería o la cámara.
// utils: obtener iniciales del nombre
const getInitials = (name = '') => name.trim().split(' ').map(p => p[0]).slice(0, 2).join('').toUpperCase();
export function Avatar({ size = 96, name = '', url, onPress }) {
const circle = { width: size, height: size, borderRadius: size / 2 };
return (
<Button onPress={onPress}>
<View style={[{ alignItems: 'center', justifyContent: 'center' }, circle]}>
{url ? (
<Image source={{ uri: url }} style={circle} />
) : (
<Text style={{ fontWeight: '700' }}>{getInitials(name)}</Text>
)}
</View>
</Button>
);
}
¿Cómo mostrar iniciales si no hay imagen?
- Verificar si la url existe.
- Si no existe: renderizar las iniciales del nombre.
- Mantener accesible el onPress para cambiar el avatar cuando se desee.
¿Cómo gestionar el perfil: estados, guardado y generación con IA?
Se consume un contexto con useProfile y se crean useState para name, role e indicadores de carga. Con useEffect se hace la primera carga del perfil (name y role). El botón de guardar llama al servicio de update desde el contexto, usa textos por defecto cuando faltan campos y muestra una alerta tras guardar. Además, existe una función asíncrona para generar un avatar con IA a partir del nombre como semilla.
// estados locales
const [name, setName] = useState('');
const [role, setRole] = useState('');
const [busy, setBusy] = useState(false);
const { profile, updateProfile } = useProfile();
const [avatar, setAvatar] = useState(profile?.avatar);
// primera carga de datos
useEffect(() => {
setName(profile?.name);
setRole(profile?.role);
}, [profile?.name, profile?.role]);
// guardar cambios
const save = async () => {
setBusy(true);
await updateProfile({
name: name || 'sin nombre',
role: role || 'sin rol',
avatar,
});
setBusy(false);
alert('datos guardados');
};
// generar avatar con IA
const generateWithAI = async () => {
setBusy(true);
const url = await service.generateAvatarWithAI(name);
setAvatar(url);
setBusy(false);
};
¿Cómo se organiza la interfaz del perfil?
- KeyboardAvoidingView: evita que el teclado oculte elementos.
- Platform para ajustar comportamiento en iOS.
- ScrollView: contenido breve sin listas extensas.
- TextInput: controla name y role con useState.
- Botones: tomar foto, elegir de galería, generar con IA y guardar.
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined}>
<ScrollView>
<View style={{ alignItems: 'center', margin: 16 }}>
<Avatar name={name} url={avatar} onPress={chooseFromGallery} />
</View>
<View>
<Text>nombre</Text>
<TextInput value={name} onChangeText={setName} style={styles.input} />
<Text>profesión</Text>
<TextInput value={role} onChangeText={setRole} style={styles.input} />
</View>
<Button title="tomar foto" onPress={takePhoto} />
<Button title="elegir de galería" onPress={chooseFromGallery} />
<PrimaryButton title="generar con ia" onPress={generateWithAI} />
<PrimaryButton title="guardar" onPress={save} />
</ScrollView>
</KeyboardAvoidingView>
// estilos mínimos del input
const styles = {
input: { borderWidth: 1, borderRadius: 8, padding: 10, marginVertical: 8 },
};
¿Cómo se habilita el acceso global a los datos?
- Agregar el provider del perfil en la raíz de la app.
- Así, todas las pantallas consumen el contexto sin pasar props.
<ProfileProvider>
<App />
</ProfileProvider>
- Los datos se almacenan en el dispositivo: permanecen al regresar.
- Puedes sobrescribir el avatar generando otro o eligiendo una nueva imagen.
- La experiencia se mantiene fluida gracias a un loader cuando el perfil está cargando.
¿Te gustaría ver variantes de estilos o flujos de permisos? Deja un comentario con tus dudas o ideas para seguir iterando este perfil con avatar y IA.