হয়তো কিছুটা দেরি হয়ে গেছে, তবে আমিও আগে একই আচরণ চাইছিলাম। এবং আমি যে সমাধানটি দিয়েছিলাম সেগুলি বর্তমানে অ্যাপ স্টোরের একটি অ্যাপ্লিকেশনে বেশ ভাল কাজ করে। যেহেতু আমি কাউকে একই পদ্ধতিতে যেতে দেখিনি, তাই আমি এখানে এটি ভাগ করে নিতে চাই। এই সমাধানটির খারাপ দিকটি এটির জন্য সাবক্লাসিংয়ের প্রয়োজন UINavigationController
। যদিও মেথড সুইজলিং ব্যবহার এড়াতে সহায়তা করতে পারে তবে আমি এতদূর যেতে পারিনি।
সুতরাং, ডিফল্ট পিছনে বোতামটি বাস্তবে পরিচালিত হয় UINavigationBar
। কোনও ব্যবহারকারী যখন পিছনের বোতামে ট্যাপ করেন, UINavigationBar
তার ডেলিগেটকে জিজ্ঞাসা করুন যে এটি UINavigationItem
কল করে শীর্ষে পপ করা উচিত navigationBar(_:shouldPop:)
। UINavigationController
বাস্তবে এটি বাস্তবায়ন করুন, তবে এটি UINavigationBarDelegate
(কেন !?) গ্রহণ করে তা প্রকাশ্যে ঘোষণা করে না । এই ইভেন্টটি আটকাতে, এর একটি সাবক্লাস তৈরি করুন UINavigationController
, এর সাথে সংযুক্তি ঘোষণা করুন UINavigationBarDelegate
এবং বাস্তবায়ন করুন navigationBar(_:shouldPop:)
। true
শীর্ষ আইটেম পপ করা উচিত যদি ফিরে । false
যদি এটি থাকা উচিত তবে ফিরে আসুন ।
দুটি সমস্যা আছে। প্রথমটি হ'ল আপনাকে অবশ্যই কোনও সময়ে UINavigationController
সংস্করণটি কল করতে হবে navigationBar(_:shouldPop:)
। তবে UINavigationBarController
প্রকাশ্যে এটিকে সামঞ্জস্যপূর্ণ হিসাবে ঘোষণা করে না UINavigationBarDelegate
, এটিকে কল করার চেষ্টা করার ফলে একটি সংকলন সময় ত্রুটি হবে। আমি যে সমাধানটি দিয়েছিলাম সেটি হ'ল অবজেক্টিভ-সি রানটাইমটি সরাসরি বাস্তবায়ন পেতে এবং এটিকে কল করতে। কারওর থেকে আরও ভাল সমাধান থাকলে দয়া করে আমাকে জানান।
অন্যান্য সমস্যাটি হ'ল যদি ব্যবহারকারীরা পিছনের বোতামে ট্যাপ করেন তবে navigationBar(_:shouldPop:)
প্রথমে তাকে অনুসরণ করা হয় popViewController(animated:)
। ভিউ কন্ট্রোলারকে কল করে পপ করা থাকলে অর্ডারটি বিপরীত হয় popViewController(animated:)
। এই ক্ষেত্রে, আমি এটির জন্য একটি বুলিয়ান ব্যবহার করি যা popViewController(animated:)
আগে কল করা হয়েছিল কিনা তার navigationBar(_:shouldPop:)
অর্থ ব্যবহারকারী পিছনের বোতামে ট্যাপ করেছেন।
এছাড়াও, আমি UIViewController
নেভিগেশন কন্ট্রোলারটিকে ভিউ কন্ট্রোলারটিকে জিজ্ঞাসা করতে দিতে বলি যে যদি ব্যবহারকারী পিছনের বোতামে ট্যাপ করে তবে পপ করা উচিত কিনা। দেখুন নিয়ন্ত্রকরা ফিরে আসতে পারেন false
এবং প্রয়োজনীয় ক্রিয়াগুলি করতে পারেন এবং popViewController(animated:)
পরে কল করতে পারেন ।
class InterceptableNavigationController: UINavigationController, UINavigationBarDelegate {
// If a view controller is popped by tapping on the back button, `navigationBar(_:, shouldPop:)` is called first follows by `popViewController(animated:)`.
// If it is popped by calling to `popViewController(animated:)`, the order reverses and we need this flag to check that.
private var didCallPopViewController = false
override func popViewController(animated: Bool) -> UIViewController? {
didCallPopViewController = true
return super.popViewController(animated: animated)
}
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
// If this is a subsequence call after `popViewController(animated:)`, we should just pop the view controller right away.
if didCallPopViewController {
return originalImplementationOfNavigationBar(navigationBar, shouldPop: item)
}
// The following code is called only when the user taps on the back button.
guard let vc = topViewController, item == vc.navigationItem else {
return false
}
if vc.shouldBePopped(self) {
return originalImplementationOfNavigationBar(navigationBar, shouldPop: item)
} else {
return false
}
}
func navigationBar(_ navigationBar: UINavigationBar, didPop item: UINavigationItem) {
didCallPopViewController = false
}
/// Since `UINavigationController` doesn't publicly declare its conformance to `UINavigationBarDelegate`,
/// trying to called `navigationBar(_:shouldPop:)` will result in a compile error.
/// So, we'll have to use Objective-C runtime to directly get super's implementation of `navigationBar(_:shouldPop:)` and call it.
private func originalImplementationOfNavigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
let sel = #selector(UINavigationBarDelegate.navigationBar(_:shouldPop:))
let imp = class_getMethodImplementation(class_getSuperclass(InterceptableNavigationController.self), sel)
typealias ShouldPopFunction = @convention(c) (AnyObject, Selector, UINavigationBar, UINavigationItem) -> Bool
let shouldPop = unsafeBitCast(imp, to: ShouldPopFunction.self)
return shouldPop(self, sel, navigationBar, item)
}
}
extension UIViewController {
@objc func shouldBePopped(_ navigationController: UINavigationController) -> Bool {
return true
}
}
এবং আপনি কন্ট্রোলার দেখুন, বাস্তবায়ন shouldBePopped(_:)
। আপনি যদি এই পদ্ধতিটি প্রয়োগ না করেন, ব্যবহারকারী স্বাভাবিকের মতো পিছনের বোতামে ট্যাপ করার সাথে সাথে ভিউ কন্ট্রোলারটিকে পপ করা হবে।
class MyViewController: UIViewController {
override func shouldBePopped(_ navigationController: UINavigationController) -> Bool {
let alert = UIAlertController(title: "Do you want to go back?",
message: "Do you really want to go back? Tap on \"Yes\" to go back. Tap on \"No\" to stay on this screen.",
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: nil))
alert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { _ in
navigationController.popViewController(animated: true)
}))
present(alert, animated: true, completion: nil)
return false
}
}
আপনি আমার ডেমোটি এখানে দেখতে পারেন ।