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
I am trying to figure out how to use the functions from xcode with very limited information from the Apple documentation. How to use certain functions or variables or where to find examples and detailed explanations? The particular case that I am working on now is to offset the tab bar item images on the tab bar. I came across "itemPositioning", "stackedItemPositioning" but I have no clues about how to use them. Should I put it inside the initialiser function? And how to use it?
Also, a quick question. Is there any book or video covering like somethings that teach me how to explore unknown things on SwiftUI independently?
truct MainContentView: View {
#State private var navSelection = 0
init(){
UITabBar.appearance().backgroundColor = UIColor.clear
//stackedItemPositioning = UIOffset(horizontal: 0, vertical: -10)
}
var body: some View {
VStack(alignment: .center){
NavigationView{
TabView(selection: self.$navSelection){
Text("hey")
.tabItem{
Image(systemName: "heart.fill")
.offset(y:-15)
}
.tag(0)
Text("hey")
.tabItem{
Image(systemName: "magnifyingglass")
}
.tag(1)
Text("hey")
.tabItem{
Image(systemName: "capsule.portrait.fill")
}
.tag(2)
Text("hey")
.tabItem{
Image(systemName: "wand.and.stars")
}
.tag(3)
}
}
}
}
}
My application uses a TabView and contained in it there is a NavigationView so I can transition to different views on the selected tabs. I am using .navigationTitle together with .navigationBarTitleDisplayMode(.large) to show users where they are (in the example below the title is set to "Pfizer"). All is working fine as you can see below:
var body: some View {
TabView(selection: $selectedTab) {
NavigationView {
...
However, as soon as I put a ZStack around the TabView (or use .overlay) the entire views including the navigation header move up into the safe area even though I have not specified an .ignoresSafeArea anywhere! Here is how it looks like when I am using ZStack around it:
var body: some View {
ZStack(alignment: .center) {
TabView(selection: $selectedTab) {
NavigationView {
...
Note that I intend to use ZStack to conditionally show a view on top of my TabView/NavigationView as follows:
#Binding var condition: Bool
var body: some View {
ZStack(alignment: .center) {
TabView(selection: $selectedTab) {
NavigationView {
...
}
}
.blur(radius: condition ? 3 : 0)
if condition {
VStack {
VStack(alignment: .center) {
Text("Some text")
.font(.title2).padding(.bottom)
}
.padding()
.background(Color(.secondarySystemBackground))
}
.padding(.horizontal, 40)
}
}
}
I managed to figure out by trial and error that the problem only occurs if I am using the .blur view modifier on the TabView that is inside the ZStack. If I remove the .blur view modifier, then the problem that I described does not occur and so the initial comment of Asperi makes sense.
I do not understand this behavior and I have no idea why using .blur messes up the safe area. Can anybody explain this behavior to me please?
As the title, it's a typical use case. And it's easy to achieve if using SwiftUI buttonStyle.
But for some reason I cannot use Button. So, how to do it with View?
You can use onTapGesture modifier for your view
struct ContentView: View {
#State var color = Color.green
var body: some View {
Text("Hello")
.padding()
.background(color)
.onTapGesture {
color = Color.blue
}
}
}
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.