Equal heights of subviews with SwiftUI - swiftui

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()
}
}
}
}
}

Related

Color behind the time on iOS

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)
}
}

SwifUI - Aligning items in a list

I'm trying to align a row in a list but can't work out the order that I need to place items in to get the desired results.
My current code is
HStack {
Image(imageName ?? "")
.renderingMode(.original)
.resizable()
.scaledToFit()
.frame(height: 72.0)
Text("**1**")
VStack {
Text("2")
Text("3")
Text("4")
}
VStack {
Text("5")
Text("6")
}
}
Currently this is giving me the below layout
But I'm trying to make it look like this
This is what you need:
struct ContentView: View {
var body: some View {
List {
HStack(spacing: 20.0) {
Image(systemName: "swift")
.resizable()
.scaledToFit()
.frame(height: 72.0)
VStack(alignment: .leading) {
Text("Name")
.bold()
HStack(alignment: .top) {
VStack {
Text("2")
Text("3")
Text("4")
}
VStack {
Text("5")
Text("6")
}
}
}
}
}
}
}
You just need more stacks to wrap things, like
HStack {
Image("picture")
.renderingMode(.original)
.resizable()
.scaledToFit()
.frame(height: 72.0)
VStack(alignment: .leading) { // << here !!
Text("Name").bold()
HStack(alignment: .top) { // << here !!
VStack {
Text("2")
Text("3")
Text("4")
}
VStack {
Text("5")
Text("6")
}
}
}
}
Tested with Xcode 14 / iOS 16

VStack space at top and bottom with lazyHGrid

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)
}
}

List rows not centered

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 !!

SwiftUI list row layout

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)
)
}
}