How can I change a modals sheet background? For instance, if I have:
Button(action: showAdditionalOptions) {
Image(systemName: "ellipsis")
.font(.system(size: 20))
.foregroundColor(Color.white)
}
.onTapGesture { showAdditionalOptions() }
.fullScreenCover(isPresented: $isShowingAdditionalOptions) {
AdditionalActions()
.background(Color.black.opacity(0.2))
}
The effect I am trying to get to is a blur effect that when a sheet is presented, its background is blurred and partly transparent. However I can't change the sheet's background. I can only modify a sheet's content background. Is there a way to apply a background to the sheet itself?
Related
I have a page which has a dark blue background color. When a button is pressed, a sheet is opened, however behind the sheet the blue background shifts down and it shows a white background. How can I prevent this?
ZStack {
setBackgroundColor.darkBlue
.ignoresSafeArea(.all)
HStack {
Button(action: {
self.showSheet = true
}) {
Text("Add exercise")
.frame(maxWidth: .infinity)
.frame(height: 10)
.foregroundColor(CustomColor.darkBlue)
.padding()
.background(CustomColor.cyan)
}
.clipShape(Capsule())
.sheet(isPresented: $showSheet) {
AddWorkoutSheet()
}
}
.padding(.bottom)
}
Blue background shifted when sheet is opened.
I have tried to find out what is wrong, but I cannot seem to figure it out. I quite new to programming and SwiftUI.
It is not shifting down, it is just how sheet works. When you toggle a sheet, it will pop out from the bottom with a default white background, therefore covering the background of your root view. So what you want might be a transparent sheet. If this is the case, using sheet may not be the best way as implementing a transparent sheet needs some walkaround. You may instead try using a transition to move the view up or down with offset.
Started learning SwiftUI, I want to remove this highlighted space between navigation title and Text inside VStack.
If you were to remove the NavigationView and had your VStack as the top-level view in your body, you'd see much the same layout.
That's because its frame is smaller than the frame available for it (in this case, most of the screen) and by default the smaller internal view gets centered both horizontally and vertically.
To move the text to the top of the screen, you need to ensure that your view will grow in size. The easiest way will be add to add a Spacer to the bottom of the VStack:
VStack(alignment: ...) {
Text("...")
Text("...")
Spacer()
}
Another approach would be to wrap your VStack in a scroll view. This view will automatically expand itself to fill the height, and layout its subviews (your VStack) from the top downwards:
ScrollView {
VStack(alignment: ...) {
Text("...")
Text("...")
}
}
Each approach has upsides and downsides depending on how much other data you expect to also be in the view.
You could also manually adjust the frame of your VStack using the .frame() modifier:
VStack(alignment: ...) {
Text("...")
Text("...")
}
.frame(maxHeight: .infinity, alignment: .top)
This would give you much the same effect as using the spacer. But the spacer version is a better way to go, especially if you're only starting out with SwiftUI layout.
In SwiftUI I currently have a VStack of views, and I'd like to put an overlay over the bottom two views, like this:
VStack {
Spacer()
Group {
centerView
Spacer()
}
.overlay(overlayedView)
}
The goal of the above layout is ensure that centerView is vertically centered, while also ensuring that the overlayedView goes from the top of centerView all the way to the bottom of the VStack.
However, the above code actually results in one instance of overlayedView getting overlayed on top of centerView and another overlayedView getting overlayed on top of the bottom Spacer. But what I want is a single overlayedView spread on top of both centerView and the bottom Spacer.
How can I achieve my desired behavior?
Using Group will add view modifiers to all the subviews of the group, resulting in 2 seperate overlays. To have one common overlay, you can use VStack instead of Group.
VStack {
Spacer()
VStack {
centerView
Spacer()
}
.overlay(overlayedView)
}
Using iOS14.5, Swift5.4, XCode12.5, and SwiftUI,
I am trying to build simple DetailView to which you can navigate to using a NavigationLink.
It all works, except that I have no idea about the height of my NavigationBar inside the DetailView. (note that I use the .inline Version by calling .navigationBarTitleDisplayMode(.inline) on the DetailView).
I am trying to show a simple two-line VStack in the DetailView.
And it turns out that the DetailView's body is covered by the NavigationBar unless I move the whole thing down by 56 Pixels (by using Spacer().frame(height: 56)).
And I don't even know the precise height of the NavigationBar
And even worse, I don't know how to determine it dynamically for Portrait and Landscape rotations.
How do you make the DetailView's body start below the NavBar no matter rotation-states ?
Here example Screenshots for Portrait :
Left side: the title is cut off ! Right side: using a Spacer makes title appear
Here is how I open the navigationLink:
NavigationLink(
destination: DetailView(session: session).navigationBarTitleDisplayMode(.inline),
tag: session.id ?? "",
selection: $selectedTag,
label: { EmptyView() }
)
And here is the entire Detail-Screen:
(please notice the Spacer-distance of 56 in order to make the title visible at all)
import SwiftUI
struct DetailView: View {
#State var session: THSession
var body: some View {
VStack(alignment: .leading) {
Spacer().frame(height: 56) // !!!!!!!!!! without this the title sits behind NavBar !!!!!!!!!!!!!!!!!!!
Text(session.title)
.font(.title)
.fontWeight(.bold)
.foregroundColor(.white)
Spacer().frame(height: 16)
HStack {
Text(session.invitationCode)
.font(.title)
.fontWeight(.bold)
.foregroundColor(.white)
}
Spacer()
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
.background(Color.red)
.ignoresSafeArea()
}
}
I'm assuming that you're using ignoresSafeArea() because you want the background to extend into the safe area. But, where you have it placed is having a side effect of making the titles extend into the nav bar area.
Instead, place ignoresSafeArea() inside the background modifier:
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
.background(Color.red.ignoresSafeArea())
Now, your titles won't extend into the safe area and you can avoid using a Spacer at the top of the View altogether.
If I have a Label that uses a system image and some text, let's call the text "title". How would I align the subtitle to the the leading edge of the title text and not the image?
This seems to work, but is there another way? Something just seems off about setting the top alignment.
HStack(alignment: .top) {
Image(systemName: "gift")
VStack(alignment: .leading) {
Text("Title")
Text("Subtitle")
}
}