Basel
Basel

Reputation: 700

Text alignment won't work using AttributedString SwiftUI 3

I tried using the new AttributedString in SwiftUI 3

I want to change the alignment, but it won't work. Any things else is working fine, for example I tried change color using attributedString it does work !. But I cannot do anything with paragraphStyle

struct ContentView: View {
    var body: some View {
       
        ZStack {
            
            Color(uiColor: UIColor(red: 0.92, green: 0.92, blue: 0.92, alpha: 1.00)).ignoresSafeArea()
                        
            VStack {
                
                Text("""
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
""" ) { string in
                    let paragraphStyle = NSMutableParagraphStyle()
                    paragraphStyle.alignment = .right

                    string.paragraphStyle = paragraphStyle
                    
                    string.foregroundColor = .blue
                }
                    .padding()
                    .textSelection(.enabled)
                

                Spacer()
                
            }
            
        }
        
    }

}

extension Text {
init(_ string: String, configure: ((inout AttributedString) -> Void)) {
    var attributedString = AttributedString(string) /// create an `AttributedString`
    configure(&attributedString) /// configure using the closure
    self.init(attributedString) /// initialize a `Text`
}
}

enter image description here

Upvotes: 1

Views: 2861

Answers (3)

Basel
Basel

Reputation: 700

First Thank you Omer Tekbiyik you give me the idea how I can make it work.

The issue with TextAlignment is it depend on trailing and leading not left and right , that mean if your device on LTR Language the leading will be left and trailing will be right but on RTL it will be the opposite leading will be right and trailing will left.

So what I dd, first I check the text language itself if it's RTL or LTR by depended on NaturalLanguage, then I check the device layout using layoutDirection it's like using UIApplication.shared.userInterfaceLayoutDirection but on SwiftUI code.

Notice , this line will work if the text content one line of text.

.frame(maxWidth: .infinity, alignment: naturalAlignment)

but this line will work with text that continue multiple lines of text.

.multilineTextAlignment(naturalTextAlignment)

import SwiftUI
import NaturalLanguage

struct NaturalText: View {
    @Environment(\.layoutDirection) private var layoutDirection
    var text : String
    var body: some View {
            Text(text)
           .frame(maxWidth: .infinity, alignment: naturalAlignment)
            .multilineTextAlignment(naturalTextAlignment)
    }
    private var naturalAlignment: Alignment {
        guard let dominantLanguage = dominantLanguage else {
            // If we can't identify the strings language, use the system language's natural alignment
            return .leading
        }
        switch NSParagraphStyle.defaultWritingDirection(forLanguage: dominantLanguage) {
        case .leftToRight:
            if layoutDirection == .rightToLeft {
                return .trailing
            } else {
                return .leading
            }
        case .rightToLeft:
            if layoutDirection == .leftToRight {
                return .trailing
            } else {
                return .leading
            }
        case .natural:
            return .leading
        @unknown default:
            return .leading
        }
    }

    private var naturalTextAlignment: TextAlignment {
        guard let dominantLanguage = dominantLanguage else {
            // If we can't identify the strings language, use the system language's natural alignment
            return .leading
        }
        switch NSParagraphStyle.defaultWritingDirection(forLanguage: dominantLanguage) {
        case .leftToRight:
            if layoutDirection == .rightToLeft {
                return .trailing
            } else {
                return .leading
            }
        case .rightToLeft:
            if layoutDirection == .leftToRight {
                return .trailing
            } else {
                return .leading
            }
        case .natural:
            return .leading
        @unknown default:
            return .leading
        }
    }
    private var dominantLanguage: String? {
        let firstChar = "\(text.first ?? " ")"
           return NLLanguageRecognizer.dominantLanguage(for: firstChar)?.rawValue
    }
}

How to use it

struct ContentView: View {
    
    
    var body: some View {
        
        VStack {
        
            NaturalTextView(text: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.")
                .padding()

            
            NaturalTextView(text: "هذا النص هو مثال لنص يمكن أن يستبدل في نفس المساحة، لقد تم توليد هذا النص من مولد النص العربى، حيث يمكنك أن تولد مثل هذا النص أو العديد من النصوص الأخرى إضافة إلى زيادة عدد الحروف التى يولدها التطبيق.إذا كنت تحتاج إلى عدد أكبر من الفقرات يتيح لك مولد النص العربى زيادة عدد الفقرات كما تريد، النص لن يبدو مقسما ولا يحوي أخطاء لغوية، مولد النص العربى مفيد لمصممي المواقع على وجه الخصوص، حيث يحتاج العميل فى كثير من الأحيان أن يطلع على صورة حقيقية لتصميم الموقع.ومن هنا وجب على المصمم أن يضع نصوصا مؤقتة على التصميم ليظهر للعميل الشكل كاملاً،دور مولد النص العربى أن يوفر على المصمم عناء البحث عن نص بديل لا علاقة له بالموضوع الذى يتحدث عنه التصميم فيظهر بشكل لا يليق. هذا النص يمكن أن يتم تركيبه على أي تصميم دون مشكلة فلن يبدو وكأنه نص منسوخ، غير منظم، غير منسق، أو حتى غير مفهوم. لأنه مازال نصاً بديلاً ومؤقتاً.")
                .padding()

         
            Spacer()
        }
        
    }

}

The result

enter image description here

you can use

.environment(\.layoutDirection, .rightToLeft)

to force the layout to be RTL you will notice it won't change because it depend on the text language itself

Upvotes: 0

EmilioPelaez
EmilioPelaez

Reputation: 19884

The paragraphStyle attribute is defined in the UIKit scope but not on the SwiftUI, so you can't expect it to work.

The alternative is to use the modifier .multilineTextAlignment(.trailing).

Upvotes: 6

Omer Tekbiyik
Omer Tekbiyik

Reputation: 4744

As you said . AttributedString not working on SwiftUI . Actually Text satisfy doing everything AttributedString can.

paragraphStyle is useful if your text has more then 1 line. SwiftUI says. if you have 1 line use

  Text("bla bla").frame(maxWidth: .infinity, alignment: .trailing)

If you have text that can be more then 1 line use

 var body: some View {
   
    ZStack {
        
        Color(UIColor(red: 0.92, green: 0.92, blue: 0.92, alpha: 1.00)).ignoresSafeArea()
                    
        VStack{
          
            
            Text("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.")
           .frame(maxWidth: .infinity, alignment: .trailing)
           .multilineTextAlignment(textAlignment)
            

            Spacer()
            
        }
        
    }
    
}

let textAlignment: TextAlignment = {
    var textAlign = TextAlignment.trailing
    
    
    if UIApplication.shared.userInterfaceLayoutDirection == .leftToRight {
        textAlign = TextAlignment.trailing
       } else {
        textAlign = TextAlignment.leading
       }
    return textAlign
    
}()

Upvotes: 1

Related Questions