I'm working on a proof of concept app in SwiftUI and I came up with an idea for a settings pane looking like this:
Now I want the user to be able to tap the colored "Option X" to change the text. I thought I'd just replace Text() with TextField() but if I do this it produces a view like this:
Here is the code I'm using for the view:
HStack(){
Spacer()
ZStack{
Rectangle()
.fill(Color(txtBgCol!))
.frame(width: 300, height: 475)
.cornerRadius(25)
.shadow(radius: 3)
VStack{
Group{
Spacer()
// preset 1
TextField(presets[0].name, text: $presets[0].name)
//Text(presets[0].name)
.foregroundColor(.white)
.padding()
.background(presets[0].color)
.cornerRadius(200)
.shadow(radius: 3)
.font(.body)
Text("Some settings here")
.foregroundColor(Color(txtCol!))
.padding()
.font(.body)
}
Group{
Spacer()
// preset 2
Text(presets[1].name)
.foregroundColor(.white)
.padding()
.background(presets[1].color)
.cornerRadius(200)
.shadow(radius: 3)
.font(.body)
Text("Some settings here")
.foregroundColor(Color(txtCol!))
.padding()
.font(.body)
}
Group{
Spacer()
// preset 3
Text(presets[2].name)
.foregroundColor(.white)
.padding()
.background(presets[2].color)
.cornerRadius(200)
.shadow(radius: 3)
.font(.body)
Text("Some settings here")
.foregroundColor(Color(txtCol!))
.padding()
.font(.body)
}
Spacer()
}
}
Spacer().frame(width: 30)
}
I'm not sure why changing the Text() to TextField() would mess up everything and I'd be glad to learn more about SwiftUI intricacies, as I am pretty new to this.
TextField by default expands to max available width, so instead of limit only background rectangle, you should limit container
ZStack{
Rectangle()
.fill(Color(txtBgCol!))
.frame(width: 300, height: 475)
.cornerRadius(25)
.shadow(radius: 3)
VStack{
// .. other code here
}
.frame(width: 300, height: 475) // << this restricts TextField expanding
Related
I am creating a view that is a rectangle that contains an: image, name, subtitle.
I have these in a VStack with a frame. In this VStack, the views stack correctly. However, I want the subtitle (which is text) to always be stuck to the bottom of the VStack.
At the moment the subtitle is pushed up with the other views. I tried using Spacer's but these didn't seem to do the job (maybe I used them wrong???).
Here is the view:
VStack(alignment: .center, spacing: 0) {
Image("Image")
.resizable()
.aspectRatio(contentMode: .fit)
.clipped()
.padding()
.layoutPriority(1)
}
}
Text("Name")
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.black)
.minimumScaleFactor(0.5)
.multilineTextAlignment(.center)
.padding(.leading, 5)
.padding(.trailing, 5)
.padding(.bottom, 5)
Text("Subtitle")
.font(.caption)
.foregroundColor(.gray)
.lineLimit(2)
.padding(1)
}
.frame(width: 150, height: 200)
Any ideas?
Put the subtitle into an .overlay() of the VStack and use alignment: .bottom to push it to the bottom:
VStack(alignment: .center, spacing: 0) {
Image("Image")
.resizable()
.aspectRatio(contentMode: .fit)
.clipped()
.padding()
.layoutPriority(1)
Text("Name")
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.black)
.minimumScaleFactor(0.5)
.multilineTextAlignment(.center)
.padding(.leading, 5)
.padding(.trailing, 5)
.padding(.bottom, 5)
}
.frame(width: 150, height: 200)
.overlay(alignment: .bottom) {
Text("Subtitle")
.font(.caption)
.foregroundColor(.gray)
.lineLimit(2)
.padding(1)
}
I am trying to create a view that is a rectangle with text and images inside. This is done in a VStack. At the bottom of the VStack, I have an HStack where I have a small image and a number next to it. These need to be centred aligned but I can't seem to make that happen.
The image is higher up than the number. I need them to be at an equal height.
VStack(alignment: .center, spacing: 0) {
Image("ProductLogo")
.resizable()
.aspectRatio(contentMode: .fit)
.clipped()
.padding()
.layoutPriority(1)
Text("Text Here")
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.black)
.minimumScaleFactor(0.5)
.multilineTextAlignment(.center)
.padding(.leading, 5)
.padding(.trailing, 5)
.padding(.bottom, 5)
Text("Subtitle")
.font(.headline)
.foregroundColor(.gray)
.lineLimit(2)
.padding(1)
//HERE IS WHAT NEEDS TO BE ALIGNED
HStack {
Image("CoinImage")
.resizable()
.frame(width: 35, height: 35, alignment: .center)
Text("500")
.font(.system(size: 20))
.padding(.top,20)
}
//END OF HSTACK
}
Here is an image of the VStack:
The 500 should be level with the coin image
You just need to remove padding from Text("500") and set to HStack
Please try with below code and let me know it's works for you
VStack(alignment: .center, spacing: 0) {
Image("ProductLogo")
.resizable()
.aspectRatio(contentMode: .fit)
.clipped()
.padding()
.layoutPriority(1)
Text("Text Here")
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.black)
.minimumScaleFactor(0.5)
.multilineTextAlignment(.center)
.padding(.leading, 5)
.padding(.trailing, 5)
.padding(.bottom, 5)
Text("Subtitle")
.font(.headline)
.foregroundColor(.gray)
.lineLimit(2)
.padding(1)
//HERE IS WHAT NEEDS TO BE ALIGNED
HStack {
Image("CoinImage")
.resizable()
.frame(width: 35, height: 35, alignment: .center)
Text("500")
.font(.system(size: 20))
}.padding(.top, 10)
//END OF HSTACK
}
I'm creating an iOS minesweeper game and want to have a bar at the top with three pieces of information:
The high score (next to a trophy symbol) [LEFT]
The current time (next to a timer symbol) [CENTER]
The number of bombs left (next to a bomb symbol) [RIGHT]
However, the elements are not evenly aligned as you can see in the picture at the bottom- I'm guessing the spacers are automatically the same size. So, because the text on the left side of the screen is wider than that on the right, the middle text is offset to the right.
How can I align these items so the center time/image is perfectly in the middle with the other objects on the left/right?
My code looks like:
struct GameView: View {
#EnvironmentObject var game: Game
#State var labelHeight = CGFloat.zero
var body: some View {
VStack(alignment: .center, spacing: 10) {
Text("MINESWEEPER")
.font(.system(size: 25, weight: .bold, design: .monospaced))
.kerning(3)
.foregroundColor(.red)
HStack(alignment: .center, spacing: 5) {
Image(systemName: "rosette")
.resizable()
.aspectRatio(contentMode: .fit)
.foregroundColor(.black)
Text(game.highScoreString)
.font(.system(size: 15, weight: .bold, design: .monospaced))
.foregroundColor(.black)
Spacer()
Image(systemName: "timer")
.resizable()
.aspectRatio(contentMode: .fit)
.foregroundColor(.black)
Text(game.timerString)
.font(.system(size: 15, weight: .bold, design: .monospaced))
.foregroundColor(.black)
Spacer()
Image("top_bomb")
.resizable()
.aspectRatio(contentMode: .fit)
Text(String(game.bombsRemaining))
.font(.system(size: 15, weight: .bold, design: .monospaced))
.foregroundColor(.black)
.overlay(GeometryReader(content: { geometry in
Color.clear
.onAppear(perform: {self.labelHeight = geometry.frame(in: .local).size.height})
}))
}
.frame(width: UIScreen.main.bounds.width * 0.9, height: labelHeight, alignment: .center)
BoardView()
}
}
}
Instead of aligning by spacers, move each part into separate view, say LeftHeader, CenterHeader, and RightHeader and use frame alignment, which gives exact separation by equal sizes, like
HStack {
LeftHeader()
.frame(maxWidth: .infinity, alignment: .leading)
CenterHeader()
.frame(maxWidth: .infinity, alignment: .center)
RightHeader()
.frame(maxWidth: .infinity, alignment: .trailing)
}
This can be achieved using a ZStack , HStack and Spacers.
ZStack{
HStack{
Text("Left")
Spacer()
}
HStack{
Text("Center")
}
HStack{
Spacer()
Text("Right")
}
}
Even if you remove left ( or right ) HStack, it won't affect the other components or the layout.
You can make it look bit nicer by adding paddings like this,
ZStack{
HStack{
Text("Left").padding([.leading])
Spacer()
}
HStack{
Text("Center")
}
HStack{
Spacer()
Text("Right").padding([.trailing])
}
}
I think you can create more one stack.
My solution like:
/**
* spacing is an example
* minWidth calculated by fontSize
*/
HStack(alignment: .center, spacing: 20){
HStack{ Image, Text }.frame(minWidth: 30)
HStack{ Image, Text }.frame(minWidth: 30)
HStack{ Image, Text }.frame(minWidth: 30)
}
Hope it useful for you.
absolute greenhorn writing here:
i have a very basic app that does some calculations. It has only one view that has some Stacks in it that then contain text fields. underneath are two buttons and an image. when I now click on a text field, the view moves up and off the screen even though I want to make the keyboard over the buttons and image as I do not need them visible when the keyboard is active. I have tried to apply the .ignoresSafeArea(.keyboard)addition to basically everything in the view but it still does it.
Screenshot with Keyboard up
VStack{
Spacer()
HStack (alignment: .top){
VStack (alignment: .trailing, spacing:8){
Text("Volumenstrom")
.font(.body)
.fontWeight(.bold)
.multilineTextAlignment(.center)
.frame(height: 50)
.ignoresSafeArea(.keyboard)
Text("Geschwindigkeit")
.font(.body)
.fontWeight(.bold)
.multilineTextAlignment(.center)
.frame(height: 50)
.ignoresSafeArea(.keyboard)
Text("Kanalmaß A")
.font(.body)
.fontWeight(.bold)
.multilineTextAlignment(.center)
.frame(height: 50)
.ignoresSafeArea(.keyboard)
Text("Kanalmaß B")
.font(.body)
.fontWeight(.bold)
.multilineTextAlignment(.center)
.frame(height: 50)
.ignoresSafeArea(.keyboard)
Text("Durchmesser D")
.font(.body)
.fontWeight(.bold)
.multilineTextAlignment(.center)
.frame(height: 50)
.ignoresSafeArea(.keyboard)
}
VStack (alignment: .center){
TextField("0", text: $VolumenstromEingabe,
onCommit : { self.BerechungVG1(); self.BerechungVG2()} )
.textFieldStyle(RoundedBorderTextFieldStyle())
.modifier(ClearButton(text: $VolumenstromEingabe))
.frame(width: 100, height: 50)
.keyboardType(.numbersAndPunctuation)
.ignoresSafeArea(.keyboard)
TextField("0", text: $GeschwindigkeitEingabe,
onCommit: {self.BerechungVG1(); self.BerechungVG2()})
.textFieldStyle(RoundedBorderTextFieldStyle())
.modifier(ClearButton(text: $GeschwindigkeitEingabe))
.frame(width: 100, height: 50)
.keyboardType(.numbersAndPunctuation)
.ignoresSafeArea(.keyboard)
TextField("0", text: $KanalAEingabe,
onCommit: { self.BerechungVGA()})
.textFieldStyle(RoundedBorderTextFieldStyle())
.modifier(ClearButton(text: $KanalAEingabe))
.frame(width: 100, height: 50)
.keyboardType(.numbersAndPunctuation)
.ignoresSafeArea(.keyboard)
TextField("0", text: $KanalBEingabe,
onCommit: { self.BerechungVAB(); self.BerechungVGD()
})
.textFieldStyle(RoundedBorderTextFieldStyle())
.modifier(ClearButton(text: $KanalBEingabe))
.frame(width: 100, height: 50)
.keyboardType(.numbersAndPunctuation)
.ignoresSafeArea(.keyboard)
TextField("0", text: $KanalDErgebnis,
onCommit: { self.BerechungDg(); self.BerechungVG1()})
.textFieldStyle(RoundedBorderTextFieldStyle())
.modifier(ClearButton(text: $KanalDErgebnis))
.frame(width: 100, height: 50)
.keyboardType(.numbersAndPunctuation)
.ignoresSafeArea(.keyboard)
}
VStack (alignment: .leading, spacing: 8){
Text("in m³/h")
.font(.body)
.fontWeight(.bold)
.frame(height: 50)
.ignoresSafeArea(.keyboard)
Text("in m/s")
.font(.body)
.fontWeight(.bold)
.frame(height: 50)
.ignoresSafeArea(.keyboard)
Text("in mm")
.font(.body)
.fontWeight(.bold)
.frame(height: 50)
.ignoresSafeArea(.keyboard)
Text("in mm")
.font(.body)
.fontWeight(.bold)
.frame(height: 50)
.ignoresSafeArea(.keyboard)
Text("in mm")
.font(.body)
.fontWeight(.bold)
.frame(height: 50)
.ignoresSafeArea(.keyboard)
}
}
Button(action: {
self.ClearAll()
}) {
Text("Reset")}
Spacer()
HStack{
VStack{
Spacer()
Image("Logo Martin neu-60")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 80)
.padding()
.ignoresSafeArea(.keyboard)
Button(action: {
self.showingInfoSheet.toggle()
}) {
Text("Informationen")
.ignoresSafeArea(.keyboard)
}
.sheet(isPresented: $showingInfoSheet, content: {
ScrollView1()
})
Text("Luftkanalrechner v1.0, Build 6")
.padding()
.ignoresSafeArea(.keyboard)
}
}
}
I'm building an app and i'm a fairly beginner in SwiftUI, so this is the problem I have.
I need a landing page which shows first and I've created a view for it you can check it out.
struct LandingView: View {
var body: some View {
NavigationView{
VStack(alignment: .center){
Image("exxxlogo")
Spacer()
Text("Welcome")
.font(.system(size: 38))
.fontWeight(.bold)
.padding(.horizontal, 40)
.multilineTextAlignment(.center)
.foregroundColor(Color.white)
Text("Click below to continue to the app")
.font(.system(size: 16))
.padding(.horizontal, 20)
.multilineTextAlignment(.center)
.foregroundColor(Color.white)
.padding(.bottom, 35)
NavigationLink(destination: HomeView()){
Text("CONTINUE ")
.frame(width: 250, height: 50, alignment: .center)
.background(Color.red)
.foregroundColor(Color.white)
}
}
.background(
Image("backgroundlanding")
.frame(maxWidth: .infinity,maxHeight: .infinity)
.aspectRatio(contentMode: .fill)
.edgesIgnoringSafeArea(.top)
.edgesIgnoringSafeArea(.bottom)
)
}
And I've also created the views for the tabview to redirect them to so Home,Shop, etc
I've done this to my Contentview
TabView {
HomeView()
.tabItem{
Image(systemName: "house")
Text("Home")
}
GamesView()
.tabItem{
Image(systemName: "gamecontroller")
Text("Games")
}
ShopView()
.tabItem{
Image(systemName: "bag")
Text("Shop")
}
MoreView()
.tabItem{
Image(systemName: "gear")
Text("More")
}.accentColor(.red)
And changed the windowgroup to landingview in the main app.swift file so it pops up first.
But the issue is when you click on the button in landingview, navigationlink redirects you to the homeview but there is no tabviews underneath just blank
You said that your second code example is from ContentView. If you want to show the TabView that you have in that ContentView, then your NavigationLink should point to ContentView, not HomeView.
NavigationLink(destination: ContentView()) {
Text("CONTINUE ")
.frame(width: 250, height: 50, alignment: .center)
.background(Color.red)
.foregroundColor(Color.white)
}