10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BitStarAdvent Calendar 2023

Day 13

スワイプでテキパキ切り替わるスライドUI を作ってみた

Last updated at Posted at 2023-12-13

こういうのを作ってみました😀

demo

画面収録-2023-12-13-13.43.42.gif

How to

ステップバイステップで、このUI の実装方法を紹介していきます!

今回このUI を実装は Framer Motion, Next.js, Tailwind CSS を使いました。
アニメ部分のキーであるFramer Motion は、ポピュラーで高度なアニメーションを簡単に実装できるライブラリです。

クリックで拡大・移動させる

Framer Motion のいいところは、はじまりと最後だけ定義してもちゃんと動くところです。
👇を見てみてください、これだけで拡大・移動させることができます。

import { useState } from 'react'
import { motion } from 'framer-motion'


export default function SampleCard() {

    const [isSelected, setIsSelected] = useState(false)

    return (
        <>
            <motion.li
                layoutId="card"
                className="text-blue-600 font-bold w-72 p-7 rounded-md bg-blue-400 list-none mx-auto"
                onClick={() => setIsSelected(true)}
            >
                <motion.h1>Hello</motion.h1>
            </motion.li>
            {isSelected && (
                <motion.div
                    layoutId="card"
                    className="text-green-600 font-bold w-8/12 h-96 p-7 rounded-md bg-green-400 mx-auto"
                >
                    <motion.button className="text-white" onClick={() => setIsSelected(false)}>
                        close
                    </motion.button>
                    <motion.h1>Hello from Big</motion.h1>
                </motion.div>
            )}
        </>
    )
}

画面収録-2023-12-13-2.23.50.gif

ドラッグを認識させる

ドラッグを認識させるのも簡単です。motion タグに、drag 属性とonDrag 属性を設定するだけで認識できます。

<motion.div
    layoutId="card"
    className="text-green-600 font-bold w-8/12 h-96 p-7 rounded-md bg-green-400 mx-auto"
    drag="x"
    onDrag={() => {
        console.log("Dragged !")
    }}
>

画面収録-2023-12-13-13.56.21.gif

ドラッグでイベントを発生させる

ドラッグイベントを更新して、座標に応じてイベントを発生させます。

<motion.div
    layoutId="card"
    className="text-green-600 font-bold w-8/12 h-96 p-7 rounded-md bg-green-400 mx-auto"
    drag="x"
    onDrag={(e, {offset}) => {
        // 初期座標からx軸で100px 以上移動したら
        if (offset.x > 100) {
            console.log("Wow !")
        }
    }}
>

画面収録-2023-12-13-15.04.26_1.gif

スワイプで切り替わるようにする

あとは、イベントで切り替わるようにハンドルしたら完了です!
AnimatePresence タグでアンマウントされたときまで、自動でアニメーションを適用できます。

import { useState } from 'react'
import { motion } from 'framer-motion'
import { AnimatePresence } from 'framer-motion'


export default function SampleCard() {

    const items = [{ id: "left" }, { id: "right" }]

    const [selected, setSelected] = useState("")

    return (
        <>
            <ul className = "flex mx-auto gap-5">
                {items.map(item => (
                    <motion.li
                        key={item.id}
                        layoutId={item.id}
                        className="text-blue-600 font-bold w-72 p-7 rounded-md bg-blue-400 list-none"
                        onClick={() => setSelected(item.id)}
                    >
                        <motion.h1>Hello</motion.h1>
                    </motion.li>                    
                ))}
            </ul>
            {selected !== "" && (
                <AnimatePresence>
                    <div className = "h-screen w-screen z-20 flex justify-center items-center">
                        <motion.div
                            key={selected}
                            layoutId={selected}
                            className="text-green-600 font-bold absolute w-8/12 h-96 p-7 rounded-md bg-green-400"
                            drag="x"
                            onDrag={(e, {offset}) => {
                                console.log("Dragged !")
                                // 初期座標からx軸で100px 以上移動したら
                                if (offset.x > 100) {
                                    setSelected("right")
                                } else if (offset.x < -100) {
                                    setSelected("left")
                                }
                            }}
                        >
                            <motion.button className="text-white" onClick={() => setSelected("")}>
                                close
                            </motion.button>
                            <motion.h1>Hello from {selected}</motion.h1>
                        </motion.div>
                    </div>
                </AnimatePresence>
            )}
        </>
    )
}


おわりに

いかがだったでしょうか?
Framer Motion を使う際に参考にしていただければ幸いです!

このQiita の記事は、BitStar のアドイベントカレンダーのとして掲載しました。
ぜひ、他の記事も見ていただければ嬉しいです!

BitStar では、React, Rails を使ってサービスを開発中です🧑‍💻
ご興味がある方は以下からご確認ください!

10
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?