How to make SwiftUI Form translucent? - ios

I am trying to make the SwiftUI Form translucent. I've tried applying .background(.thinMaterial) modifier to the Form. However, this changes the look of the scroll view background. I'd like to apply translucency to the area that is white in the picture I attached.
Is there a way to do it? I am developing for iOS 16.
var body: some View {
NavigationStack(path: $path) {
ZStack {
LinearGradient(gradient: Gradient(colors: [.pink, .yellow]),
startPoint: .topTrailing,
endPoint: .bottomLeading)
.edgesIgnoringSafeArea(.all)
Form {
VStack {
...
}
}.scrollContentBackground(.hidden)
}
}

It seems Form is just a List under the hood. So by applying .scrollContentBackground(.hidden) you are clearing the List background.
By using .background on Form you are setting the background for the entire List again. To set the background only on the implicit Section you need another modifier. .listRowBackground.
But listRowBackground has this signature:
func listRowBackground<V>(_ view: V?) -> some View where V : View
So you can´t use .thinMaterial. But you can add a new background to the VStack.
A possible solution would be:
var body: some View {
NavigationStack(path: $path) {
ZStack {
LinearGradient(gradient: Gradient(colors: [.pink, .yellow]),
startPoint: .topTrailing,
endPoint: .bottomLeading)
.edgesIgnoringSafeArea(.all)
Form {
VStack {
TextField("", text: $text)
Button("test"){
}
.buttonStyle(.borderedProminent)
Button("test"){
}.buttonStyle(.borderedProminent)
}
// this will clear the background
.listRowBackground(Color.clear)
// add some padding around the VStack
.padding()
// apply a new background
.background(.ultraThinMaterial)
// make the edges round again
.mask {
RoundedRectangle(cornerRadius: 20)
}
}
.scrollContentBackground(.hidden)
}
}
}
Result:

Change the form's opacity to bleed through the background colour/image:
Form {
/...
}
.opacity(0.5). // 0 = fully translucent ... 1 = opaque

Related

Make all background UI blur after a view pop up

I plan to have a pop up view that blur out all the underlying UI behind it after it show, however my background "RoundedRectangle(cornerRadius: 20)
.background(
Color.white.opacity(0.7)
)" did not show a transparent white or blur like I planned.
var body: some View {
ZStack() {
NavigationStack {
ZStack() {
MyBackGround()
VStack() {
TextField("username", text: $user)
.padding()
.background(.brown)
SecureField("password", text: $pw)
.padding()
.background(.brown)
Button("CONFIRM") {
popUp.toggle()
}
.padding()
.cornerRadius(20)
.padding()
}
}
}
if popUp {
RoundedRectangle(cornerRadius: 20)
.background(
Color.white.opacity(0.7)
)
MyPopUP()
}
}
}
Your popup background is black because by default RoundedRectangle is filled with black color, so instead of adding background modifier we need to fill it with that color.
NavigationStack {
// content ...
}
.blur(radius: popUp ? 5 : 0) // to blur (constant is up to you)
.disabled(popUp) // bluring does not prevent interaction
if popUp {
// if semi-transparent background is still needed
RoundedRectangle(cornerRadius: 20)
.foregroundColor(Color.white.opacity(0.7)) // << here !!
MyPopUP()
}
I suggest using the provided SwiftUI .blur() for this context instead.
Add this line of code after your NavigationStack.
NavigationStack{...}
.blur(radius: popUp ? 10 : 0)
if popUp {
MyPopUP()
}

Add accessory view below navigation bar title in SwiftUI

I’m trying to add an accessory view embedded in a navigation bar below the title, which can be seen in the default iOS calendar app (the “s m t w t f s” row) or the GitHub mobile app:
And I’d like it to work along with the large title style navigation bar like the GH mobile.
LazyVStack’s pinnedView with a section header almost work, but I can’t get the background color to make it seemless with the navigation bar, even with the ultraThinMaterial. It also leaves the divider line between the pinned view and the bar.
Is there a way to achieve this layout?
Solutions in SwiftUI, SwiftUI+Introspect, and UIKit are all welcome!
Have you tried setting a .safeAreaInset view? This will have the stickiness you're looking for, and items in the "main" part of the view will take its height into account when rendering, so won't get obscured.
Here's a quick example I knocked up:
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(0 ..< 30) { item in
Text("Hello, world!")
}
}
.navigationTitle("Accessory View")
.safeAreaInset(edge: .top) {
AccessoryView()
}
}
}
}
struct AccessoryView: View {
var body: some View {
HStack {
Button("Button") { }
Button("Button") { }
Button("Button") { }
Spacer()
}
.padding()
.background(Color(uiColor: .systemGroupedBackground))
.buttonStyle(.bordered)
.controlSize(.mini)
}
}
You have to give the view a background otherwise it'll be transparent – but that background will (as long as it's a colour or a material) automatically extend into the navigation bar itself. Here's a GIF of the above code in action, where I've set the background to match the grouped list's background:
It's not perfect, especially as it looks distinct from the nav bar on scroll, but it might be useable for you?
Another idea is to replace the navigation bar with a custom one like this:
{
...
}
.safeAreaInset(edge: .top) {
VStack(alignment: .leading, spacing: 8) {
HStack() {
Button {
presentationMode.wrappedValue.dismiss()
} label: {
Image(systemName: "chevron.backward")
}
Spacer()
Text(navigationTitle).font(.title2).bold()
.multilineTextAlignment(.center)
.foregroundColor(.accentColor)
.frame(maxWidth: .infinity)
Spacer()
}
HStack {
Button("Button") { }
Button("Button") { }
Button("Button") { }
Spacer()
}
}
.padding()
.background(
.bar
)
}
You will also have to set:
.navigationBarBackButtonHidden(true)
and do not set a navigation title:
// .navigationTitle("....")

SwiftUI: background color for whole screen and not simple view?

I am trying to do something very simple, display a view with a background color, and in the center of this view, display a single label.
I tried this:
var body: some View {
VStack {
Text("Hello!")
}
.background(MyColors.blue)
.ignoresSafeArea()
}
Here is the given result:
What am I doing wrong?
Thank you for your help
I managed to get it working with this code:
var body: some View {
ZStack {
Style.Color.red
VStack {
Text("Hello!")
}
}
.ignoresSafeArea()
}
I didn't understand first that background and rest of the view must be set on a different z-axis.
You can do it like this:
Text("Hello!")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(MyColors.blue)
.ignoresSafeArea()
Source: https://www.hackingwithswift.com/articles/224/common-swiftui-mistakes-and-how-to-fix-them

SwiftUI NavigationView with transparent background

I Have this view with a Gradient as a background, I want to place another view on top of it, this last view has a NavigationView inside but for some reason I can't make it have a transparent background so I can show off the gradient behind.
Even more strange is the fact that is not even possible to change the NavigationView's background color, I ve looked every where but it seems that I can't find any method that allows me to change color nor to make it transparent
First View( The one with the gradient background I want to display)
ZStack { // Global Stack for views
//Background gradient
VStack {
LinearGradient(gradient: Gradient(colors: [Color("background2"), Color(.systemBackground)]), startPoint: .top, endPoint: .bottom)
.frame(height: screenHeight/4)
Spacer()
}.background(Color(.systemBackground))
Subjects()
VStack {
HStack { // Topbar with menu-btn and profile-btn
MenuButton(show: self.$showMenu)
.disabled(self.showProfile)
Spacer()
HStack {
TodayButton(show: self.$showToday)
ProfileButton(show: self.$showProfile)
}
}
Spacer()
}
.padding()
.padding(.top, screenHeight*0.05)
}
Second View (The one with the NavigationView I want to make transparent)
struct Subjects: View {
let subjects = [
Subject(id: UUID(), name: "Matematica", color: "ff06f0", grades: [3,7,6.5,5.5]),
Subject(id: UUID(), name: "Informatica", color: "5506f9", grades: [7,5,4.5,6,9]),
Subject(id: UUID(), name: "Geografia", color: "f39904", grades: [2,5,10,6.5,9,10,4.5])
]
var body: some View {
ZStack(alignment: .bottomTrailing) {
ZStack {
NavigationView {
VStack(spacing: 5) {
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 30) {
ForEach(subjects) { subject in
SubjectCard(subject: subject)
}
}.padding()
.padding(.top)
}
}.navigationBarTitle(Text("Materie"))
}
}.offset(y: screenHeight*0.1)
ActionButton(icon: "plus")
}
}
}
I had almost the exact same problem on a NavigationView containing Lists and Navigation Links. These appeared white, blocking my gradient background, which was underneath it on the ZStack. I never found an answer that worked, but I did find a workaround.
I solved the problem by adding .blendMode(.darken) on a VStack containing these elements. Darken blendmode will pick the darker of the two views and display it. If your gradient is lighter, you may want to try .blendMode(.lighten). See my code below to see if it would work for you.
NavigationView {
ZStack {
LinearGradient(gradient: Gradient(colors: [Color.purple , Color.green]), startPoint: .topLeading, endPoint: .bottomTrailing)
.ignoresSafeArea()
VStack {
SideMenuHeaderView()
VStack {
List(SideMenuViewModel.MenuItem.allCases) { itemText in
NavigationLink(destination: viewModel.getDestination(itemText: itemText.rawValue)) {
SideMenuCell(text: itemText.rawValue)
}
}
}.blendMode(.darken)
.padding()
}
}
}
Hopefully that works for you as well.

Change UIView background color in SwiftUI

Hello everyone. I'm creating a simple iOS app with SwiftUI, and I'd like to change my view's background color to a custom one I have.
This is something extremely easy to do but it seems that it's impossible to achieve in SwiftUI without using ZStacks or workarounds like that, which if you use a List, for example, don't work.
I want to change the color of the view, not use a ZStack with a custom color and then put the rest of the views on top of it. I tried using UIView.appearance().backgroundColor = color when initializing my view, but then all the view is hidden and the screen is filled with the color chosen.
As I'm not good at explaining, here you have some images describing the problem:
Without color change
With color change
My code
import SwiftUI
struct TabController: View {
#State private var selection = 0
init() {
UIView.appearance().backgroundColor = UIColor(named: "backgroundColor")
}
var body: some View {
TabView(selection: $selection) {
HomePageView()
.tabItem {
Image(systemName: "house.fill")
.font(.title)
}
.tag(0)
Text("Second View")
.font(.title)
.tabItem {
Image(systemName: "bell.fill")
.font(.title)
}
.tag(1)
}.edgesIgnoringSafeArea(.top)
}
}
Hope this will help to understand:
var body: some View {
Color.purple
.overlay(
VStack(spacing: 20) {
Text("Overlay").font(.largeTitle)
Text("Example").font(.title).foregroundColor(.white)
})
.edgesIgnoringSafeArea(.vertical)
}
Another If you use the views in Group
var body: some View {
Group {
Text("Hello SwiftUI!")
}
.background(Color.black)
}
For changing the background color, I think the current method most people, and myself, are using is using a ZStack. I haven't seen many problems with putting a UIViewRepresentable on top of it.
var body: some View {
ZStack {
Color.blue
.edgesIgnoringSafeArea(.all)
VStack {
Text("Hello World!")
}
}
}

Resources