MacOS SwiftUI: remove titlebar, include windows tabs - HSplitView paints above tabs? - macos

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

Related

SwiftUI Text width animation

expected result
current result
I want to make it animation controllable
Open - text shows with animation
Close - text hide with animation
My code:
struct HomeView: View {
#State var isOpen = false
var body: some View {
ZStack {
Image("background")
.resizable()
VStack(alignment: .leading) {
Text("Appearing title text")
.frame(width: isOpen ? 200 : 0, height: 20, alignment: .leading)
.animation(.linear(duration: 2))
.font(.system(size: 20))
.foregroundColor(.white)
HStack {
Button("Open") {
isOpen = true
}
Button("Close") {
isOpen = false
}
}
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.padding(.top, 100)
}
.ignoresSafeArea()
}
}
Prompt me, please, how can I do it?

Swiftui expanding menu expands whole HStack?

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

How to make the view full frame even if Sidebar is on in SwiftUI?

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

SwiftUI macOS toolbar icons alignment for three column layout

Following this question, how to add a toolbar divider for a three column view in swiftUI life cycle
, I have a slightly different issue. I am trying to achive the same thing but the second and third columns are contained in a view which in turn is added inside a NavigationView next to first column which is the Sidebar.
Code example
import SwiftUI
#main
struct ThreeColumnsAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.frame(minWidth: 900, maxWidth: .infinity, minHeight: 600, maxHeight: .infinity)
}
.windowStyle(DefaultWindowStyle())
.windowToolbarStyle(UnifiedWindowToolbarStyle(showsTitle: true))
}
}
struct ContentView: View {
var body: some View {
NavigationView {
Sidebar()
.toolbar { Button(action: {}, label: { Image(systemName: "sidebar.left") }) }
MainContentView()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct Sidebar: View {
var body: some View {
List {
Text("Menu 1")
Text("Menu 2")
Text("Menu 3")
Text("Menu 4")
}
.frame(minWidth: 250)
.listStyle(SidebarListStyle())
}
}
struct MainContentView: View {
var body: some View {
NavigationView {
ListItemView()
DetailView()
}
.navigationTitle("Items List")
.navigationSubtitle("5 items found")
}
}
struct ListItemView: View {
var body: some View {
List {
Text("List item 1")
Text("List item 2")
Text("List item 3")
Text("List item 4")
Text("List item 5")
}
.frame(minWidth: 250)
.listStyle(InsetListStyle())
.toolbar {
Button(action: {}, label: { Image(systemName: "arrow.up.arrow.down.square") })
}
}
}
struct DetailView: View {
var body: some View {
Text("Detail of list 1")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.toolbar {
Button(action: {}, label: { Image(systemName: "plus") })
Button(action: {}, label: { Image(systemName: "minus") })
Button(action: {}, label: { Image(systemName: "pencil") })
}
}
}
Output
As you can see bellow, the arrow icon, which should be on the second column's toolbar, is pushed to the right together with the detail view's toolbar icons. It seems NavigationView sees ListItemView and DetailView toolbars as a single one.
Desired output
Question
So, my question is how to have the toolbar icons aligned with their view?
In order to do this properly, you need a ToolbarItem on each of the three columns of the view. For example, this:
struct TripleNavView: View {
var body: some View {
NavigationView {
Text("Column 1")
.toolbar {
ToolbarItem {
Button(action: {}, label: {Image(systemName: "sidebar.left")})
}
}
Text("Column 2")
.toolbar {
ToolbarItem {
Button(action: {}, label: {Image(systemName: "plus")})
}
}
Text("Column 3")
.toolbar {
ToolbarItem {
Button(action: {}, label: {Image(systemName: "trash")})
}
}
}
.navigationTitle("Title")
}
}
Produces this:
The important thing is that both columns 2 and 3 need to have a ToolbarItem of some kind. If you only put a button on one of the columns, then SwiftUI will place it all the way at the trailing edge of the toolbar, and ruin the look.
As a result, if you don't want a button on a particular column, substitute a Spacer in place of the button.
Note that leaving it blank or using EmptyView() won't work - SwiftUI will optimize it out, and act as if you didn't include a ToolbarItem in the first place!

Xcode SwiftUI Button - Unable to Centre

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:

Resources