Swift UI Button doesnt compile - swiftui

I am trying to understand SwiftUI and got stuck on a problem where Xcode refuses to compile.
I have no clue why it allows to add 2 buttons, but complains when adding a third one.
Couldn't find an answer on SO.
Here's the code:
import SwiftUI
struct LoginUI: View {
#State private var name = "dfdfdfdfdf"
#State private var logintitle = "LOGIN/LOGOUT"
#State private var xxx = 0
var body: some View {
VStack{
Text("login")
.font(.largeTitle)
.multilineTextAlignment(.center)
HStack {
VStack {
Text("loginusernametext")
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green)
VStack {
TextField(/*#START_MENU_TOKEN#*/"Placeholder"/*#END_MENU_TOKEN#*/, text: $name)
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green)
}
HStack {
VStack {
Text("loginpassword")
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green)
VStack {
TextField("Password", text: $name)
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green)
}
HStack {
VStack {
Text("databasereference")
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green)
VStack {
TextField("Database", text: $name)
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green)
}
HStack {
VStack {
Text("carplate")
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green)
VStack {
TextField("Database", text: $name)
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green)
}
HStack {
//GeometryReader { metrics in
// self.heigth = metrics.size.heigth
Button(action: {
self.doLogin()
}) {
Text(String("jaja"))
.font(.largeTitle)
.foregroundColor(.red)
.background(Color.blue)
}
//}
//Image("aa14b")
// .background(Color.green)
// .frame(minWidth: 0, maxWidth: 80, minHeight: 0, maxHeight: self.heigth, alignment: .topLeading)
Button(action: {
self.doPause()
}) {
Text(String(self.xxx))
.font(.largeTitle)
.foregroundColor(.red)
.background(Color.blue)
}
}
HStack {
Button(action: {
self.doLogin()
}) {
Text(String("odometerdelta"))
.font(.largeTitle)
.foregroundColor(.red)
}
}
HStack{
Text(String("Loginexplain"))
.font(.largeTitle)
.multilineTextAlignment(.center)
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
}
func loginauthdelta(){
}
func doPause(){
xxx += 1
}
func doLogin(){
}
struct LoginUI_Previews: PreviewProvider {
static var previews: some View {
LoginUI()
}
}
}
and here's the error
SO says: "
It looks like your post is mostly code; please add some more details.", dont knwo how much I have to write until that error message goes away. Never seen this message before...

SwiftUI has a hard limit on the number of elements in a view.
Try wrapping some of your top-level elements in a group...

Related

Split two columns into specific width percentages using SwiftUI

So I have been struggling on this for some time now, so I wanted to reach out and see if someone might be able to assist me.
So I have the following code:
HStack(alignment: .top, spacing: 3) {
VStack(alignment: .leading) {
Text("Location")
.font(.callout.weight(.semibold))
.lineLimit(1)
if item.address != "" {
Group {
Text(item.address)
Text(item.city + ", " + item.state)
}
.font(.footnote)
.foregroundColor(.secondary)
} else {
Text("N/A")
}
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
VStack {
HStack(alignment: .top, spacing: 3) {
VStack(alignment: .leading) {
Text("Weather")
.font(.subheadline.weight(.semibold))
.lineLimit(1)
HStack(spacing: 3) {
Image(systemName: "waveform")
.imageScale(.small)
.foregroundColor(.secondary)
Text("79%")
.font(.caption.weight(.regular))
.foregroundColor(.secondary)
}
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
VStack(alignment: .leading) {
Text("Reviews")
.font(.subheadline.weight(.semibold))
.lineLimit(1)
HStack(spacing: 3) {
Image(systemName: "star")
.imageScale(.small)
.foregroundColor(.secondary)
Text("4.7 (1212)")
.font(.caption.weight(.regular))
.foregroundColor(.secondary)
}
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
}
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
.border(.red)
}
Which outputs two main 50%/50% VStack columns:
What is the best way to have the two main VStack use 30%/70%?
I would like to have the first VStack be 30% of the screen view, then the second VStack be 70% of the screen view.
You could use GeometryReader to get the width of the main HStack and set the width of the child VStacks to a percentage of the width which can be accessed through GeometryReader
struct ContentView: View {
var body: some View {
GeometryReader { geometry in
HStack(alignment: .top, spacing: 3) {
firstVStack
.frame(width: geometry.size.width * 0.3)
secondVStack
.frame(width: geometry.size.width * 0.7)
}
}
}
private var firstVStack: some View {
VStack(alignment: .leading) {
Text("Location")
.font(.callout.weight(.semibold))
.lineLimit(1)
if item.address != "" {
Group {
Text(item.address)
Text(item.city + ", " + item.state)
}
.font(.footnote)
.foregroundColor(.secondary)
} else {
Text("N/A")
}
}
}
private var secondVStack: some View {
VStack {
HStack(alignment: .top, spacing: 3) {
VStack(alignment: .leading) {
Text("Weather")
.font(.subheadline.weight(.semibold))
.lineLimit(1)
HStack(spacing: 3) {
Image(systemName: "waveform")
.imageScale(.small)
.foregroundColor(.secondary)
Text("79%")
.font(.caption.weight(.regular))
.foregroundColor(.secondary)
}
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
VStack(alignment: .leading) {
Text("Reviews")
.font(.subheadline.weight(.semibold))
.lineLimit(1)
HStack(spacing: 3) {
Image(systemName: "star")
.imageScale(.small)
.foregroundColor(.secondary)
Text("4.7 (1212)")
.font(.caption.weight(.regular))
.foregroundColor(.secondary)
}
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
}
}
}
}

How do you center Text in ScrollView at SwiftUI

How do you center text here ?
Texts are at the left side of scrollViews.
What is .center for ?
var scrolls = ["One", "Two", "Three"]
VStack {
Spacer()
ForEach(0..<scrolls.count
, id: \.self) { index in
ScrollView(.horizontal, showsIndicators: true) {
Text(" \(scrolls[index])")
.frame(maxWidth: .infinity,
maxHeight: .infinity,
alignment: .center)
.background(Color.gray)
}
.frame(maxWidth: .infinity,
maxHeight:50,
alignment:
.center)
.background(Color.green)
}.frame(alignment: .bottom)
}
}
You can use GeometryReader and frame(minWidth: for that, like below.
Tested with Xcode 13.2 / iOS 15.2
var body: some View {
GeometryReader { gr in
VStack {
Spacer()
ForEach(0..<scrolls.count
, id: \.self) { index in
ScrollView(.horizontal, showsIndicators: true) {
Text(" \(scrolls[index])")
.frame(minWidth: gr.size.width, // << here !!
maxHeight: .infinity,
alignment: .center)
.background(Color.gray)
}
.frame(maxWidth: .infinity,
maxHeight:50,
alignment:
.center)
.background(Color.green)
}.frame(alignment: .bottom)
}
}
}

Limit the number of dots in Page Tab View Swiftui

I am trying to use the PageTabview option to allow a user to move through a series of pages whose data is coming from a JSON file. I want to be able to limit the number of visible dots to 5 or 6 even if there are many values in the field. What I don't want is to have 25 dots if there are twenty-five values in the field. How would I do that? I want to be able to show indicator like an arrow that tells the user there is more to come...Thank you.
My code is below:
struct TopicsExperienceCards: View {
#Binding var closeExperience: Bool
let etype: EItype
var body: some View {
//start of content of zstack layout
ZStack {
VStack(spacing: 20) {
HStack{
Rectangle()
.fill(Color.white)
.frame(width: 300, height: 1, alignment: .center)
Spacer()
Button(action: {
closeExperience = false })
{
Image(systemName:"xmark")
.foregroundColor(Color(etype.accentcolor))
.padding()
}
} //HSTACK
TabView {
ForEach(etype.experience,id: \.self) { item in
// Display the content of a card //
VStack (alignment:.center, spacing:0){
Text(item)
.padding()
.frame(width:300, height:300, alignment:.center)
Divider()
Spacer()
Text("Room for an image")
Spacer()
Spacer()
}//VSTACK
//End of display of content of the card //
} //: FOREACH
} //: TABVIEW
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
.onAppear {
setupAppearance() }
} //VSTACK
} //: ZStack
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
.background(Color.white)
.overlay(
RoundedRectangle(cornerRadius: 16)
.strokeBorder()
.foregroundColor(Color(etype.accentcolor)))
.cornerRadius(16.0)
.padding()
}
}
struct TopicsExperienceCards_Previews: PreviewProvider {
static let etypes: [EItype] = Bundle.main.decode("eibasestructure.json")
static var previews: some View {
TopicsExperienceCards(closeExperience:.constant(true),etype:etypes[1])
}
}
enter image description here
System dots view is limited to around 10 dots, maybe depending on the device. You can't change this value.
Instead of that you can hide system one, and create your own view with dots. As an example you can follow this article, so at the end you'll have something like this:
#State var currentIndex = 0
var body: some View {
//start of content of zstack layout
ZStack {
printUI(currentIndex)
VStack(spacing: 20) {
HStack{
Rectangle()
.fill(Color.white)
.frame(width: 300, height: 1, alignment: .center)
Spacer()
Button(action: {
closeExperience = false })
{
Image(systemName:"xmark")
.foregroundColor(Color.red)
.padding()
}
} //HSTACK
TabView(selection: $currentIndex.animation()) {
ForEach(etype.experience.indices,id: \.self) { i in
let item = etype.experience[i]
// Display the content of a card //
VStack (alignment:.center, spacing:0){
Text(item)
.padding()
.frame(width:300, height:300, alignment:.center)
Divider()
Spacer()
Text("Room for an image")
Spacer()
Spacer()
}//VSTACK
//End of display of content of the card //
} //: FOREACH
} //: TABVIEW
.tabViewStyle(PageTabViewStyle())
.onAppear {
setupAppearance()
}
Fancy3DotsIndexView(numberOfPages: etype.experience.count, currentIndex: currentIndex)
.padding()
.background(Color.green)
.clipShape(Capsule())
} //VSTACK
} //: ZStack
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
.background(Color.white)
.overlay(
RoundedRectangle(cornerRadius: 16)
.strokeBorder()
.foregroundColor(Color.red)
)
.cornerRadius(16.0)
.padding()
}
Result:

SwiftUI - remove space between TabView that has PageViewStyle

I have a TabView with 7 pages. Each one of the pages has 100 points less than the screen's width.
struct ContentView: View {
var body: some View {
GeometryReader { reader in
VStack(alignment: .center) {
TabView {
ForEach(0..<7) { index in
VStack {
}
.frame( maxHeight: .infinity)
.frame(width: reader.size.width - 100)
.background(Color.red)
.cornerRadius(15)
}
}
.background(Color.yellow)
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
.frame(width: reader.size.width, height: 500)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
TabView has as much as much width as the screen's width.
There are 50 points on both sides the Vstack's though each one of them has 100 points less than the screen width.
I need to remove the space between the red views.
how about something different using a "ScrollView" and a "HStack", like this:
struct ContentView: View {
var body: some View {
GeometryReader { reader in
ScrollView (.horizontal) {
HStack (spacing: 0) {
ForEach(0..<7) { index in
VStack {
Text("\(index)")
}
.frame(maxHeight: .infinity)
.frame(minWidth: reader.size.width - 100)
.background(Color.red)
.cornerRadius(20)
}
}.frame(maxWidth: .infinity, maxHeight: 500)
}.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
EDIT2: using paging
struct ContentView: View {
var body: some View {
GeometryReader { reader in
VStack(alignment: .center) {
TabView {
ForEach(0..<7) { index in
VStack {
Text("\(index)")
}
.frame(maxHeight: .infinity)
.frame(width: reader.size.width)
.background(Color.red)
.cornerRadius(25)
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
.frame(width: reader.size.width, height: 500)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}

Vertically centering text in Swift UI

I want the "$0.00" to be in the middle of the screen but I can't figure out how to do it.
This is my code:
var body: some View {
NavigationView {
ScrollView {
VStack(alignment: .center) {
Text(String(format: "$%.2f", (dolaresVM.dolares.last?.v)!))
.font(.largeTitle)
}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
}.navigationBarTitle("Test")
.onAppear(perform: self.dolaresVM.fetchDolares)
}
}
What am I doing wrong?
ScrollView has infinite inner space for its children. The VStack can't take all of this space. So VStack's height is defined by its content (in our case - Text).
Without ScrollView it will work like you want:
var body: some View {
NavigationView {
VStack(alignment: .center) {
Text(String(format: "$%.2f", 0)).font(.largeTitle)
}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
.navigationBarTitle("Test")
}
}
Providing idealHeight for the VStack can be helpful as well. You can use GeometryReader to get the 'outer' height of the ScrollView:
NavigationView {
GeometryReader { geometry in
ScrollView {
VStack(alignment: .center) {
Text(String(format: "$%.2f", 0)).font(.largeTitle)
}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, idealHeight: geometry.size.height, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
}.navigationBarTitle("Test")
}
}
As we discussed above, you don't need ScrollView so can write .navigationBarTitle("Test") inside NavigationView. So that NavigationBarTitle and Text("$0.00") both will be display on your screen.
Here i put static value of Text, you can replace it with dynamic value which you are setting up from your Model.
struct ContentView: View {
var body: some View {
NavigationView {
VStack(alignment: .center) {
Text("$0.00")
.font(.largeTitle)
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
.navigationBarTitle("Test")
}
}
}