Change interactivePopGestureRecognizer direction

1.4k views Asked by At

My app supports both English and Arabic. interactivePopGestureRecognizer works properly when using English, ie on swiping from left to right, it pops viewController. But when i am using arabic, I have changed the semanticContentAttribute from right to left.

if([[[NSUserDefaults standardUserDefaults] objectForKey:@"LanguageCode"] isEqualToString:@"en"])
    {
        [[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceLeftToRight];       //View for English language
    }
    else
    {
        [[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceRightToLeft];       //mirror view for Arabic language
    }

But the interactivePopGestureRecogniser is still from left to right. How can I change the direction of interactivePopGestureRecogniser such that it supports Arabic? I want to swipe from right to left to pop view controller on using Arabic language.

2

There are 2 answers

0
ytpm On

I found the solution for it after searching long time, if someone seeks.

The previous answer may cause the UI to hang / freeze.

The reason that the UI freezes / hangs is because the UINavigationController is missing a check for the root view controller when the gesture is executed on the root view. There a few ways to fix that, the following is what I did.

You should subclass UINavigationController, this is the right way to go and add implement as followed:

class RTLNavController: UINavigationController, UINavigationControllerDelegate, UIGestureRecognizerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        //  Adding swipe to pop viewController
        self.interactivePopGestureRecognizer?.isEnabled = true
        self.interactivePopGestureRecognizer?.delegate = self

        //  UINavigationControllerDelegate
        self.delegate = self
    }
    
    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
        navigationController.view.semanticContentAttribute = UIView.isRightToLeft() ? .forceRightToLeft : .forceLeftToRight
        navigationController.navigationBar.semanticContentAttribute = UIView.isRightToLeft() ? .forceRightToLeft : .forceLeftToRight
    }

    //  Checking if the viewController is last, if not disable the gesture
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if self.viewControllers.count > 1 {
            return true
        }
        
        return false
    }
}

extension UIView {
    static func isRightToLeft() -> Bool {
        return UIView.appearance().semanticContentAttribute == .forceRightToLeft
    }
}

Resources:

Original question:

The answer is used for the solution:

Other solution which may work better (But it's in Objective-C):

0
Amr Hossam On

After a lot of trials, the only solution worked for me was this:

Swift 3:

extension UIViewController {
    open override func awakeFromNib() {
        super.awakeFromNib()
        navigationController?.view.semanticContentAttribute = .forceRightToLeft
        navigationController?.navigationBar.semanticContentAttribute = .forceRightToLeft
    }
}

You can exclude the semantic attribute for certain types like:

UIView.appearance(whenContainedInInstancesOf: [UITableViewCell.self]).semanticContentAttribute = .forceLeftToRight