semanticContentAttribute is not working
Asked Answered
P

5

10

In my app there is three languages i.e. ar , fr & en. And Based on the app language is changing the app language and semantics.

In my app, app language is properly changed as per the requirement but its semantics is not changing.

Here is the tried code what I am doing when user changed the language.

let cur_lang = Localize.currentLanguage()
    print("current lang; \(cur_lang)")
    if cur_lang == "ar"{
        UIView.appearance().semanticContentAttribute = .forceRightToLeft
    }
    else{
        UIView.appearance().semanticContentAttribute = .forceLeftToRight
    }

    imgView.image = UIImage(named: "flag".localized())
    lblTitle.text = "Title".localized()
    lblDescription.text = "Description".localized()
    lblName.text = "Name".localized()
    tfName.text = "textName".localized()

Here is the gif of the screen.

enter image description here

Required Output:

enter image description here

Edit

If I take all contents in a view , then it is working as expected but natural text alignment and navigation bar is still uneffected.

It is not possible to flip each and every view as it may reduce app performance if there is complex layout.

So I tried self.view.semanticContentAttribute = .forceRightToLeft and it does not make any difference.

My every UI component have leading trailing not left right and respect language direction is also selected.

enter image description here

Perdure answered 14/3, 2018 at 12:26 Comment(7)
UIAppearance doc: "iOS applies appearance changes when a view enters a window, it doesn’t change the appearance of a view that’s already in a window. To change the appearance of a view that’s currently in a window, remove the view from the view hierarchy and then put it back."Chloromycetin
@Chloromycetin Can you please let me know how to do this. I already tired of google searches I didn't found any solution.Perdure
You need to "reload" the view (remove them and reenter) if you want UIView.appearance().semanticContentAttribute = ... to work.Chloromycetin
@Chloromycetin I already tried UIView.appearance().semanticContentAttribute , if you see my code above. It does not make any change in UI. And i din't fount any other way to do this. Now either I have to use pseudo language (it does not make any sense in real - app) or change each and every UI with loop (it reduces app performance).Perdure
you either do loop or reload the VCMerrell
@Sh_Khan I already know this solution before posting the question. I wanted avoid this bcz if UI is complex and heavy then it is not a good practice (think about it). second thing is that natural text alignment is not working expected and at last navigation controller still be at same position (button).Perdure
in most cases you don't have to flip all the layout it's always some part , so hold a reference to the parent view of that part and control it's semantic & change the alignment manually if ---- selection is not workingMerrell
O
9
  1. First step, you need to apply the semantic content attribute as mentioned in the other answers.

    // get current language using your 'Localize' class
    let locale = Localize.currentLanguage()
    UIView.appearance().semanticContentAttribute = locale == "ar" ? .forceRightToLeft : .forceLeftToRight
    

    However, this alone would not work because based on Apple's Doc:

    iOS applies appearance changes when a view enters a window, it doesn’t change the appearance of a view that’s already in a window. To change the appearance of a view that’s currently in a window, remove the view from the view hierarchy and then put it back.

  2. The second step is in the doc itself. You only need to remove the view from the view hierarchy and then put it back.

    let window = self.view.superview
    self.view.removeFromSuperview()
    window?.addSubview(self.view)
    

    Note: Since self.view is already instantiated and you're only removing it from the view hierarchy and putting it back, you don't need to worry about recreating the view from scratch. :)

Voila!

Osteotomy answered 5/2, 2019 at 19:6 Comment(0)
T
7

Swift 4.2, 5.0

        if isArabic {
            UIView.appearance().semanticContentAttribute = .forceRightToLeft
            UIButton.appearance().semanticContentAttribute = .forceRightToLeft
            UITextView.appearance().semanticContentAttribute = .forceRightToLeft
            UITextField.appearance().semanticContentAttribute = .forceRightToLeft
        } else {
            UIView.appearance().semanticContentAttribute = .forceLeftToRight
            UIButton.appearance().semanticContentAttribute = .forceLeftToRight
            UITextView.appearance().semanticContentAttribute = .forceLeftToRight
            UITextField.appearance().semanticContentAttribute = .forceLeftToRight
        }
Talmud answered 21/1, 2020 at 8:48 Comment(0)
M
4

Another way to solve this problem is put your condition code in

override func viewWillLayoutSubviews() {
        if Language.language == .arabic {
            DispatchQueue.main.async {
                self.inputTextField.semanticContentAttribute = .forceRightToLeft
                self.inputTextField.textAlignment = .right
            }

        } else {
            DispatchQueue.main.async {
                self.inputTextField.semanticContentAttribute = .forceRightToLeft
                self.inputTextField.textAlignment = .left
            }
        }
    }

Simply work ;)

Marvelous answered 5/2, 2021 at 12:49 Comment(0)
M
1

Semantic content attribute must be applied to the direct parent of the view you want to flip when change the language , so do this for the parent view of flag imageV and the 2 labels

self.directParentView.semanticContentAttribute = .forceRightToLeft
Merrell answered 14/3, 2018 at 12:29 Comment(6)
So you are saying I have to apply semanticContentAttribute on each and every uiview?Perdure
even natural text aligment is also not working.Perdure
one fast way is to loop through all subviews for the self.view and change there semantic , also for every subviews inside the subview , i mean recursionMerrell
i will make a demo for your caseMerrell
If I take all contents in a view , then it is working as expected (I already tried) but natural text alignment and navigation bar is still uneffected.Perdure
they must have leading & trailing constraints to be flippedMerrell
I
0

for textFields - use can use extension like this:

extension UITextField {
 open override func awakeFromNib() {
        super.awakeFromNib()
        if UserDefaults.languageCode == "ar" {
            if textAlignment == .natural {
                self.textAlignment = .right
            }
        }
    }
}
Inure answered 20/8, 2018 at 6:7 Comment(1)
Its not all about text, its UI. Every thing must be from right to leftPerdure

© 2022 - 2024 — McMap. All rights reserved.