I am displaying some rows in a list (actually, 2 parallel lists in the example posted here), from a custom row view labeled EventRow.
In order to avoid bad UI on larger devices like an iPad, I limited the width of the EventRow to 200.
How could I get the EventRows to be centered in my lists on larger devices ?
I tried applying a .center alignment to the EventRows in the ForEach methods of my lists, tried doing the same on the lists as well, but nothing seems to work.
As an alternate solution, is there a way to set a MAX Spacer width ? I know you can set a minLength, but not a MAX it seems...
Here's a screenshot on the iPad Pro 11 sim :
The code for my EventRow file is as follows :
import SwiftUI
struct EventRow: View {
var body: some View {
VStack{
HStack {
Text("Text one")
Spacer()
Text("Text two")
}
HStack {
Spacer()
Image(systemName: "flame")
.font(.body)
Spacer()
} // END of second HStack
.padding(.top, -14)
} //END of Vstack
.frame(maxWidth: 200) // To limit width on larger devices
.listRowBackground(LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom))
}
}
struct EventRow_Previews: PreviewProvider {
static var previews: some View {
EventRow().previewLayout(.fixed(width: 300, height: 60))
}
}
And my ContentView :
struct ContentView: View {
struct listsSetup: ViewModifier {
func body(content: Content) -> some View {
return content
.frame(maxHeight: UIScreen.main.bounds.size.height/3)
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.blue, lineWidth: 1))
.padding([.top, .bottom])
}
}
#State private var selected : Int = 0
var body: some View {
VStack {
HStack {
VStack { // 1 list Vstack
VStack {
Text("List 1")
.padding(.top)
List {
EventRow()
EventRow()
} // END of 1st List
}
.modifier(listsSetup())
} // END of 1st list VStack
VStack { // 2nd Vstack
VStack {
Text("List 2")
.padding(.top)
List {
EventRow()
EventRow()
} // END of Landings List
}
.modifier(listsSetup())
} // End of 2nd List VStack
} // End of 1st & 2nd lists HStack
.padding(.top)
Spacer()
Picker("", selection: $selected){
Text("0").tag(0)
Text("1").tag(1)
}.pickerStyle(SegmentedPickerStyle())
Text("\(selected)")
} // END of VStack
} // END of body
}
Again, any help would be appreciated.
Just embed it in one more container, like below (tested with Xcode 11.4)
VStack {
VStack{
HStack {
Text("Text one")
Spacer()
Text("Text two")
}
HStack {
Spacer()
Image(systemName: "flame")
.font(.body)
Spacer()
} // END of second HStack
.padding(.top, -14)
} //END of Vstack
.frame(maxWidth: 200) // To limit width on larger devices
}.frame(maxWidth: .infinity) // << here !!
Related
This is my code:
struct Account: View {
var body: some View {
VStack {
ScrollView {
HStack {
Text("Account")
.font(.largeTitle)
.fontWeight(.bold)
Spacer(minLength: 0)
}
.padding()
.background(Color.indigo)
VStack {
Text("Doe, John Jack")
.font(.title)
Divider()
.foregroundColor(Color.indigo)
HStack {
Text("")
}
}
Spacer(minLength: 0)
VStack {
Button(action: {
}) {
Text("Log Out")
.foregroundColor(.red)
.fontWeight(.bold)
}
}
}
}
}
}
If you run the code above, you will see that the indigo doesn't go behind the time and battery precentage. How can I make it do that?
Try like this:
struct Account: View {
var body: some View {
VStack {
ScrollView {
HStack {
Text("Account")
.font(.largeTitle)
.fontWeight(.bold)
Spacer(minLength: 0)
}
.padding()
.background(Color.indigo)
VStack {
Text("Doe, John Jack")
.font(.title)
Divider()
.foregroundColor(Color.indigo)
HStack {
Text("")
}
}
Spacer(minLength: 0)
VStack {
Button(action: {
}) {
Text("Log Out")
.foregroundColor(.red)
.fontWeight(.bold)
}
}
}.padding(.top, 66)
}
.background(Color.indigo)
.edgesIgnoringSafeArea(.all)
}
}
You would also have to add some top padding to the ScrollView since ignoring safe area is going to push all your views to the margins
You should ignore the top safe area for this:
.ignoresSafeArea(.container, edges: .top)
Full working example
struct ContentView: View {
var body: some View {
Color
.indigo
.ignoresSafeArea(.container, edges: .top)
}
}
I have this example. Why is there this space at top and bottom of the VStack? The borders of the inner views doesn't seem to be as high as the border of the VStack. I think it has something to do with the LazyHGrid!? Thanks for an answer.
struct ContentView: View{
let names = ["house","creditcard"]
var body: some View{
VStack{
Text("skldfjsjf")
Text("klsadjf")
Text("lksajf")
ScrollView(.horizontal){
LazyHGrid(
rows: [GridItem(.flexible(minimum: 40)),GridItem(.flexible(minimum: 40))],
spacing: 10) {
ForEach(names, id: \.self) { icon in
Image(systemName: icon)
.padding()
}
}
.border(Color.orange)
}
.border(Color.green)
}
.frame(width: UIScreen.main.bounds.width * 0.9)
.border(Color.black)
}
}
I'm new to SwiftUI, but I think you want the content in your VStack to be top hugging?
struct ContentView: View {
let names = ["house","creditcard"]
var body: some View{
VStack (spacing:0) { //THIS HERE FOR NO SPACE FOR VSTACK INTERNAL VIEWS
Text("skldfjsjf")
Text("klsadjf")
Text("lksajf")
ScrollView(.horizontal){
LazyHGrid(
rows: [GridItem(.flexible(minimum: 40)),GridItem(.flexible(minimum: 40))],
spacing: 10) {
ForEach(names, id: \.self) { icon in
Image(systemName: icon)
.padding()
}
}
.border(Color.orange)
}
.border(Color.green)
Spacer() //THIS HERE TO MAKE IT TOP HUGGING
}
.frame(width: UIScreen.main.bounds.width * 0.9)
.border(Color.black)
}
}
Back with a couple of SwiftUI layout questions :
I'm trying to display 2 lists side by side with custom cells.
I created the cell views (EventRow.swift) and I display them in my content view.
I added a border to my lists, for better visibility.
As you can see from the picture below, the result is ghastly:
I would like the gradient effect to be applied to the whole cell, width and height wise.
I tried setting the frame of my EventRow (using .infinity for width and height), but this crashes the app.
Since the size of EventRow is inferred, I also don't know how to adapt my row cells height to its size : you can see the horizontal delimitating bars are not fitted to my custom EventRow...
If anyone has some pointers for this, it would be greatly appreciated.
The sample project can be found here
But I also post my code below:
ContentView :
import SwiftUI
struct ContentView: View {
struct listsSetup: ViewModifier {
func body(content: Content) -> some View {
return content
.frame(maxHeight: UIScreen.main.bounds.size.height/3)
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.blue, lineWidth: 1))
.padding([.top, .bottom])
}
}
var body: some View {
VStack {
HStack {
VStack { // 1 list Vstack
VStack {
Text("List 1")
.padding(.top)
List {
EventRow()
EventRow()
} // END of 1st List
}
.modifier(listsSetup())
} // END of 1st list VStack
VStack { // 2nd Vstack
VStack {
Text("List 2")
.padding(.top)
List {
EventRow()
EventRow()
} // END of Landings List
}
.modifier(listsSetup())
} // End of 2nd List VStack
} // End of 1st & 2nd lists HStack
.padding(.top)
Spacer()
} // END of VStack
} // END of body
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
EventRow :
import SwiftUI
struct EventRow: View {
var body: some View {
LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom)
.edgesIgnoringSafeArea(.all)
.overlay(
VStack{
HStack {
Text("Text one")
Spacer()
Text("Text two")
}
HStack {
Spacer()
Image(systemName: "flame")
.font(.body)
Spacer()
} // END of second HStack
.padding(.top, -14)
} //END of Vstack
)
}
}
struct EventRow_Previews: PreviewProvider {
static var previews: some View {
EventRow().previewLayout(.fixed(width: 300, height: 60))
}
}
Edit after trying Asperi's solution :
My actual EventRow code is as follows, and the listRowBackground modifier doesn't seem to have any effect :
import SwiftUI
import CoreData
struct EventRow: View {
var event: Events
var dateFormatter: DateFormatter {
let formatter = DateFormatter()
// formatter.dateStyle = .long
formatter.dateFormat = "dd MMM yy"
return formatter
}
var body: some View {
VStack{
HStack {
Text(event.airportName ?? "")
.font(.headline)
Spacer()
Text(self.dateFormatter.string(from: event.eventDate!))
.font(.body)
}
HStack {
Text(event.flightNumber ?? "")
.font(.body)
Spacer()
if event.isSimulator {
Image(systemName: "s.circle")
.font(.body)
} else {
Image(systemName: "airplane")
.font(.body
)
}
Spacer()
if event.aircraftType == 0 {
Text("")
.font(.body)
} else if event.aircraftType == 1 {
Text("330")
.font(.body)
} else if event.aircraftType == 2 {
Text("350")
.font(.body)
}
} // END of second HStack
.padding(.top, -14)
} //END of Vstack
.listRowBackground(LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom))
}
}
struct EventRow_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let newEvent = Events(context: context)
newEvent.eventDate = Date()
newEvent.aircraftType = 1
newEvent.airportName = "LDG tst"
newEvent.flightNumber = "AF TEST"
newEvent.id = UUID()
newEvent.isLanding = true
newEvent.isSimulator = false
return EventRow(event: newEvent).environment(\.managedObjectContext, context)
.previewLayout(.fixed(width: 300, height: 60))
}
}
Here is a solution to make gradient row-wide
struct EventRow: View {
var body: some View {
VStack{
HStack {
Text("Text one")
Spacer()
Text("Text two")
}
HStack {
Spacer()
Image(systemName: "flame")
.font(.body)
Spacer()
} // END of second HStack
.padding(.top, -14)
} //END of Vstack
.listRowBackground(LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom)
)
}
}
Equals heights of Image (square form) and TextOne with paddings. How can I do it without GeometryReader?
I can't use GeometryReader because I use this view as row of List
var body: some View {
return HStack {
VStack {
Image(systemName: "name").resizable().frame(width: ???, height: ???)
Spacer()
}
VStack {
HStack (alignment: .center) {
Text("TextOne").padding()
Spacer()
Text("TextTwo").padding()
}
HStack (alignment: .top) {
Text("TextDownOne").padding()
Spacer()
Button(action: { action() }) {
Text("ButtonText").padding()
}
}
}
}
}
I'm using Xcode 11 beta 5 and iPhone SE with iOS 13 beta 5.
In my app I have a NavigationView where each List row contains of two lines. I now want to add an Image(systemName: "circle") at the end of the text of the 2nd text line. When doing that, the space between the first and second text line increases.
I tried with adding using NSTextAttachment() as described in the WWDC19 session on SF Symbols, but the image isn't shown at all. See Section 1 in the code and screenshot.
I also tried using using Image(uiImage: UIImage(systemName: "circle")!), the image is shown but the space between the lines increased. See Section 2.
Also, for reference, when just using text, the line spacing as shown in Section 3 is what I want to have.
The code I used is:
import SwiftUI
struct ContentView: View {
func appendSymbol(string: String /*, image:UIImage*/ )-> String {
let mutableString = NSMutableAttributedString(string: string)
let circleImage = UIImage(systemName: "circle")
let redCircleImage = circleImage?.withTintColor(.red, renderingMode: .alwaysOriginal)
let circleAttachment = NSTextAttachment(image: redCircleImage!)
let circleString = NSAttributedString(attachment: circleAttachment)
mutableString.insert(circleString, at: 3)
return mutableString.string
}
var body: some View {
NavigationView {
List {
Section(header: Text("Section 1")) {
HStack {
VStack (alignment: .leading) {
HStack {
Text("Text 1.1")
}
.border(Color.red)
HStack {
Text(appendSymbol(string: "Tex t 1.2"))
}
.border(Color.green)
}
.border(Color.red)
}
.border(Color.red)
}
Section(header: Text("Section 2")) {
HStack {
VStack (alignment: .leading) {
HStack {
Text("Text 2.1")
}
.border(Color.red)
HStack {
Text("Text 2.2")
Image(uiImage: UIImage(systemName: "circle")!)
}
.border(Color.green)
}
.border(Color.red)
}
.border(Color.red)
}
Section(header: Text("Section 3")) {
HStack {
VStack (alignment: .leading) {
HStack {
Text("Text 3.1")
}
.border(Color.red)
HStack {
Text("Text 3.1")
Text("circle")
}
.border(Color.red)
}
.border(Color.red)
}
}
}
}
}
}
Screenshot using the included code
Any idea why the first code (Section 1) isn't working, and how to fix the spacing?
Simply try adding spacing after the alignment option of your VStack.
Example code for Section 2 would be like this:
Section(header: Text("Section 2")) {
HStack {
//adding the spacing option for the VStack
VStack (alignment: .leading, spacing: 0) {
HStack {
Text("Text 2.1")
}
.border(Color.red)
HStack {
Text("Text 2.2")
Image(uiImage: UIImage(systemName: "circle")!)
}
.border(Color.green)
}
.border(Color.red)
}
.border(Color.red)
}
You could also use
Image(systemName: "circle")
instead of
Image(uiImage: UIImage(systemName: "circle")!)