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 superiorimport*asImagePickerfrom'image-picker';// elegir desde galeríaconstchooseFromGallery=async()=>{const result =awaitImagePicker.launchImageLibraryAsync({// tipo de imagen según librería.quality:0.8,});if(result.canceled)return;setAvatar(result.assets?.[0]?.uri);};// tomar foto con cámaraconsttakePhoto=async()=>{const{ status }=awaitImagePicker.requestCameraPermissionsAsync();if(status !=='granted'){alert('otorga permisos de cámara');return;}const result =awaitImagePicker.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 nombreconst getInitials =(name ='')=> name.trim().split(' ').map(p=> p[0]).slice(0,2).join('').toUpperCase();exportfunctionAvatar({ size =96, name ='', url, onPress }){const circle ={width: size,height: size,borderRadius: size /2};return(<ButtononPress={onPress}><Viewstyle={[{alignItems:'center',justifyContent:'center'}, circle]}>{url ?(<Imagesource={{uri: url }}style={circle}/>):(<Textstyle={{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 localesconst[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 datosuseEffect(()=>{setName(profile?.name);setRole(profile?.role);},[profile?.name, profile?.role]);// guardar cambiosconstsave=async()=>{setBusy(true);awaitupdateProfile({name: name ||'sin nombre',role: role ||'sin rol', avatar,});setBusy(false);alert('datos guardados');};// generar avatar con IAconstgenerateWithAI=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.
<KeyboardAvoidingViewbehavior={Platform.OS==='ios'?'padding':undefined}><ScrollView><Viewstyle={{alignItems:'center',margin:16}}><Avatarname={name}url={avatar}onPress={chooseFromGallery}/></View><View><Text>nombre</Text><TextInputvalue={name}onChangeText={setName}style={styles.input}/><Text>profesión</Text><TextInputvalue={role}onChangeText={setRole}style={styles.input}/></View><Buttontitle="tomar foto"onPress={takePhoto}/><Buttontitle="elegir de galería"onPress={chooseFromGallery}/><PrimaryButtontitle="generar con ia"onPress={generateWithAI}/><PrimaryButtontitle="guardar"onPress={save}/></ScrollView></KeyboardAvoidingView>
// estilos mínimos del inputconst 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.