SwiftUI - RTL device languages don't display the expected RTL layout - ios

The following code:
struct ContentView: View {
var body: some View {
VStack {
Text("Hello, world!")
.padding(.leading, 150)
HStack {
Spacer()
.frame(width: 16)
Image(systemName: "pencil.circle.fill")
.resizable()
.frame(width: 100, height: 100)
Spacer()
}
}
}
}
looks like this when the system and app languages are set to a LTR language:
Oddly, if I set the device language to Arabic the layout is unchanged, it appears the same as English. The same problem if I set the app language to Arabic in "Edit scheme..." in Xcode.
However, if I set the app language to "Right-to-Left pseudolanguage" the layout is as expected for a RTL language:
Why is the expected RTL layout not shown when I set the device or app language to Arabic? How can I make my app display correctly on devices set to a RTL language?

Related

SwiftUI different behavior on different iOS versions

I have been developing an app with minimum iOS 13, but whole development process was done on iOS 15. Now when testing the iOS 13 devices, I noticed some problems.
Minimalistic example: You have a list of items, where each item contains leading icon, with a title and a subtitle vertically stacked. To adapt to various screen sizes, I attached a .minimumScaleFactor() to the texts so they would scale down when needed. That's working nicely on iOS 15. After a whole lot of testing, it also works on iOS 13.4 that is the oldest where I've got it working, so, iOS 13 - <13.4 is in question here.
On the screenshot you can see iPhone 8 13.3 vs iPhone 8 13.4, the text is scaled down even when there is space available. On iPhone 6s Plus 13.3 there is even more available space (screen size).
And the code:
struct Viewwww: View {
var title = "This is a title This is a title This is a title This is a title This is a title "
var subtitle = "This is a subtitle This is a subtitle This is a subtitle This is a subtitle This is a subtitle "
var body: some View {
VStack{
Text("Onboarding test").font(.title).multilineTextAlignment(.center).lineLimit(2)
Spacer()
buildItem()
buildItem()
buildItem()
buildItem()
buildItem()
Spacer()
}.padding(.horizontal, 20)
.padding(.top, 30)
}
#ViewBuilder
func buildItem() -> some View {
HStack(alignment: .top, spacing: 20){
VStack {
Image(systemName: "pin").resizable().scaledToFit().frame(width: 44, height: 44)
}
VStack(alignment: .leading, spacing: 10){
Text(title).font(Font.title).minimumScaleFactor(0.5)
Text(subtitle).font(Font.body).minimumScaleFactor(0.5)
}
Spacer()
}.frame(maxWidth: .infinity).background(Color.red)
}
}
So anyone has experienced this, and can help? Thank you!

SwiftUI - can I make one element in Form fill the whole screen width (without horizontal margins)?

I would like a single item inside SwiftUI Form to run from side to side, without having Form's default margins.
Unfortunately, whatever I do (like ading a wider .frame, negative horizontal padding, or .offset), the team image view seems to be always cropped by the form to fit the form area (= has horizontal margins).
Is it possible to make the Image below touch the left and right side of the screen?
I am using Form for my app settings, but I would like to add a full-width section there (think eg. a banner to promote a feature).
SwiftUI Playgrounds code:
import SwiftUI
import PlaygroundSupport
struct ContentView: View {
var body: some View {
Form {
Section(
header: Text("First section")
) {
Text("Hello world")
}
Text("The image below should be stretched to touch the left and right window edge, without being cropped by the Form.")
Image(systemName: "sun.max.fill")
.resizable()
.aspectRatio(contentMode: .fill)
.listRowInsets(EdgeInsets()) // this is supposed to fix the problem, but all it does is to set the default item inner padding to zero, so the image at least touches the edge of teal area.
.listRowBackground(Color.teal)
Section(
header: Text("Last section")
) {
Text("Hello world")
}
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
How it looks:
Unfortunately, SwiftUI Form is very temperamental and forces you to strictly adhere to the standard iOS Settings screen formatting.
Fortunately, you can re-implement similar formatting yourself with SwiftUI!
For the top, something like:
VStack(spacing: 4) {
Text("FIRST SECTION")
.font(.system(size: 12, weight: .regular))
.foregroundColor(.gray)
.padding(.leading)
Text("Hello, world!")
.font(.system(size: 15, weight: .regular))
.foregroundColor(.black)
.padding(.horizontal)
.frame(height: 44, alignment: .center)
.background(Color.white)
.cornerRadius(10)
}

In a SwiftUI VStack how do I make multiple Text Views, each with multiple lines of text, the same width

I'm trying to make the text in the VStack the same width but don't know how. I saw it suggested elsewhere to set a frame maxWidth to .infinity for each of the Text Views but it doesn't have any effect when I try it in my code.
This is the code I have:
struct ContentView: View {
var body: some View {
VStack(alignment: .center, spacing: 8.0) {
Spacer()
Text("Youngsters can play in Kids mode. If you're feeling very adventurous you can play in BigKids mode.")
.padding(.horizontal)
Text("Kids mode uses large images and big differences between the number of images shown.")
.padding(.horizontal)
Text("BigKids mode, on the other hand, uses small images and small differences between the number of images shown. Go for it!")
.padding(.horizontal)
Spacer()
}
.frame(maxWidth: 600.0)
}
}
I'm using a frame maxWidth of 600 for the VStack as I don't want it wider than that when an iPad is used.
Here's the results of the code. Note that each Text View is a different width.

How to align text within a SwiftUI ZStack for smaller screen sizes?

I'm attempting to align a Text view within a ZStack. It works fine for larger screens like the iphone 11 plus max but on smaller screens the text will go off screen if I use trailing or leading alignment like below. I get the same result on the preview, simulator and a real SE device.
iPhone SE (2nd gen) Screenshot showing misaligned text for photo attribution text.
import SwiftUI
struct ItemDetail: View {
var item: MenuItem
var body: some View {
VStack {
ZStack(alignment: .bottomTrailing) {
Image(item.mainImage)
Text("Photo: \(item.photoCredit)")
.padding(4)
.font(.caption)
.background(Color.black)
.foregroundColor(.white)
}
Text(item.description)
.padding()
Spacer()
}
.navigationBarTitle(Text(item.name), displayMode: .inline)
}
}
I think your code is good, the problem is that your image is too wide and it's overflowing on the right side of the screen. The text label is aligning correctly to the trailing of the image (that's why it works on bigger devices), not to the trailing of the screen (what you want).
You should make sure your image doesn't overflow.
Image(item.mainImage)
.resizable()
.scaleToFit()
I would use GeomteryReader. Just like that:
GeometryReader { geo in
Text(item.description)
.fixedSize(horizontal: false, vertical: true)
.frame(width: geo.size.width, alignment: .leading)
}

How to have back button of style being displayed in Apple App Store, on banner images?

I need to have back button which looks like the one displayed on any App's page in Apple App Store, having banner image. See image below:
I have tried finding any possible system icon image name as guided here:
https://stackoverflow.com/a/58900114/1152014
But couldn't find any appropriate one. Please guide.
The system icon image name is chevron.left.circle.fill (the one with fill color) and chevron.left.circle (the one without fill color)
By default the fill color is black, which you can change using the foreground color option.
import SwiftUI
struct ContentView: View {
var body: some View {
List {
Image(systemName: "chevron.left.circle.fill")
.resizable()
.frame(width: 50, height: 50, alignment: .center)
.listRowBackground(Color.green)
Text("")
Image(systemName: "chevron.left.circle")
.resizable()
.frame(width: 50, height: 50, alignment: .center)
.listRowBackground(Color.green)
}
.foregroundColor(.white)
}
}

Resources