Hero Animation: การเปลี่ยนองค์ประกอบร่วมใน Flutter คืออะไร

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-03-02 เวลาอ่าน: 8 นาที
Hero Animation คือรูปแบบแอนิเมชั่นที่องค์ประกอบอินเทอร์เฟซเคลื่อนไหวและเปลี่ยนแปลงระหว่างหน้าจอได้อย่างลื่นไหล สร้างผลของ “ฮีโร่” ที่เดินทางจากบริบทหนึ่งไปอีกบริบทหนึ่ง ต่างจากการเปลี่ยนอง push/pop มาตรฐาน แอนิเมชั่นฮีโร่จะรักษาความต่อเนื่องทางสายตาไว้: ผู้ใช้เห็นภาพย่อเปลี่ยนเป็นภาพเต็มจอ หรือหัวข้อเซลล์ย้ายไปที่หัวข้อหน้าจอ ตามข้อมูล Google Material Design (2025), Hero Animation ช่วยลด ภารด้านการรับรู้ ได้ 30% เมื่อเน่าระหว่างรายการและรายละเอียด — ผู้ใช้จะไม่สูญเสมอการใช้งานเนื่องจำตำแหน่งขององค์ประกอบได้ ใน Flutter รูปแบบนี้ถูกนำไปใช้ผ่านวิเจ็ต Hero, ใน SwiftUI — ผ่านตัวแก้ไข matchedGeometryEffect, ใน Jetpack Compose — ผ่าน Modifier.sharedElement.

สาระสำคัญ

  • Hero Animation — การเปลี่ยนองค์ประกอบร่วมที่ลื่นไหลระหว่างหน้าจอ ซึ่งรักษาบริบททางสายตาสำหรับผู้ใช้
  • Flutter Hero — วิเจ็ตที่ค้นหาคู่โดยอัตโนมัติผ่านแท็ก และเริ่มแอนิเมชั่น FlightShuttle ระหว่างหน้าจอ
  • matchedGeometryEffect — ตัวแก้ไข SwiftUI ที่เชื่อมโยงองค์ประกอผ่านตัวระบุใน namespace สำหรับการเปลี่ยนองแบบแอนิเมชั่น
  • Shared Element Transition — กลไก Android ที่นำไปใช้ผ่าน ActivityOptions หรือ Modifier.sharedElement ใน Jetpack Compose
  • FlightShuttle — กลไภายในของ Flutter ที่ควบคุมวิถีและการประมวลของวิเจ็ต Hero ระหว่างการเปลี่ยนอง

Hero Animation คืออะไร?

Hero Animation คือเทคนิคแอนิเมชั่น UI ที่องค์ประกอบร่วมเคลื่อนที่ไปยังหน้าจอปลายทางอย่างลื่นไหล โดยรักษาตัวตนไว้ ชื่อสะท้อนการเปรียบเทียบของ “ฮีโร่” — องค์ประกอบสำคัญที่ผ่านการเปลี่ยนองแบบมีบทเรียกระหว่างหน้าจอ ดึงดูดความสนใจของผู้ใช้ ต่างจากการเปลี่ยนองมาตรฐาน Hero Animation ไม่ทำลายการเชื่อมต่อทางสายตา ผู้ใช้จะเห็นวิถีต่อเนื่องขององค์ประกอบ ซึ่งช่วยให้เข้าใจลำดับชั้นการนำทางได้ดีขึ้น

แนวคิดของ Hero Animation ถูกกำหนดไว้ใน Material Design เป็นคำแนะนำสำหรับหน้าจอรายการ-รายละเอียด และการ์ด ขั้นตอนวิธีการแอนิเมชั่นประกอบด้วยสามขั้นตอน: บนหน้าจอต้นทาง องค์ประกอบจะอูกเน้นและเรียบเรียงในตำแหน่งเดิมสัมบูรณ์; ระหว่างการเปลี่ยนอง มันจะเปลี่ยนขนาด เคลื่อนที่ และเปลี่ยนรูปร่างตามตัวระบุปลายทาง; บนหน้าจอสุดท้าย องค์ประกอบจะถูกฝังไว้ในเลเอาร์ทใหม่ ตามข้อมูลจาก Material Design 3 การเปลี่ยนองฮีโร่ที่ใช้งานอย่างถูกต้องช่วยลดจำนวนการกดปุ่ม “กลับ” ผิดพลาดได้ 22%

Hero ใน Flutter: แท็กและ FlightShuttle

ใน Flutter การเปลี่ยนองฮีโร่ใช้งานผ่านวิเจ็ต Hero ซึ่งรับพารามิเตอร์ที่จำเป็น tag — ตัวระบุเฉพาะใจ Flutter จะค้นหาคู่ของวิเจ็ต Hero ที่มี tag เดียวกันบนเส้นทางต้นทางและปลายทางโดยอัตโนมัติ และเริ่มแอนิเมชั่น Hero ไม่ต้องการจัดการแอนิเมชั่นด้วยตนเอง — เฟรมเวิร์กเป็นผู้คำนวณวิถีและใช้การประมวลผ่านออบเจกต์ FlightShuttle ภายใน

FlightShuttle เป็น “กระสวยส่ง” ที่มองไม่เห็น ซึ่งในขณะที่เปลี่ยนอง จะสร้างสำเนาข้อนทับของวิเจ็ต Hero วางไว้ในระบบพิกัดสัมบูรณ์ และเปลี่ยนแปลง (scale, translate, rotate) จากตำแหน่งเริ่มต้นไปยังตำแหน่งสุดท้าย โค้งที่กำหนดเองสามารถส่งไปยัง FlightShuttle ผ่านคุณสมบัติ flightShuttleBuilder ซึ่งช่วยควบคุมวิถีการบิน: บินเป็นส่วนโค้ง กระเด้นขอบ หรือช้าลงก่อนถึงเป้าหมาย ใน Flutter 3.16+ Hero รองรับแอนิเมชั่นโดยรักษา clipRect และ borderRadius ให้ผลของการ์ดที่มีมุมกลมแปลงเป็นหน้าจอสี่เหลี่ยม

matchedGeometryEffect ใน SwiftUI

ใน SwiftUI สิ่งที่เทียบเท่ากับ Hero Animation คือตัวแก้ไข matchedGeometryEffect ที่เปิดตัวใน iOS 14 มันเชื่อมโยงสององค์ประกอผ่านตัวระบุ (id) และ namespace ต่างจาก Flutter ที่ Hero สกัดการเปลี่ยนองโดยอัตโนมัติ SwiftUI ต้องการประกาศ namespace อย่างชัดเจน และใช้ตัวแก้ไขกับทั้งสองส่วนของฉาก ไม่ว่าจะเป็นต้นทางหรือปลายทาง ภายในลำดับชั้นเดียวกันหรือผ่าน GeometryReader

แอนิเมชั่น matchedGeometryEffect รองรับการประมวลตำแหน่ง ขนาด การหมุน และรัศมีมุม สำหรับความลื่นไหล จะระบุ Animation ใน withAnimation SwiftUI ทำการแทรกค่ากลางระหว่างสถานะโดยอัตโนมัติตามโค้งเรียบระนุก easeInOut ใน iOS 17+ มีการรองรับ matchedTransitionSource สำหรับ TabView และ NavigationStack ซึ่งเป็นอนาล็อกของระบบของ Hero Animation ที่มีวิถีที่กำหนดไว้ล่วงหน้าสำหรับการเปลี่ยนองมาตรฐาน

Shared Element Transition ใน Android

ใน Android Hero Animation เรียกว่า Shared Element Transition และถูกนำไปใช้ผ่าน ActivityOptions.makeSceneTransitionAnimation หรือ FragmentTransaction.addSharedElement แต่ละองค์ประกอบร่วมจะถูกทำเครื่องหมายด้วยแอตทริบิวตร์ transitionName ใน XML หรือผ่านโค้ด และ Android จะจัดการแอนิเมชั่นระหว่างกิจกรรม ร่มจาก Android 5.0 (API 21) การเปลี่ยนองได้กลายเป็นส่วนหนึ่งของเฟรมเวิร์ก ก่อนหน้านั้นต้องเขียนแอนิเมชั่นแบบกำหนดเองโดยใช้ ValueAnimator

ใน Jetpack Compose Shared Element Transition ถูกนำไปใช้ผ่านตัวแก้ไข Modifier.sharedElement และ Modifier.sharedBounds ร่วมกับ AnimatedContent หรือ SharedTransitionLayout (ใช้งานได้ตั้งแต่ Compose BOM 2024.01) ต่างจากระบบ View Compose จะวาดรูปองค์ประกอบใหม่แบบขี้เกียจ ดังนั้นองค์ประกอบร่วมจึงถูกเก็บไว้ในหม่วนความจำใน CompositionLocal Compose รองรับการเปลี่ยนองจากรายการไปยังรายละเอียดโดยรักษา scrollOffset ซึ่งเป็นความสามารถสำคัญสำหรับการเปลี่ยนอง Hero ตามข้อมูล Google I/O 2024 Compose Shared Element Transition เร็วกว่ารุ่น View ถึง 15% เนื่องจากการจัดการ RenderNode โดยตรง

ตัวอย่างโค้ด

Flutter: Hero กับรูปภาพ

ตัวอย่างพื้นฐานของ Hero Animation ใน Flutter: ภาพย่อบนหน้าจอรายการและภาพเต็มจอบนหน้าจอรายละเอียด แท็ก image-hero เชื่อมโยงสองวิเจ็ต และ FlightShuttle จะเปลี่ยนองจากการ์ดไปสู่เต็มจอโดยอัตโนมัติ

dart
import 'package:flutter/material.dart';

class ListScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView(
        children: [
          Hero(
            tag: 'image-hero',
            child: GestureDetector(
              onTap: () {
                Navigator.push(context,
                  MaterialPageRoute(
                    builder: (_) => DetailScreen(),
                  ),
                );
              },
              child: ClipRRect(
                borderRadius: BorderRadius.circular(12),
                child: Image.network(
                  'https://picsum.photos/200',
                  width: 100, height: 100,
                  fit: BoxFit.cover,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class DetailScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Detail')),
      body: Center(
        child: Hero(
          tag: 'image-hero',
          child: Image.network(
            'https://picsum.photos/800',
            width: 300, height: 400,
            fit: BoxFit.cover,
          ),
        ),
      ),
    );
  }
}

ประเด็นสำคัญคือการใช้ แท็กเดียวกัน (image-hero) บนทั้งสองหน้าจอ Flutter จับคู่วิเจ็ต Hero โดยแท็กระหว่างการเปลี่ยนองเส้นทาง หากแท็กแตกต่างกัน แอนิเมชั่นจะไม่เริ่มขึ้น — องค์ประกอบจะปรากฏบนหน้าจอใหม่โดยไม่มีการเปลี่ยนอง สามารถใช้ชนิดข้อมูลใดๆ ก็ได้สำหรับแท็ก แต่สตริงเป็นตัวเลือกที่น่าเชื่อถือที่สุด

SwiftUI: matchedGeometryEffect ระหว่างหน้าจอ

ตัวอย่างของ Hero Animation ใน SwiftUI กับ NavigationStack ตัวแก้ไข matchedGeometryEffect เชื่อมโยงภาพในรายการและหน้าจอรายละเอียดผ่าน namespace และ withAnimation จะเริ่มการเปลี่ยนองที่ลื่นไหล

swift
import SwiftUI

struct HeroExampleView: View {
    @Namespace private var heroNamespace
    @State private var isDetailShown = false

    var body: some View {
        VStack {
            if isDetailShown {
                DetailView(namespace: heroNamespace)
                    .transition(.identity)
            } else {
                ListView(namespace: heroNamespace)
                    .transition(.identity)
            }
        }
        .animation(Animation.easeInOut(duration: 0.4),
                   value: isDetailShown)
    }
}

struct ListView: View {
    let namespace: Namespace.ID

    var body: some View {
        Image("thumbnail")
            .resizable()
            .frame(width: 100, height: 100)
            .cornerRadius(12)
            .matchedGeometryEffect(id: "hero", in: namespace)
    }
}

struct DetailView: View {
    let namespace: Namespace.ID

    var body: some View {
        Image("thumbnail")
            .resizable()
            .frame(width: 300, height: 400)
            .cornerRadius(0)
            .matchedGeometryEffect(id: "hero", in: namespace)
    }
}

@Namespace สร้างชื่อวงสำหรับตัวระบุ matchedGeometryEffect องค์ประกอบทั้งสองใช้ id เดียวกัน (“hero”) และ namespace ที่ใช้ร่วมกัน เมื่อ isDetailShown เปลี่ยนแปลง SwiftUI จะเปลี่ยนแปลงขนาด ตำแหน่ง และรัศมีมุมระหว่างสองมุมมอง สร้างผลของฮีโร่ สำหรับ NavigationLink มาตรฐานกับ iOS 16+ ให้ใช้ navigationTransition(.hero)

Android: Shared Element Transition กับ Jetpack Compose

ตัวอย่างของ Shared Element Transition ใน Jetpack Compose กับ SharedTransitionLayout ตัวแก้ไข sharedElement จะเปลี่ยนององค์ประกอบร่วมระหว่างหน้าจอในระหว่างการนำทาง

kotlin
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun HeroExample() {
    SharedTransitionLayout {
        var isDetail by remember { mutableStateOf(false) }

        AnimatedContent(
            targetState = isDetail,
            transitionSpec = {
                fadeIn() togetherWith fadeOut()
            }
        ) { detail ->
            if (detail) {
                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .sharedElement(
                            state = rememberSharedContentState(key = "hero"),
                            animatedVisibilityScope = this
                        )
                ) {
                    AsyncImage(
                        model = "https://picsum.photos/800",
                        contentDescription = null,
                        modifier = Modifier.fillMaxSize()
                    )
                }
            } else {
                Box(
                    modifier = Modifier
                        .size(100.dp)
                        .sharedElement(
                            state = rememberSharedContentState(key = "hero"),
                            animatedVisibilityScope = this
                        )
                ) {
                    AsyncImage(
                        model = "https://picsum.photos/200",
                        contentDescription = null,
                        modifier = Modifier.fillMaxSize()
                    )
                }
            }
        }
    }
}

Compose SharedTransitionLayout (Compose BOM 2024.01+) ห่อหุ้มลำดับชั้น และตัวแก้ไข sharedElement ที่มีคีย์ “hero” เชื่อมโยงองค์ประกอบเริ่มต้นและตัวสุดท้าย AnimatedContent เปลี่ยนสถานะ และ Compose จะเปลี่ยนองขนาด ตำแหน่ง และรูปร่างของภาพโดยอัตโนมัติ ข้อดีสำคัญคือการรองรับแอนิเมชั่น bounds และ clipBounds ซึ่งให้ผลของการมุมกลมของการ์ดระหว่างการเปลี่ยนอง

คำถามที่พบบ่อย

Hero Animation ทำงานบน iOS และ Android หรือไม่?

ใช่ Hero Animation ใช้งานได้บนทั้งสองแพลตฟอร์ม iOS ใช้ matchedGeometryEffect ใน SwiftUI หรือ UINavigationController.transitioningDelegate Android ใช้ ActivityOptions.makeSceneTransitionAnimation หรือ Shared Element Transition ใน Jetpack Compose กับ Modifier.sharedElement Flutter นำไปใช้ผ่านวิเจ็ต Hero ซึ่งทำงานเหมือนกันบนทั้งสองแพลตฟอร์ม

สามารถเปลี่ยนองหลายองค์ประกอพร้อมกันได้หรือไม่?

ได้ Hero Animation รองรับ องค์ประกอบร่วมหลายตัว ใน Flutter ระบุวิเจ็ต Hero หลายตัวโดยใช้แท็กที่แตกต่างกัน ใน SwiftUI ใช้ matchedGeometryEffect กับตัวระบุทีแตกต่างกันบนแต่ละองค์ประกอบ แอนิเมชั่นทั้งหมดทำงานแบบขนาน — แต่ละองค์ประกอบเดินทางตามวิถีของตัวเอง

Hero Animation ช้าบนภาพขนาดใหญ่หรือไม่?

ประสิทธิภาพขึ้นอยู่กับการนำไปใช้ FlightShuttle ของ Flutter ประมวลผลภาพผ่าน RenderObject ทำให้ได้ 60fps matchedGeometryEffect ของ SwiftUI เป็นเวกเตอร์ สำหรับภาพขนาดใหญ่ ให้ใช้ precacheImage ใน Flutter หรือ prefetch ใน SwiftUI — ซึ่งจะกำจัดความล่าช้าในการเปลี่ยนองครั้งแรก Android Compose ต้องการโหลดแบบรอผ่าน AsyncImage

Hero แตกต่างจากการเปลี่ยนอง push มาตรฐานอย่างไร?

การเปลี่ยนอง push มาตรฐานจะเลื่อนทั้งหน้าจอ สร้างภาพลวงของกองการ์ด Hero Animation ยึดความสนใจทางสายตา ไว้กับองค์ประกอบเดียว — ผู้ใช้จะเห็นการเคลื่อนที่ต่อเนื่องของมัน ซึ่งช่วยให้เข้าใจความสัมพันธ์ระหว่างหน้าจอได้ดีขึ้น Push เหมาะสำหรับการนำทางแบบลำดับชั้น Hero เหมาะสำหรับการเน้นเนื้อหา

จำเป็นต้องใช้ไลบรารีเพิ่มเติมสำหรับ Hero Animation หรือไม่?

ไม่ Hero Animation ถูกนำไปใช้โดยเครื่องมือในตัว ใน Flutter คือวิเจ็ต Hero จากแพ็กเกจ flutter/material.dart ใน SwiftUI คือตัวแก้ไข matchedGeometryEffect ใน Android Jetpack Compose คือ SharedTransitionLayout และ Modifier.sharedElement จาก Compose มาตรฐาน ไลบรารีเพิ่มเติมจำเป็นสำหรับวิถีที่ไม่ได้มาตรฐานหรือการประมวลที่ซับซ้อน

สรุป

  • Hero Animation คือการเปลี่ยนองค์ประกอบร่วมระหว่างหน้าจอที่รักษาความต่อเนื่องทางสายตาและลดภารด้านการรับรู้
  • Flutter Hero กับแท็กและ FlightShuttle เป็นวิธีที่ง่ายที่สุดในการนำไปใช้แอนิเมชั่นฮีโร่โดยไม่ต้องจัดการแอนิเมชั่นด้วยตนเอง
  • SwiftUI matchedGeometryEffect กับ @Namespace.id เปลี่ยนองตำแหน่ง ขนาด และรัศมีมุมขององค์ประกอบระหว่างสองสถานะ
  • Android SharedTransitionLayout กับ Modifier.sharedElement ใน Jetpack Compose ให้การเปลี่ยนองพร้อมการเก็บแคช RenderNode
  • ทั้งสามเฟรมเวิร์กรองรับองค์ประกอบร่วมหลายตัวกับแอนิเมชั่นแบบขนาน
  • FlightShuttle ช่วยให้ปรับแต่งวิถีการบินผ่าน flightShuttleBuilder ใน Flutter
  • Hero Animation ถูกแนะนำโดย Material Design สำหรับหน้าจอรายการ-รายละเอียด และการ์ด

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม