Как создать жест смахивания карты Tinder с помощью React и framer-motion?

Опубликовано: 8 Августа, 2022

Мы можем создать простое приложение Tinder, такое как жест смахивания, используя следующий подход, используя модуль Framer в ReactJS.

Предпосылки:

  1. Знание JavaScript (ES6)
  2. Знание HTML/CSS.
  3. Базовые знания ReactJS.

Крюки Framer, используемые при создании этого приложения:

  1. Framer useMotionValue
  2. Использование FramerTransform
  3. Использование FramerАнимация

Создание приложения React и установка модуля:

Шаг 1: Создайте приложение React с помощью следующей команды.

npx create-react-app tinder-swipe

Шаг 2: После создания папки проекта, т. е. Tinder-swipe, перейдите к ней с помощью следующей команды.

cd tinder-swipe

Шаг 3: После создания приложения ReactJS установите модули фреймов с помощью следующей команды.

npm install framer

Структура проекта: Дерево структуры нашего проекта должно выглядеть так:

Подход:

  • Мы собираемся использовать useMotionValue() для перемещения карты, когда пользователь перетаскивает курсор, поскольку все компоненты движения внутренне используют motionValues для отслеживания состояния и скорости анимируемого значения, которое мы собираемся получить с помощью этого хука.
  • Мы собираемся использовать хук useTransform() для поворота карты по мере того, как карта движется при перетаскивании, связывая с ней motionValue карты.
  • Кроме того, мы собираемся использовать хук useTransform() для изменения непрозрачности карты при ее перемещении, привязав ее к motionValue.
  • useAnimation() — это служебный хук, который используется для создания элементов управления анимацией (animControls), которые можно использовать для ручного запуска, остановки и последовательности анимации на карте.

Пример 1:

index.js




import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import { Frame, useMotionValue, useTransform, useAnimation } from "framer";
  
// Some styling for the card
const style = {
  backgroundImage: "URL(
  backgroundRepeat: "no-repeat",
  backgroundSize: "contain",
  backgroundColor: "#55ccff",
  boxShadow: "5px 10px 18px #888888",
  borderRadius: 10,
  height: 300,
};
  
const App = () => {
  // To move the card as the user drags the cursor
  const motionValue = useMotionValue(0);
  
  // To rotate the card as the card moves on drag
  const rotateValue = useTransform(motionValue, [-200, 200], [-50, 50]);
  
  // To decrease opacity of the card when swiped
  // on dragging card to left(-200) or right(200)
  // opacity gradually changes to 0
  // and when the card is in center opacity = 1
  const opacityValue = useTransform(
    motionValue,
    [-200, -150, 0, 150, 200],
    [0, 1, 1, 1, 0]
  );
  
  // Framer animation hook
  const animControls = useAnimation();
  
  return (
    <div className="App">
      <Frame
        center
        // Card can be drag only on x-axis
        drag="x"
        x={motionValue}
        rotate={rotateValue}
        opacity={opacityValue}
        dragConstraints={{ left: -1000, right: 1000 }}
        style={style}
        onDragEnd={(event, info) => {
          // If the card is dragged only upto 150 on x-axis
          // bring it back to initial position
          if (Math.abs(info.point.x) <= 150) {
            animControls.start({ x: 0 });
          } else {
            // If card is dragged beyond 150
            // make it disappear
            // making use of ternary operator
            animControls.start({ x: info.point.x < 0 ? -200 : 200 });
          }
        }}
      />
    </div>
  );
};
  
ReactDOM.render(<App />, document.getElementById("root"));

index.css




body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 
               "Segoe UI", "Roboto", "Oxygen",
               "Ubuntu", "Cantarell", "Fira Sans"
               "Droid Sans", "Helvetica Neue",
                sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
  
.App {
  text-align: center;
}
  
code {
  font-family: source-code-pro, Menlo, 
               Monaco, Consolas, "Courier New",
    monospace;
}

Шаг для запуска приложения: Запустите приложение с помощью следующей команды из корневого каталога проекта.

npm start

Вывод: теперь откройте браузер и перейдите по адресу http://localhost:3000/ , вы увидите следующий вывод:

Пример 2: Создание колоды карт

index.js




import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import { Frame, useMotionValue, useTransform, useAnimation } from "framer";
  
// Card component with destructured props
const Card = ({ image, color }) => {
  // To move the card as the user drags the cursor
  const motionValue = useMotionValue(0);
  
  // To rotate the card as the card moves on drag
  const rotateValue = useTransform(motionValue, [-200, 200], [-50, 50]);
  
  // To decrease opacity of the card when swiped
  // on dragging card to left(-200) or right(200)
  // opacity gradually changes to 0
  // and when the card is in center opacity = 1
  const opacityValue = useTransform(
    motionValue,
    [-200, -150, 0, 150, 200],
    [0, 1, 1, 1, 0]
  );
  
  // Framer animation hook
  const animControls = useAnimation();
  
  // Some styling for the card
  // it is placed inside the card component
  // to make backgroundImage and backgroundColor dynamic
  const style = {
    backgroundImage: `url(${image})`,
    backgroundRepeat: "no-repeat",
    backgroundSize: "contain",
    backgroundColor: color,
    boxShadow: "5px 10px 18px #888888",
    borderRadius: 10,
    height: 300
  };
  
  return (
    <div className="App">
      <Frame
        center
        // Card can be drag only on x-axis
        drag="x"
        x={motionValue}
        rotate={rotateValue}
        opacity={opacityValue}
        dragConstraints={{ left: -1000, right: 1000 }}
        style={style}
        onDragEnd={(event, info) => {
          
          // If the card is dragged only upto 150 on x-axis
          // bring it back to initial position
          if (Math.abs(info.point.x) <= 150) {
            animControls.start({ x: 0 });
          } else {
            
            // If card is dragged beyond 150
            // make it disappear
  
            // Making use of ternary operator
            animControls.start({ x: info.point.x < 0 ? -200 : 200 });
          }
        }}
      />
    </div>
  );
};
  
const App = () => {
  const cards = [
    {
      color: "#55ccff"
    },
    {
      color: "#e8e8e8"
    },
    {
      color: "#0a043c"
    },
    {
      color: "black"
    }
  ];
  
  return (
    <div className="App">
      
      {/* Traversing through cards arrray using map function
      and populating card with different image and color */}
        
      {cards.map((card) => (
        <Card image={card.image} color={card.color} />
      ))}
    </div>
  );
};
  
ReactDOM.render(<App />, document.getElementById("root"));

Шаг для запуска приложения: Запустите приложение, используя следующую команду из корневого каталога проекта:

npm start

Вывод: теперь откройте браузер и перейдите по адресу http://localhost:3000/ , вы увидите следующий вывод: