I am new to SwiftUI and I would some assistance with regards positioning of a Custom Button which I am unable to to centre.
I have used VStack and HStack to try and get the button bottom centered, but button keeps aligning left.
Any assistance will be appreciated.
struct ContentView: View {
var body: some View {
VStack {
NavigationView {
Section {
VStack(alignment: .leading) {
Text("Meal Description").foregroundColor(.green)
Spacer()
NavigationLink(destination: PoundedYam()) {
Text("Pounded Yam & Egusi Soup")
}
NavigationLink(destination: YamPepSoup()) {
Text("Yam and Pepper Soup")
}
NavigationLink(destination: JollofRice()) {
Text("Jollof Rice & Plantain")
}
Spacer()
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
}.padding()
}
Section {
Image("africanfoods")
.resizable()
.frame(width: 275.0, height: 250.0)
.clipShape(Circle())
.overlay(Circle().stroke(Color.black, lineWidth: 5))
.scaledToFit()
}
VStack { //For Button
Spacer()
Button( action: {},
label: { Text("Create Order") })
}
.navigationBarTitle(Text("Menu"))
} //NavView End
} //VStack End
}
}
You can add .frame(maxWidth: .infinity) to the Button. This will also increase teachability.
Button("Create Order") { }
.frame(maxWidth: .infinity)
May be not most elegant solution but it works:
HStack() {
Spacer()
Button( action: {},
label: { Text("Create Order") })
Spacer()
}
First fast idea: set your button in HStack between Spacers:
// ...
VStack { //For Button
Spacer()
HStack {
Spacer()
Button( action: {}, label: { Text("Create Order") })
Spacer()
}
}
.navigationBarTitle(Text("Menu"))
// ...
and the result is:
Related
I have something like that for the first time. The preview and the simulator do not look identical. I really have no idea how to fix it. Normally the simulator and the preview should be identical?
But it may be that I've nested something but I don't know what exactly.
The images and code are below:
Simulator
Preview Layout
var body: some View {
ZStack {
Image("bg-official")
.resizable()
.edgesIgnoringSafeArea(.all)
VStack {
Spacer()
Text("NUMBER MATCH")
.fontWeight(.bold)
.font(.title)
GeometryReader { (geometry : GeometryProxy) in
ZStack {
RoundedRectangle(cornerRadius: 30)
.foregroundColor(Color("bg-roundedrectangle"))
.frame(width: 295, height: 310)
VStack(spacing: 3){
HStack(spacing: 3) {
Button {
} label: {
ZStack {
Rectangle()
.fill(Color.black.opacity(0.7))
.frame(width: geometry.size.width/3, height: geometry.size.height/5.5)
.cornerRadius(radius: 20, corners: [.topLeft])
Text("60 Seconds")
.font(.title3)
.foregroundColor(.white)
}
}
Button {
} label: {
ZStack {
Rectangle()
.fill(Color.black.opacity(0.7))
.frame(width: geometry.size.width/3, height: geometry.size.height/5.5)
.cornerRadius(radius: 20, corners: [.topRight])
Text("Endless")
.font(.title3)
.foregroundColor(.white)
}
}
}
HStack(spacing: 3) {
Spacer()
Button {
} label: {
ZStack {
Rectangle()
.fill(Color.white)
.frame(width: geometry.size.width/3, height: geometry.size.height/5.5)
.cornerRadius(radius: 20, corners: [.bottomLeft])
Text("Game Center")
.font(.title3)
.foregroundColor(.black)
}
}
Button {
withAnimation() {
sheetManager.present(with: .init(
systemName: "info",
title: "Game Info",
content: "The aim of this game is to match as many tiles as you can with the same number and earn points. Tap a tile to select it and tap another tile with matching number of the first tile you tapp ed. Be careful and quick; the game will end if you tap a wrong tile, if the timer runs out or if th board gets filled by tiles!"))
}
} label: {
ZStack {
Rectangle()
.fill(Color.white)
.frame(width: geometry.size.width/3, height: geometry.size.height/5.5)
.cornerRadius(radius: 20, corners: [.bottomRight])
Text("Game Info")
.font(.title3)
.foregroundColor(.black.opacity(0.9))
}
}
Spacer()
}
}
}
}
.popup(with: sheetManager)
}
}
}}
Is it possible to have an expanding menu that does not expand the HStack it is in?
I want a "menu bar" on top of my app and on the right is an expanding menu with all my objects in. But when I expand the menu all of the HStack expands which looks bad.
I tried putting a .fixedsize() on the HStack but it didn't help.
Do I have to move the menu or is it possible?
This is my code:
HStack{
Text("Input searchfunction here")
.foregroundColor(Color.white)
.padding()
Spacer()
Button(action: {
createViewIsActive = true
}, label: {
Text("Lägg till tecken.")
.foregroundColor(Color.white)
.onAppear {
if signs.count != 0 {
activeSign = signs[0]
}
}
Image(systemName: "plus")
.foregroundColor(Color.white)
})
.padding()
Button(action: {
deleteItems()
}, label: {
Text("Delete")
})
Spacer()
DisclosureGroup("Tecken", isExpanded: $isExpanded) {
ScrollView{
VStack{
ForEach(signs, id: \.self) { sign in
HStack{
Text(sign.name!)
.font(.title3)
.padding(.all)
.onTapGesture {
self.isExpanded.toggle()
self.activeSign = sign
}
}
}
}
}
}
.accentColor(.white) // Arrow color
.font(.title3)
.foregroundColor(.white) // Text color
.padding(.all)
.cornerRadius(8)
.frame(minWidth: 10, maxWidth: 300)
}
.background(Color.gray)
.padding()
Goal
Like the app Maps, views appear to be full frame size when Sidebar is open. Views are under Sidebar.
What I've tried
In order to maximize View's size, I've set the size to be infinity and add view modifier .ignoresSafeArea() but it's still not full frame like Maps
You will see the frame of view will be adjusted when I turn on the sidebar
var body: some View {
NavigationView {
List(0 ..< 5) { item in
NavigationLink("Test") {
VStack {
Text("Test")
}
.navigationTitle("Test")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.ignoresSafeArea()
}
}
ScrollView {
Text("Hello, world!")
.padding()
}
}
.frame(minWidth: 400, minHeight: 400)
.toolbar {
ToolbarItem(placement: .navigation) {
Button(action: toggleSidebar, label: {
Image(systemName: "sidebar.leading")
})
}
}
}
Just use transparent content for right side and place map below NavigationView.
Here is a demo of approach. Tested with Xcode 13 / macOS 12
var body: some View {
ZStack {
MapView() // << content here !!
NavigationView {
List(0 ..< 5) { item in
NavigationLink("Test") {
VStack {
Text("Test")
}
.navigationTitle("Test")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.ignoresSafeArea()
}
}
Color.clear // << transparent right !!
}
.frame(minWidth: 400, minHeight: 400)
.toolbar {
ToolbarItem(placement: .navigation) {
Button(action: toggleSidebar, label: {
Image(systemName: "sidebar.leading")
})
}
}
}
}
When removing the window titlebar it makes sense that I can paint to the top of the window.
However with the window tab bar showing, the HSplitView doesn't stop at the window tab but goes straight over it.
How do I have the HSplitView stop at the bottom of the tab?
The issue is
TestApp.swift
#main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.windowStyle(HiddenTitleBarWindowStyle())
}
}
ContentView.swift
struct ContentView: View {
var body: some View {
NavigationView {
Text("Sidebar")
HSplitView {
Text("left")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.navigationTitle("tab name")
Text("right")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.toolbar {
Button(action: {}){
Image(systemName: "arrow.triangle.turn.up.right.diamond")
Text("Button 1")
}
}
}
}
}
Result (HSplitView goes all the way to the top of the window):
2 possible solutions that feel inadequate are
struct ContentView: View {
var body: some View {
NavigationView {
Text("Sidebar")
VStack(spacing: 0) {
Divider()
HSplitView {
Text("left")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.navigationTitle("tab name")
Text("right")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.toolbar {
Button(action: {}){
Image(systemName: "arrow.triangle.turn.up.right.diamond")
Text("Button 1")
}
}
}
}
}
}
Which results in this (however I don't want a divider below the tabs):
OR
struct ContentView: View {
var body: some View {
NavigationView {
Text("Sidebar")
VStack(spacing: 0) {
VStack {}
.frame(maxWidth: .infinity, maxHeight: 1)
HSplitView {
Text("left")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.navigationTitle("tab name")
Text("right")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.toolbar {
Button(action: {}){
Image(systemName: "arrow.triangle.turn.up.right.diamond")
Text("Button 1")
}
}
}
}
}
}
Which results in this (but I wonder if this is "accidentally" working):
I am building a simple form in SwiftUI for macOS but once I add a picker the layout is screwed up.
This is my code:
var body: some View {
GeometryReader { geometry in
Form {
HStack {
Text("Label")
.frame(minWidth: 0.25 * geometry.size.width, alignment: .leading)
TextField("", text: $field1)
}
HStack {
Text("Long Label")
.frame(minWidth: 0.25 * geometry.size.width, alignment: .leading)
TextField("", text: $field2)
}
// HStack {
// Text("Picker")
// .frame(minWidth: 0.25 * geometry.size.width, alignment: .leading)
//
// Picker("", selection: $selectedColor) {
// ForEach(colors, id: \.self) {
// Text($0)
// }
// }
// }
}
.padding(20)
}
}
}
and this is the form which comes out:
Adding a simple picker, the layout becomes:
and I am not able to keep all the labels aligned. I have tried to add a frame to the picker and to the HStack but nothing helps.
I have also tried with:
Picker(selection: $selectedColor, label: EmptyView() {
...
}
and:
Picker(selection: $selectedColor, label: Text("Picker") {
...
}
getting the same result.
How do I keep the labels aligned?
Add labelsHidden() to your Picker:
HStack {
Text("Picker").frame(minWidth: 0.25 * geometry.size.width, alignment: .leading)
Picker("", selection: $selectedColor) {
ForEach(colors, id: \.self) {
Text($0)
}
}.labelsHidden()
}
I think #jnpdx's answer is better but this is another way.
Read comments in the code:
Embed 3 HStacks into a VStack
Change minWidth to 0.24
import SwiftUI
struct ContentView: View {
var body: some View {
GeometryReader { geometry in
Form {
// Embed 3 HStacks into a VStack
VStack {
HStack {
Text("Label")
.frame(minWidth: 0.25 * geometry.size.width, alignment: .leading)
TextField("label", text: .constant("")).labelStyle(IconOnlyLabelStyle())
}
HStack {
Text("Long label")
.frame(minWidth: 0.25 * geometry.size.width, alignment: .leading)
TextField("long Label", text: .constant(""))
}
HStack {
Text("Picker")
// Change minWidth to 0.24
.frame(minWidth: 0.24 * geometry.size.width, alignment: .leading)
Picker("", selection: .constant(Color.red)) {
ForEach([Color.red, Color.green, Color.blue], id: \.self) {
Text($0.description)
}
}
}
}
}
.padding(20)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
This answer is much better than accepted answer: https://stackoverflow.com/a/73946863/202179
In short there is a LabeledContent for that purpose now.