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.
Related
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 having an alignment problem while using SwiftUI.
Maybe I should say a layout issue. Anyway here is the situation:
This is the relevant part of the app interface:
One can see that while the text ("+++++") is centered, the flag is not. It is slightly shifted to the left. This left-shifting is precisely my problem. I would like the image to be centered as the text is.
Here follows the code, I would like to know what I am doing wrong for the image not to be centered:
import SwiftUI
struct TheNiceView: View {
........
var body: some View {
VStack {
HStack {
Spacer()
TheButtonView()
Spacer()
}
HStack {
Spacer()
Button(action: {})
{
Text("+++++")
.font(.largeTitle)
.foregroundColor(.gray)
.fontWeight(.heavy)
}
Spacer()
}
}
}
}
struct TheButtonView: View {
........
let imgSide:CGFloat = 72.0
var body: some View {
HStack {
Button(action: {})
{
Image(uiImage: ThaiFlagImg)
.resizable()
.frame(width: imgSide, height: imgSide)
}
}
}
}
Just in case this may be useful, this is the image used for the flag:
1
Thailand flag has five horizontal stripes in the colours red, white, blue, white and red. The image you use has 7 srtips.
2
Using the Spacers and HStack are unnecessary.
I used the following image without the Spacers and HStack, both the +++ button and the flag are aligned in the center.
https://upload.wikimedia.org/wikipedia/commons/a/a9/Flag_of_Thailand.svg
struct TheNiceView: View {
var body: some View {
VStack {
TheButtonView()
Button(action: {}) {
Text("+++++")
.font(.largeTitle)
.foregroundColor(.gray)
.fontWeight(.heavy)
}
}
}
}
struct TheButtonView: View {
let imgSide:CGFloat = 72.0
var body: some View {
Button(action: {}){
Image( "ThaiFlagImg")
.resizable()
.frame(width: imgSide, height: imgSide)
}
}
}
I am trying to create a List View where rows looks like this:
However, I am unable to align the Circle on the leading side. Tried using Spacer(), HStack within VStack, it just doesn't work. Here's my code and its output.
struct PeopleView: View {
let people = ["Adam", "James"]
var body: some View {
NavigationView {
List {
ForEach(people, id: \.self) { person in
HStack {
Circle()
VStack {
Text("\(person)")
}
}
}
}
.navigationBarTitle("People", displayMode: .inline)
}
}
}
Actually you don't need shape itself in this case, but only as a mask to visually present text in circle.
So the solution can be like following
HStack {
Text(person.prefix(2).uppercased()).bold()
.foregroundColor(.white)
.padding()
.background(Color.red)
.mask(Circle()) // << shaping text !!
Spacer()
VStack {
Text("\(person)")
}
}
Some views in SwiftUI fill all available space. Such views are shapes, colors, spacers, dividers, and GeometryReader.
Your Circle is a shape and it behaves similarly like a Spacer (in terms of filling space).
If you replace Circle with an image of a circle it will work:
ForEach(people, id: \.self) { person in
HStack {
Image(systemName: "circle.fill")
.imageScale(.large)
Spacer()
VStack {
Text("\(person)")
}
}
}
That is happening because you did not give a fixed (or relative) frame to the Circle Shape, so the Circle is taking up the maximum available width.
If you add a frame(width:height:), everything should work correctly:
struct PeopleView: View {
let people = ["Adam", "James"]
var body: some View {
NavigationView {
List {
ForEach(people, id: \.self) { person in
HStack {
Circle()
.frame(width: 50, height: 50)
VStack {
Text("\(person)")
}
}
}
}
.navigationBarTitle("People", displayMode: .inline)
}
}
}
I'm trying to reproduce the Apple tutorial(Composing Complex Interfaces) and I have a very weird problem. My CategoryItem view is being displayed as a blue frame.
If I remove the NavigationLink which wraps it, everything works fine but with that one it doesn't.
struct CategoryRow: View {
var categoryName: String
var items: [Landmark]
var body: some View {
VStack(alignment: .leading) {
Text(self.categoryName)
.font(.headline)
.padding(.leading, 15)
.padding(.top, 5)
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .top, spacing: 0) {
ForEach(self.items) { landmark in
NavigationLink(
destination: LandmarkDetail(
landmark: landmark
)
) {
CategoryItem(landmark: landmark)
}
}
}
}.frame(height: 185)
}
}
}
NavigationLink has a blue accent color by default, just call .accentColor(Color.clear) on it
Or you could try this:
NavigationView {
NavigationLink(destination: Text("Detail view here")) {
Image("YourImage")
}
.buttonStyle(PlainButtonStyle())
}
https://www.hackingwithswift.com/quick-start/swiftui/how-to-disable-the-overlay-color-for-images-inside-button-and-navigationlink
renderingMode(.original) is what did it for me; .accentColor(Color.clear) made the image invisible (my best explanation here is because it didn't have a transparency).
NavigationView {
NavigationLink(destination: Text("Detail view here")) {
Image("YourImage")
.renderingMode(.original)
}
}
As the answer above mentioned, How to disable the overlay color for images inside Button and NavigationLink is a good write up as well.
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!")
}
}
}