মূল বিষয়
Hero Animation একটি UI অ্যানিমেশন কৌশল যেখানে একটি শেয়ার্ড এলিমেন্ট মসৃণভাবে উৎস স্ক্রিন থেকে গন্তব্য স্ক্রিনে চলে যায়, তার পরিচয় বজায় রাখে। নামটি একটি “হিরো”-র রূপককে প্রতিফলিত করে — একটি মূল এলিমেন্ট যা স্ক্রিনের মধ্যে একটি স্ক্রিপ্টেড ট্রানজিশনের মধ্য দিয়ে যায়, ব্যবহারকারীর দৃষ্টি আকর্ষণ করে। স্ট্যান্ডার্ড ট্রানজিশনের বিপরীতে, Hero Animation ভিজ্যুয়াল সংযোগ ভাঙ্গে না: ব্যবহারকারী এলিমেন্টের একটি অবিচ্ছিন্ন গতিপথ দেখেন, যা নেভিগেশন ক্রমবিন্যাসের বোঝাপড়া উন্নত করে।
Hero Animation-এর ধারণা Material Design-এ তালিকা-বিবরণ স্ক্রিন, গ্যালারি এবং কার্ডের জন্য সুপারিশ হিসাবে প্রতিষ্ঠিত। অ্যানিমেশন অ্যালগরিদম তিনটি পর্যায় নিয়ে গঠিত: উৎস স্ক্রিনে, এলিমেন্টটি হাইলাইট করা হয় এবং একটি পরম অবস্থানে স্থির করা হয়; ট্রানজিশনের সময়, এটি লক্ষ্য কন্টেইনার অনুযায়ী স্কেল, স্থানান্তর এবং আকার পরিবর্তন করে; চূড়ান্ত স্ক্রিনে, এলিমেন্টটি নতুন লেআউটে এম্বেড করা হয়। Material Design 3 অনুসারে, সঠিকভাবে প্রয়োগ করা হিরো অ্যানিমেশন ভুল “পিছনে” বাটন চাপের সংখ্যা 22% হ্রাস করে।
Flutter-এ, Hero Animation Hero উইজেট-এর মাধ্যমে প্রয়োগ করা হয়, যা একটি বাধ্যতামূলক প্যারামিটার tag — একটি অনন্য শনাক্তকারী নেয়। Flutter স্বয়ংক্রিয়ভাবে উৎস এবং গন্তব্য রুটে একই ট্যাগ সহ Hero উইজেটের জুড়ি খুঁজে পায় এবং অ্যানিমেশন শুরু করে। Hero উইজেটের ম্যানুয়াল অ্যানিমেশন ব্যবস্থাপনার প্রয়োজন নেই — ফ্রেমওয়ার্ক স্বাধীনভাবে গতিপথ গণনা করে এবং অভ্যন্তরীণ FlightShuttle অবজেক্টের মাধ্যমে রূপান্তর প্রয়োগ করে।
FlightShuttle একটি অদৃশ্য “শাটল” যা ট্রানজিশনের মুহূর্তে, Hero উইজেটের একটি ওভারলে কপি তৈরি করে, এটি একটি পরম স্থানাঙ্ক ব্যবস্থায় স্থাপন করে এবং প্রাথমিক অবস্থান থেকে চূড়ান্ত পর্যন্ত রূপান্তর (স্কেল, ট্রান্সলেট, রোটেট) অ্যানিমেট করে। flightShuttleBuilder প্রপার্টির মাধ্যমে FlightShuttle-এ কাস্টম কার্ভ পাস করা যেতে পারে, যা উড়ানের গতিপথ নিয়ন্ত্রণ করতে দেয়: চাপে উড়া, সীমানা থেকে বাউন্স করা, বা আগমনের আগে ধীর হওয়া। Flutter 3.16+-এ, Hero clipRect এবং borderRadius সংরক্ষণ করে অ্যানিমেশন সমর্থন করে, যা গোলাকার কার্ডগুলিকে আয়তক্ষেত্রাকার স্ক্রিনে রূপান্তরিত করার প্রভাব দেয়।
SwiftUI-তে, Hero Animation-এর সমতুল্য হল matchedGeometryEffect মডিফায়ার, যা iOS 14-এ চালু করা হয়েছিল। এটি একটি শনাক্তকারী (id) এবং একটি namespace-এর মাধ্যমে দুটি এলিমেন্টকে সংযুক্ত করে। Flutter-এর বিপরীতে, যেখানে Hero স্বয়ংক্রিয়ভাবে ট্রানজিশন আটকায়, SwiftUI-তে namespace-এর স্পষ্ট ঘোষণা এবং দৃশ্যের উভয় অংশে — উৎস এবং গন্তব্য — একই ক্রমবিন্যাসের মধ্যে বা GeometryReader-এর মাধ্যমে মডিফায়ার প্রয়োগ প্রয়োজন।
matchedGeometryEffect অ্যানিমেশন অবস্থান, আকার, ঘূর্ণন এবং কোণের ব্যাসার্ধের রূপান্তর সমর্থন করে। মসৃণতার জন্য, withAnimation-এ একটি Animation নির্দিষ্ট করা হয়। SwiftUI ডিফল্ট easeInOut কার্ভের ভিত্তিতে মধ্যবর্তী অবস্থাগুলি স্বয়ংক্রিয়ভাবে ইন্টারপোলেট করে। iOS 17+-এ, TabView এবং NavigationStack-এর জন্য matchedTransitionSource-এর সমর্থন যুক্ত করা হয়েছে — মানক ট্রানজিশনের জন্য পূর্বনির্ধারিত গতিপথ সহ Hero Animation-এর একটি সিস্টেম অ্যানালগ।
Android-এ, Hero Animation কে Shared Element Transition বলা হয় এবং এটি ActivityOptions.makeSceneTransitionAnimation বা FragmentTransaction.addSharedElement-এর মাধ্যমে প্রয়োগ করা হয়। প্রতিটি শেয়ার্ড এলিমেন্ট XML-এ transitionName অ্যাট্রিবিউট বা কোডের মাধ্যমে চিহ্নিত করা হয়, এবং 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 স্ক্রলঅফসেট সংরক্ষণের সাথে তালিকা-থেকে-বিবরণ অ্যানিমেশন সমর্থন করে — Hero ট্রানজিশনের জন্য একটি মূল ক্ষমতা। Google I/O 2024 অনুসারে, Compose Shared Element Transition সরাসরি RenderNode ব্যবস্থাপনার কারণে View সংস্করণের তুলনায় 15% দ্রুত।
Flutter-এ Hero Animation-এর একটি মৌলিক উদাহরণ: তালিকা স্ক্রিনে একটি থাম্বনেইল এবং বিবরণ স্ক্রিনে একটি পূর্ণ-স্ক্রিন ছবি। ট্যাগ image-hero দুটি উইজেটকে সংযুক্ত করে, এবং FlightShuttle স্বয়ংক্রিয়ভাবে কার্ড থেকে ফুলস্ক্রিনে ট্রানজিশন অ্যানিমেট করে।
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 উইজেট মেলায়। যদি ট্যাগ ভিন্ন হয়, অ্যানিমেশন শুরু হবে না — এলিমেন্টটি ট্রানজিশন ছাড়াই নতুন স্ক্রিনে উপস্থিত হবে। ট্যাগের জন্য যেকোনো প্রকার ব্যবহার করা যেতে পারে, কিন্তু স্ট্রিং হল সবচেয়ে নির্ভরযোগ্য বিকল্প।
NavigationStack-এর সাথে SwiftUI-তে Hero Animation-এর একটি উদাহরণ। matchedGeometryEffect মডিফায়ার তালিকার ছবি এবং বিবরণ স্ক্রিনকে একটি namespace-এর মাধ্যমে সংযুক্ত করে, এবং withAnimation একটি মসৃণ ট্রানজিশন শুরু করে।
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 দুটি ভিউয়ের মধ্যে আকার, অবস্থান এবং কোণের ব্যাসার্ধের রূপান্তর অ্যানিমেট করে, হিরো প্রভাব তৈরি করে। iOS 16+-এর সাথে স্ট্যান্ডার্ড NavigationLink-এর জন্য, navigationTransition(.hero) ব্যবহার করুন।
SharedTransitionLayout-এর সাথে Jetpack Compose-এ Shared Element Transition-এর একটি উদাহরণ। sharedElement মডিফায়ার নেভিগেশনের সময় স্ক্রিনের মধ্যে একটি শেয়ার্ড এলিমেন্ট অ্যানিমেট করে।
@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+) ক্রমবিন্যাসটি মোড়ক করে, এবং “hero” কী-সহ sharedElement মডিফায়ার প্রাথমিক এবং চূড়ান্ত এলিমেন্টগুলিকে সংযুক্ত করে। AnimatedContent অবস্থা টগল করে, এবং Compose স্বয়ংক্রিয়ভাবে ছবির আকার, অবস্থান এবং আকৃতি অ্যানিমেট করে। একটি মূল সুবিধা হল bounds এবং clipBounds অ্যানিমেশনের জন্য সমর্থন, যা ট্রানজিশনের সময় কার্ড গোলাকার প্রভাব প্রদান করে।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
হ্যাঁ, Hero Animation উভয় প্ল্যাটফর্মেই উপলব্ধ। iOS SwiftUI-তে matchedGeometryEffect বা UINavigationController.transitioningDelegate ব্যবহার করে। Android ActivityOptions.makeSceneTransitionAnimation বা Jetpack Compose-এ Modifier.sharedElement-এর সাথে Shared Element Transition ব্যবহার করে। Flutter Hero উইজেটের মাধ্যমে Hero Animation প্রয়োগ করে, যা উভয় প্ল্যাটফর্মেই একইভাবে কাজ করে।
হ্যাঁ, Hero Animation একাধিক শেয়ার্ড এলিমেন্ট সমর্থন করে। Flutter-এ, বিভিন্ন ট্যাগ সহ একাধিক Hero উইজেট নির্দিষ্ট করুন। SwiftUI-তে, প্রতিটি এলিমেন্টে বিভিন্ন শনাক্তকারী সহ matchedGeometryEffect ব্যবহার করুন। সমস্ত অ্যানিমেশন সমান্তরালে চলে — প্রতিটি এলিমেন্ট তার নিজস্ব গতিপথে ভ্রমণ করে।
কর্মক্ষমতা বাস্তবায়নের উপর নির্ভর করে। Flutter FlightShuttle RenderObject-এর মাধ্যমে ছবি প্রক্রিয়া করে, 60fps অর্জন করে। SwiftUI matchedGeometryEffect ভেক্টরাইজড। বড় ছবির জন্য, Flutter-এ precacheImage বা SwiftUI-তে prefetch ব্যবহার করুন — এটি প্রথম ট্রানজিশনে বিলম্ব দূর করে। Android Compose-এ AsyncImage-এর মাধ্যমে বিলম্বিত লোডিং প্রয়োজন।
একটি স্ট্যান্ডার্ড push ট্রানজিশন পুরো স্ক্রিন স্লাইড করে, কার্ডের স্তুপের বিভ্রম তৈরি করে। Hero Animation দৃষ্টি আকর্ষণ স্থির করে একটি একক এলিমেন্টে — ব্যবহারকারী এর অবিচ্ছিন্ন গতি দেখেন, যা স্ক্রিনের মধ্যে সম্পর্কের বোঝাপড়া উন্নত করে। Push শ্রেণিবদ্ধ নেভিগেশনের জন্য ভাল, Hero বিষয়বস্তু জোর দেওয়ার জন্য।
না, Hero Animation অন্তর্নির্মিত সরঞ্জাম দিয়ে প্রয়োগ করা হয়েছে। Flutter-এ, এটি flutter/material.dart প্যাকেজ থেকে Hero উইজেট। SwiftUI-তে, এটি matchedGeometryEffect মডিফায়ার। Android Jetpack Compose-এ, এটি স্ট্যান্ডার্ড Compose থেকে SharedTransitionLayout এবং Modifier.sharedElement। অতিরিক্ত লাইব্রেরি শুধুমাত্র অ-মানক গতিপথ বা জটিল রূপান্তরের জন্য প্রয়োজন।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন