@FocusState হলো SwiftUI-তে একটি property wrapper, যা iOS 15-এ প্রবর্তিত হয়েছে, যা আপনাকে টেক্সট ফিল্ড এবং অন্যান্য এলিমেন্টে ইনপুট ফোকাস প্রোগ্রাম্যাটিকভাবে নিয়ন্ত্রণ করতে দেয়। এর আগমনের আগে, ডেভেলপারদের UIKit মেথড becomeFirstResponder এবং resignFirstResponder অ্যাক্সেস করতে UIViewRepresentable ব্যবহার করতে হতো। @FocusState এই সমস্যাটি নেটিভভাবে সমাধান করে: আপনি .focused() মডিফায়ারের মাধ্যমে একটি প্রপার্টিকে ফিল্ডের সাথে বাঁধেন, যার পরে ফোকাস সেট বা রিসেট করা একটি সাধারণ ভ্যালু অ্যাসাইনমেন্টের মাধ্যমে হয়। Apple Developer Documentation — FocusState (2025) অনুসারে, @FocusState দুটি মোড সমর্থন করে: সহজ ব্যবস্থাপনার জন্য Bool (ফোকাস অন বা অফ) এবং একাধিক ফিল্ডের জন্য enum, যেখানে প্রতিটি কেস একটি নির্দিষ্ট ইনপুট ফিল্ডের সাথে মিলে যায়।
মূল পয়েন্ট
@FocusState হলো একটি property wrapper যা ফোকাস অবস্থাকে SwiftUI-তে একটি নির্দিষ্ট ইনপুট ফিল্ড বা অন্য ফোকাসযোগ্য এলিমেন্টের সাথে বাঁধে। UIKit-এর বিপরীতে, যেখানে ফোকাস ব্যবস্থাপনা becomeFirstResponder এবং resignFirstResponder মেথডের মাধ্যমে হয়, SwiftUI একটি ঘোষণামূলক পদ্ধতি ব্যবহার করে: আপনি একটি অবস্থা (@FocusState) ঘোষণা করেন এবং এটি .focused() মডিফায়ারের মাধ্যমে একটি এলিমেন্টের সাথে বাঁধেন। অবস্থা পরিবর্তন করলে স্বয়ংক্রিয়ভাবে ফোকাস পরিবর্তিত হয়।
iOS 15-এ @FocusState প্রবর্তনের আগে, ডেভেলপারদের UITextField-এর চারপাশে UIViewRepresentable র্যাপার তৈরি করতে বা থার্ড-পার্টি লাইব্রেরি ব্যবহার করতে হতো। @FocusState সরাসরি SwiftUI-তে সমন্বিত এবং TextField, TextEditor, SecureField এবং SearchField-এর সাথে কাজ করে। এটি কোড পরিষ্কার করে, UIKit ব্রিজের সংখ্যা কমায় এবং পরীক্ষাযোগ্যতা উন্নত করে।
WWDC Session 10136 — What's new in SwiftUI (2024) অনুসারে, @FocusState এলিমেন্টের মধ্যে ফোকাস তথ্য পাস করতে SwiftUI-এর preference key সিস্টেম ব্যবহার করে। যখন একটি ফিল্ড ফোকাস পায়, SwiftUI স্বয়ংক্রিয়ভাবে সম্পর্কিত @FocusState প্রপার্টি আপডেট করে, যা আপনাকে কোডে ফোকাস পরিবর্তনে প্রতিক্রিয়া জানাতে দেয়।
@FocusState ব্যবহারের সবচেয়ে সহজ উপায় হলো Bool টাইপের সাথে। যখন একটি ফিল্ড ফোকাসে থাকে, প্রপার্টিটি true হয়। যখন ফোকাস চলে যায় — false। আপনি true সেট করে ফোকাস জোর করতে পারেন, বা false সেট করে তা সরাতে পারেন।
struct LoginForm: View {
@State var email = ""
@FocusState var isEmailFocused: Bool
var body: some View {
VStack {
TextField("Email", text: $email)
.focused($isEmailFocused)
Button("কীবোর্ড দেখান") {
isEmailFocused = true
}
Button("কীবোর্ড লুকান") {
isEmailFocused = false
}
}
}
}
এই উদাহরণে, isEmailFocused স্বয়ংক্রিয়ভাবে true হয় যখন ব্যবহারকারী টেক্সট ফিল্ডে ট্যাপ করে, এবং কীবোর্ড লুকালে false হয়। বাটনগুলি আপনাকে প্রোগ্রাম্যাটিকভাবে ফোকাস পরিচালনা করতে দেয় — কাস্টম কীবোর্ড, "পরবর্তী" বাটন এবং ফর্ম জমা দেওয়ার পরে জোর করে কীবোর্ড লুকানোর প্রয়োজন হয় এমন পরিস্থিতির জন্য উপযোগী।
একাধিক ফিল্ডের ফর্মের জন্য, @FocusState FocusStateValue (বা Hashable) প্রোটোকল অনুসরণকারী enum সমর্থন করে। প্রতিটি enum কেস একটি নির্দিষ্ট ফিল্ডের সাথে মিলে যায়। এটি ফিল্ডের মধ্যে ফোকাস স্যুইচ করতে দেয় — উদাহরণস্বরূপ, যখন ব্যবহারকারী পরবর্তী ফিল্ডে যেতে কীবোর্ডে "পরবর্তী" টিপে।
struct RegistrationForm: View {
enum Field: Hashable {
case email
case password
case confirmPassword
}
@State var email = ""
@State var password = ""
@State var confirmPassword = ""
@FocusState var focusedField: Field?
var body: some View {
Form {
TextField("Email", text: $email)
.focused($focusedField, equals: .email)
.onSubmit { focusedField = .password }
SecureField("Password", text: $password)
.focused($focusedField, equals: .password)
.onSubmit { focusedField = .confirmPassword }
SecureField("Confirm", text: $confirmPassword)
.focused($focusedField, equals: .confirmPassword)
.onSubmit { submitForm() }
}
}
}
.onSubmit মডিফায়ারটি লক্ষ্য করুন — এটি কল করা হয় যখন ব্যবহারকারী কীবোর্ডে "Return" টিপে। .onSubmit-এর ভিতরে আমরা focusedField-কে পরবর্তী ফিল্ডে স্যুইচ করি, যা স্বয়ংক্রিয়ভাবে ফোকাস স্থানান্তর করে। শেষ ফিল্ডটি ফর্ম জমা দিতে submitForm() কল করে।
@FocusState কীবোর্ড লুকানোর একটি সহজ উপায় প্রদান করে — শুধু প্রপার্টিটি nil (enum-এর জন্য) বা false (Bool-এর জন্য) সেট করুন। তবে, কখনও কখনও আপনাকে একটি নির্দিষ্ট ফিল্ডের সাথে বাঁধা ছাড়াই কীবোর্ড লুকানোর প্রয়োজন হয় — উদাহরণস্বরূপ, খালি জায়গায় ট্যাপ করার সময়। এই ক্ষেত্রে, বেশ কয়েকটি পদ্ধতি আছে।
struct DismissKeyboardView: View {
@State var text = ""
@FocusState var isFocused: Bool
var body: some View {
TextField("Enter text", text: $text)
.focused($isFocused)
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button("সম্পন্ন") {
isFocused = false
}
}
}
}
}
placement .keyboard সহ .toolbar মডিফায়ার কীবোর্ডের উপরে একটি বাটন যোগ করে। কীবোর্ড লুকানোর জন্য iOS-এ এটি একটি মানক UX প্যাটার্ন। একটি বিকল্প পদ্ধতি হলো ব্যাকগ্রাউন্ডে ট্যাপ করার সময় ফোকাস রিসেট করতে রুট VStack-এ .onTapGesture ব্যবহার করা।
@FocusState ফর্ম বৈধতার সাথে পুরোপুরি সমন্বিত হয়। একটি সাধারণ প্যাটার্ন: "জমা দিন" বাটন চাপার পরে, সব ফিল্ড বৈধতা যাচাই করুন এবং প্রথম ত্রুটিপূর্ণ ফিল্ডে ফোকাস সেট করুন। এটি ব্যবহারকারীর অভিজ্ঞতা উন্নত করে — ব্যবহারকারী সাথে সাথে দেখতে পায় কোন ফিল্ডটি সংশোধন করতে হবে।
struct ValidatedForm: View {
enum Field: Hashable { case name; case phone }
@State var name = ""
@State var phone = ""
@FocusState var focusedField: Field?
@State var errors: [String] = []
var body: some View {
Form {
TextField("Name", text: $name)
.focused($focusedField, equals: .name)
TextField("Phone", text: $phone)
.focused($focusedField, equals: .phone)
Button("জমা দিন") { validateAndSubmit() }
}
}
func validateAndSubmit() {
if name.isEmpty {
focusedField = .name
return
}
if phone.isEmpty {
focusedField = .phone
return
}
// ফর্ম জমা দিন
}
}
এই উদাহরণে, যদি name ফিল্ড খালি থাকে, ফোকাস সেটির দিকে চলে যায়, এবং ব্যবহারকারী সাথে সাথে দেখতে পায় ত্রুটিটি কোথায়। যদি name পূর্ণ থাকে, phone যাচাই করা হয়। এটি ফর্মের জন্য স্বাভাবিক আচরণ — ব্যবহারকারী ওপর থেকে নিচে ফিল্ড পূরণ করে, এবং বৈধতা একই ক্রম অনুসরণ করে।
সবচেয়ে সাধারণ ভুল হলো Hashable-এর অনুসরণ করে না এমন একটি টাইপের সাথে @FocusState ব্যবহার করার চেষ্টা করা। @FocusState-এর জন্য প্রপার্টি টাইপ Hashable হওয়া প্রয়োজন (Bool এবং অপশনাল enums ইতিমধ্যেই অনুসরণ করে)। যদি আপনি একটি কাস্টম স্ট্রাকচার ব্যবহার করার চেষ্টা করছেন, নিশ্চিত করুন যে এটি Hashable বাস্তবায়ন করে।
// ❌ ভুল: enum-এর পরিবর্তে দুটি @FocusState Bool
@FocusState var isNameFocused: Bool
@FocusState var isEmailFocused: Bool
// ✅ সঠিক: একক enum @FocusState
enum Field: Hashable { case name; case email }
@FocusState var focusedField: Field?
প্রায়শই জিজ্ঞাসিত প্রশ্ন
@FocusState iOS 15, iPadOS 15, macOS 12, tvOS 15 এবং watchOS 8 থেকে উপলব্ধ। iOS 14 এবং তার নিচে সমর্থন করে এমন প্রকল্পগুলির জন্য, UITextField এবং becomeFirstResponder-এর সাথে UIViewRepresentable ব্যবহার করুন, অথবা কাস্টম ফোকাস ব্যবস্থাপনা বাস্তবায়ন সহ থার্ড-পার্টি লাইব্রেরি ব্যবহার করুন।
হ্যাঁ, এর জন্য কাস্টম UIViewRepresentable-এ UIViewRepresentable প্রোটোকলের মাধ্যমে FocusState সমর্থন বাস্তবায়ন করতে হবে। কাস্টম View-এ becomeFirstResponder এবং resignFirstResponder থাকতে হবে। আপনি যদি .focused() মডিফায়ার নির্দিষ্ট করেন তবে SwiftUI স্বয়ংক্রিয়ভাবে @FocusState-কে এই মেথডগুলির সাথে সংযুক্ত করবে।
List বা Form-এ, কোষগুলি পুনরায় ব্যবহার করা যেতে পারে, যা ফিল্ডের সাথে @FocusState বাইন্ডিং ভেঙে দেয়। সমাধান: প্রতিটি TextField-এর জন্য একটি অনন্য শনাক্তকারী সহ .id() মডিফায়ার যোগ করুন। উদাহরণস্বরূপ: .id(fieldName)। এটি SwiftUI-কে প্রতিটি ফিল্ডের জন্য একটি পৃথক View ইন্সট্যান্স তৈরি করতে বাধ্য করে।
রুট কন্টেইনারে (VStack, ZStack) .onTapGesture যোগ করুন এবং ফোকাস রিসেট করুন: focusedField = nil। তবে, .onTapGesture ভিতরের বাটনে ট্যাপ ব্লক করতে পারে — .contentShape(Rectangle()) সহ কন্টেইনার এবং তার উপর .onTapGesture ব্যবহার করুন, অথবা কাস্টম UIKitBackgroundView ব্যবহার করুন।
@FocusState কীবোর্ড অ্যানিমেশনের জন্য সরাসরি API প্রদান করে না — এটি iOS সিস্টেমের আচরণ। তবে, আপনি কাস্টম কন্টেন্ট অ্যানিমেশনের জন্য .onChange(of: focusedField) বা .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification))-এর মাধ্যমে ফোকাস পরিবর্তনে প্রতিক্রিয়া জানাতে পারেন।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন