Construyendo una Galería de Imágenes Interactiva al Estilo de la App de Fotos del iPhone con Next.js y Framer Motion

100 views
Tiempo de lectura: 5 min
Desarrollo
2024-09-05

En este artículo, exploraremos cómo crear una galería de imágenes interactiva inspirada en la app de Fotos del iPhone de Apple, utilizando Next.js, React, TypeScript y Framer Motion. Este enfoque no solo proporciona una experiencia de usuario fluida y atractiva, sino que también aprovecha la familiaridad de los usuarios con la interfaz de Apple para ofrecer una experiencia de navegación de imágenes intuitiva. Además, para ver más componentes visuales interactivos como este, puedes visitar smoothui.dev.

Características Clave

  • Diseño de cuadrícula responsivo similar a la app de Fotos de iOS
  • Funcionalidad de selección de imágenes
  • Eliminación de imágenes seleccionadas
  • Restablecimiento de la galería a su estado inicial
  • Animaciones suaves utilizando Framer Motion
imagen blog

Desglose del Código

Analicemos los componentes principales de nuestro ImageSelector:

Importaciones y Configuración Inicial

"use client"
 
import { useCallback, useState } from "react"
import Image from "next/image"
import { AnimatePresence, motion } from "framer-motion"
import { Share2, Trash2 } from "lucide-react"
 
// Importación de imágenes y configuración de datos iniciales

Comenzamos importando las dependencias necesarias y configurando nuestros datos iniciales de imágenes.

Gestión de Estado

const [images, setImages] = useState<number[]>(
  initialImages.map((img) => img.id)
)
const [selectedImages, setSelectedImages] = useState<number[]>([])
const [isSelecting, setIsSelecting] = useState(false)

Utilizamos el hook useState de React para gestionar el estado de nuestro componente, incluyendo la lista de imágenes, las imágenes seleccionadas y el modo de selección.

  • images: IDs de las imágenes actualmente en la galería.
  • selectedImages: IDs de las imágenes seleccionadas.
  • isSelecting: Booleano que indica si estamos en modo de selección.

Manejadores de Eventos

const handleImageClick = useCallback(
  (id: number) => {
    if (!isSelecting) return
    setSelectedImages((prev) =>
      prev.includes(id) ? prev.filter((imgId) => imgId !== id) : [...prev, id]
    )
  },
  [isSelecting]
)
const handleDelete = useCallback(() => {
  setImages((prev) => prev.filter((id) => !selectedImages.includes(id)))
  setSelectedImages([])
}, [selectedImages])
const handleReset = useCallback(() => {
  setImages(initialImages.map((img) => img.id))
  setSelectedImages([])
  setIsSelecting(false)
}, [])
const toggleSelecting = useCallback(() => {
  setIsSelecting((prev) => !prev)
  if (isSelecting) setSelectedImages([])
}, [isSelecting])

Estos manejadores de eventos gestionan la lógica principal de nuestra aplicación:

  • handleImageClick: Selecciona o deselecciona una imagen.
  • handleDelete: Elimina las imágenes seleccionadas.
  • handleReset: Restablece la galería a su estado inicial.
  • toggleSelecting: Activa o desactiva el modo de selección.

Utilizamos useCallback para memoizar estas funciones y evitar renderizados innecesarios.

Renderizado de la Galería

return (
 
<div className="flex h-full w-full flex-col justify-between p-4">
  {/ Encabezado con botones de Restablecer y Seleccionar /}
  {/ Cuadrícula de imágenes /}
  {/ Barra de herramientas de selección /}
</div>
)

La función de renderizado principal devuelve un contenedor con un encabezado, una cuadrícula de imágenes y una barra de herramientas de selección.

Cuadrícula de Imágenes

 
<motion.div className="grid grid-cols-3 gap-1 overflow-scroll" layout>
  <AnimatePresence>
    {images.map((id) => {
      const image = imageMap.get(id)
      if (!image) return null
      return (
        <motion.div
          key={image.id}
          layout
          initial={{ opacity: 0, scale: 0.8 }}
          animate={{ opacity: 1, scale: 1 }}
          exit={{ opacity: 0, scale: 0.8 }}
          transition={{ type: "spring", stiffness: 300, damping: 25 }}
          className="relative aspect-square cursor-pointer"
          onClick={() => handleImageClick(image.id)}
        >
          {/ Componente de imagen /}
          {/ Indicador de selección /}
        </motion.div>
      )
    })}
  </AnimatePresence>
</motion.div>

La cuadrícula de imágenes utiliza Framer Motion para animaciones suaves al agregar o eliminar imágenes, similar a la app de Fotos de Apple.

  • Utilizamos motion.div de Framer Motion para animar la cuadrícula completa.
  • AnimatePresence se usa para animar la entrada y salida de elementos de la lista.
  • Cada imagen está envuelta en un motion.div con animaciones de entrada, salida y disposición.
  • Las animaciones utilizan un tipo de transición "spring" para un efecto más natural.

Barra de Herramientas de Selección

 
<AnimatePresence>
  {isSelecting && (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0, y: 20 }}
      className="bg-light1/20 dark:bg-dark1/20 absolute bottom-0 left-0 right-0 z-10 flex items-center justify-between p-4 bg-blend-luminosity backdrop-blur-xl"
    >
      {/ Share and Delete buttons /}
      {/ Selected count /}
    </motion.div>
  )}
</AnimatePresence>

La barra de herramientas de selección aparece en modo de selección, permitiendo a los usuarios compartir o eliminar las imágenes seleccionadas, al igual que en la app de Fotos de iOS.

Conclusión

Este tutorial te ha guiado a través del proceso de creación de una galería de imágenes interactiva inspirada en la app de Fotos de iOS. Hemos cubierto:

  1. Configuración del proyecto y gestión de estado con React Hooks.
  2. Implementación de una interfaz de usuario responsiva y atractiva.
  3. Uso de Framer Motion para animaciones suaves y naturales.
  4. Manejo de eventos para selección, eliminación y restablecimiento de imágenes.

Este componente demuestra cómo combinar Next.js, React, TypeScript y Framer Motion para crear interfaces de usuario modernas y atractivas. Las animaciones no solo mejoran la estética, sino que también proporcionan retroalimentación visual a las acciones del usuario, mejorando la experiencia general. Para seguir mejorando este componente, podrías considerar añadir funcionalidad de zoom para las imágenes, implementar gestos táctiles para dispositivos móviles, o integrar con un backend para cargar y guardar imágenes dinámicamente. Recuerda, la práctica es clave para dominar estas tecnologías. ¡Experimenta con el código, ajusta las animaciones y haz que este componente sea tuyo!

Ver Más

Visita smoothui.dev para ver este y otros componentes visuales con animaciones increíbles, especialmente útiles si estás interesado en crear experiencias interactivas como las de las aplicaciones de Apple.

Entendiendo y calculando el Line Height

CSS
Desarrollo
Diseño

Aprende a calcular y aplicar el line height en tus diseños web para mejorar la legibilidad y la estética. Descubre cómo ajustar el espacio entre líneas de texto de manera efectiva.

Guía Completa para Montar una VPS con Next.js en Hostinger

Hosting
Tutorial

Aprende paso a paso cómo desplegar un proyecto Next.js en una VPS de Hostinger. Configura Node.js, Nginx, PM2 y gestiona certificados SSL con Certbot para asegurar tu aplicación web.