I have a list in swiftUI and I want the background to be somewhat see through. However there seems to be a white background applied to both scrollview and List. I was wondering if anyone had a work around or way to change it so when .background(Color.white.opacity(0.7)) is applied to the list, it can be translucent and not have the same affect as .background(Color.white).
Here is my code for the view that I am trying to implement the desired effect. The wordPosts is simply just a custom data struct used to populate the list item data. I've already trying changing the cell and tableview appearance using UIkit on init which did not work.
struct ProfileWordsView: View {
init(){
UITableView.appearance().backgroundColor = .clear
UITableViewCell.appearance().backgroundColor = .clear
}
var body: some View {
List {
ForEach(wordPosts) { post in
Group {
VStack(alignment: .leading) {
HStack(alignment: .top) {
RoundedRectangle(cornerRadius: 5)
.fill()
.frame(width: 4)
VStack(alignment: .leading, spacing: 0) {
HStack(spacing: 5) {
Text(post.title).font(.custom("Gilroy-SemiBold", size: 20)).foregroundColor(.black).lineLimit(1)
Text("• \(post.timestamp)").font(.custom("Gilroy-SemiBold", size: 19)).foregroundColor(.gray)
}
HStack {
Text(post.text).font(.custom("Gilroy-Regular", size: 16)).foregroundColor(Color.black.opacity(0.7)).padding(.top, 5)
}
}
Spacer()
VStack {
Button(action: {}) {
Image(systemName: "chevron.up")
.resizable()
.frame(width: 20, height: 15)
.font(Font.title3)
.foregroundColor(.gray)
.padding(.bottom, 6)
}
Text("\(post.rizz)").font(.custom("Gilroy-SemiBold", size: 18)).foregroundColor(.gray)
Button(action: {}) {
Image(systemName: "chevron.down")
.resizable()
.frame(width: 20, height: 15)
.font(Font.title3)
.foregroundColor(.gray)
}
}
}
}.listRowInsets(EdgeInsets(top: 10, leading: 5, bottom: 10, trailing: 10))
}.listRowBackground(Color.clear)
}
.listRowSeparator(.hidden)
}.edgesIgnoringSafeArea(.all).listStyle(.plain)
}
}
I'm not sure if it is possible for your code but I'd recommend using a scrollview instead. They are transparent by default, so that should help. You can always add a frame with a semi-transparent color if you want to have a semi-transparent background instead.
Related
I don't want the behavior I'm getting with this SwiftUI thing (first time messing with it). I've been putting .background() on everything and there's some kind of padding happening and some sort of dividing line, whether I enable the Button code or not (pic below is with Button code commented out).
What do I need to do to fix it?
var body: some View {
ZStack() {
Color.black
.ignoresSafeArea(.all)
VStack(alignment: .leading, spacing: 0) {
List(eventFields) { eventField in
HStack() {
Spacer(minLength: 10)
if let iconName = eventField.iconName {
Button(action: {
print("edit \(eventField.name)")
}, label: {
Image(uiImage: UIImage(named: iconName)!.colorizeMask(eventField.iconColor!))
.frame(width: 27, height: 27)
self.background(.black)
}).background(.black)
} else {
Text("")
.frame(width: 27)
}
Text(eventField.iconName == nil ? "" : eventField.name)
.font(.system(size: eventField.labelFontSize))
.foregroundColor(eventField.labelFontColor)
.frame(width: 50, alignment: .trailing)
Spacer(minLength: 3)
Text(eventField.stringValue)
.font(.system(size: eventField.fontSize))
.foregroundColor(eventField.fontColor)
.frame(width: 200, alignment: .leading)
Spacer(minLength: 10)
}.background(.black)
}.background(.black)
}
}
}
}
instead of putting .background on the HStack, use
.listRowBackground(Color.black)
and for separator use
.listRowSeparator(.hidden)
Keep in mind, this is on the HStack not the List
Full Code:
var body: some View {
ZStack() {
Color.black
.ignoresSafeArea(.all)
VStack(alignment: .leading, spacing: 0) {
List(eventFields) { eventField in
HStack() {
Spacer(minLength: 10)
if let iconName = eventField.iconName {
Button(action: {
print("edit \(eventField.name)")
}, label: {
Image(uiImage: UIImage(named: iconName)!.colorizeMask(eventField.iconColor!))
.frame(width: 27, height: 27)
self.background(.black)
}).background(.black)
} else {
Text("")
.frame(width: 27)
}
Text(eventField.iconName == nil ? "" : eventField.name)
.font(.system(size: eventField.labelFontSize))
.foregroundColor(eventField.labelFontColor)
.frame(width: 50, alignment: .trailing)
Spacer(minLength: 3)
Text(eventField.stringValue)
.font(.system(size: eventField.fontSize))
.foregroundColor(eventField.fontColor)
.frame(width: 200, alignment: .leading)
Spacer(minLength: 10)
}
.listRowBackground(Color.black)
.listRowSeparator(.hidden)
}
}
}
}
}
I believe the color specification for your hstack and frames is supposed to be "(Color.black)" instead of just "(.black)".
Which type of color you use isn't consistent across all Swift objects. Some objects, such as UITableView use "UI colors" which are in the form ".black", while others, like frames, vstacks, hstacks and other objects, use SwiftUI colors in the form "Color.black".
I recommend this very informative page for a very accessible explanation of using color in a view and a stack.
Why is there so much space between the three blue rectangles and the list? How can I remove the space so that all views within the VStack stack at the top? I tried using a Spacer() directly after the List, but nothing changed.
struct ContentView: View {
init() { UITableView.appearance().backgroundColor = UIColor.clear }
var body: some View {
NavigationView {
ZStack {
Color.red
.ignoresSafeArea()
VStack {
HStack {
Text("Faux Title")
.font(.system(.largeTitle, design: .rounded))
.fontWeight(.heavy)
Spacer()
Button(action: {
// settings
}, label: {
Image(systemName: "gearshape.fill")
.font(.system(.title2))
})
}
.padding()
GeometryReader { geometry in
HStack() {
Text("1")
.frame(width: geometry.size.width * 0.30, height: 150)
.background(Color.blue)
Spacer()
Text("2")
.frame(width: geometry.size.width * 0.30, height: 150)
.background(Color.blue)
Spacer()
Text("3")
.frame(width: geometry.size.width * 0.30, height: 150)
.background(Color.blue)
}
}
.padding()
List {
Text("One")
Text("Two")
Text("Three")
Text("Four")
Text("Five")
Text("Six")
}
.listStyle(InsetGroupedListStyle())
}
}
.navigationBarHidden(true)
}
}
}
Bonus question: In web development, you can open your browser's Web Inspector and use the element selector to click on elements which highlights their borders. Useful for something like this where you're trying to figure out which element the offending spacing belongs to. Is there something like that in Xcode?
VStack(spacing: 0) {...}
Spacer()
to your question you can in Xcode use the view inspector. https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/ExaminingtheViewHierarchy.html
Since you know that your HStack with the blue rectangles is going to be a height of 150, you should constrain it to that using .frame(height: 150):
GeometryReader { geometry in
...
}
.padding()
.frame(height: 150) //Here
Otherwise, the GeometryReader will occupy all available vertical space.
Re: your web dev comparison, check out the Xcode view hierarchy inspector. It's not exactly the same, but it's in the same vein: https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/ExaminingtheViewHierarchy.html
I am trying to build a List that I want to look like a timeline.
Each cell will represent a milestone.
Down the left hand side of the table, I want the cells to be 'connected', by a line (the timeline).
I have tried various things to get it to display as I want but I have settled with basic geometric shapes , i.e Circle() and Rectangle().
This is sample code to highlight the problem:
import SwiftUI
struct ContentView: View {
var body: some View {
let roles: [String] = ["CEO", "CFO", "Managing Director and Chairman of the supervisory board", "Systems Analyst", "Supply Chain Expert"]
NavigationView{
VStack{
List {
ForEach(0..<5) { toto in
NavigationLink(
destination: dummyView()
) {
HStack(alignment: .top, spacing: 0) {
VStack(alignment: .center, spacing: 0){
Rectangle()
.frame(width: 1, height: 30, alignment: .center)
Circle()
.frame(width: 10, height: 10)
Rectangle()
.frame(width: 1, height: 20, alignment: .center)
Circle()
.frame(width: 30, height: 30)
.overlay(
Image(systemName: "gear")
.foregroundColor(.gray)
.font(.system(size: 30, weight: .light , design: .rounded))
.frame(width: 30, height: 30)
)
//THIS IS THE RECTANGLE OBJECT FOR WHICH I WANT THE HEIGHT TO BE VARIABLE
Rectangle()
.frame(width: 1, height: 40, alignment: .center)
.foregroundColor(.green)
}
.frame(width: 32, height: 80, alignment: .center)
.foregroundColor(.green)
VStack(alignment: .leading, spacing: 0, content: {
Text("Dummy operation text that will be in the top of the cell")
.font(.subheadline)
.multilineTextAlignment(.leading)
.lineLimit(1)
Label {
Text("March 6, 2021")
.font(.caption2)
} icon: {
Image(systemName: "calendar.badge.clock")
}
HStack{
HStack{
Image(systemName: "flag.fill")
Text("In Progress")
.font(.system(size: 12))
}
.padding(.horizontal, 4)
.padding(.vertical, 3)
.foregroundColor(.blue)
.background(Color.white)
.cornerRadius(5, antialiased: true)
HStack{
Image(systemName: "person.fill")
Text(roles[toto])
.font(.system(size: 12))
}
.padding(.horizontal, 4)
.padding(.vertical, 3)
.foregroundColor(.green)
.background(Color.white)
.cornerRadius(5, antialiased: true)
HStack{
Image(systemName: "deskclock")
Text("in 2 Months")
.font(.system(size: 12))
}
.padding(.horizontal, 4)
.padding(.vertical, 3)
.foregroundColor(.red
)
.background(
Color.white
)
.cornerRadius(5, antialiased: true)
}
})
}.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
}
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct dummyView: View {
var body: some View {
Text("Hello, World!")
}
}
struct dummyView_Previews: PreviewProvider {
static var previews: some View {
dummyView()
}
}
but as you can see in the enclosed picture, there are unwanted gaps
So other content in the cell is making the height of the entire cell 'unpredictable' and break the line.
Is there a way to determine the height of the cell and extend the dimensions of the Rectangle, so that it extends to the full height of the cell?
Is there a better approach you recommend for trying to build such a timeline ?
PS: I have tried playing around with .frame and .infinity but that does work.
Many thanks.
Why not just draw the line based on the size of the row. See Creating custom paths with SwiftUI. Remember, everything is a view.
First, you need to decompose what you are doing into subviews. You have too many moving parts in one view to get it correct. Also, I would avoid setting specific padding amounts as that will mess you up when you change devices. You want a simple, smart view that is generic enough to handle different devices.
I would have a row view that has a geometry reader so it knows its own height. You could then draw the line so that it spanned the full height of the row, regardless of the height. Something along the lines of this:
struct ListRow: View {
var body: some View {
GeometryReader { geometry in
ZStack {
HStack {
Spacer()
Text("Hello, World!")
Spacer()
}
VerticalLine(geometry: geometry)
}
}
}
}
and
struct VerticalLine: View {
let geometry: GeometryProxy
var body: some View {
Path { path in
path.move(to: CGPoint(x: 20, y: -30))
path.addLine(to: CGPoint(x: 20, y: geometry.size.height+30))
}
.stroke(Color.green, lineWidth: 4)
}
}
I have a SwiftUI view that is a circular view which when tapped opens up and is supposed to extend over the UI to its right. How can I make sure that it will appear atop the other ui? The other UI elements were created using a ForEach loop. I tried zindex but it doesn't do the trick. What am I missing?
ZStack {
VStack(alignment: .leading) {
Text("ALL WORKSTATIONS")
ZStack {
ChartBackground()
HStack(alignment: .bottom, spacing: 15.0) {
ForEach(Array(zip(1..., dataPoints)), id: \.1.id) { number, point in
VStack(alignment: .center, spacing: 5) {
DataCircle().zIndex(10)
ChartBar(percentage: point.percentage).zIndex(-1)
Text(point.month)
.font(.caption)
}
.frame(width: 25.0, height: 200.0, alignment: .bottom)
.animation(.default)
}
}
.offset(x: 30, y: 20)
}
.frame(width: 500, height: 300, alignment: .center)
}
}
}
}
.zIndex have effect for views within one container. So to solve your case, as I assume expanded DataCircle on click, you need to increase zIndex of entire bar VStack per that click by introducing some kind of handling selection.
Here is simplified replicated demo to show the effect
struct TestBarZIndex: View {
#State private var selection: Int? = nil
var body: some View {
ZStack {
VStack(alignment: .leading) {
Text("ALL WORKSTATIONS")
ZStack {
Rectangle().fill(Color.yellow)//ChartBackground()
HStack(alignment: .bottom, spacing: 15.0) {
ForEach(1...10) { number in
VStack(spacing: 5) {
Spacer()
ZStack() { // DataCircle()
Circle().fill(Color.pink).frame(width: 20, height: 20)
.onTapGesture { self.selection = number }
if number == self.selection {
Text("Top Description").fixedSize()
}
}
Rectangle().fill(Color.green) // ChartBar()
.frame(width: 20, height: CGFloat(Int.random(in: 40...150)))
Text("Jun")
.font(.caption)
}.zIndex(number == self.selection ? 1 : 0) // << here !!
.frame(width: 25.0, height: 200.0, alignment: .bottom)
.animation(.default)
}
}
}
.frame(height: 300)
}
}
}
}
i have an image that i want to strech only it's height to fit different content, how do i do that in swiftUI? right now it looks like this
struct ContentView: View {
var body: some View {
VStack {
HStack {
VStack(alignment: .leading, spacing: 130) {
Text("Title")
.font(.headline)
.foregroundColor(.primary)
Text("text")
.font(.subheadline)
.foregroundColor(.secondary)
Text("padding")
}
.padding(.vertical)
Spacer()
Image("rightTag")
.resizable(capInsets: .init(top: 0, leading: 0, bottom: 0, trailing: 0), resizingMode: .stretch)
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 20)
}
.frame(maxWidth: screen.width - 60)
.padding(.leading)
.background(.white)
.cornerRadius(20)
}
}
}
how can i stretch its height to fit this outer frame? ragular resizable and stuff can't get it done.
any helped would be wonderful! Thanks!
sry i didn't make myself clear earllier.
Here is possible approach. However as I see now you'd rather need to stretch not the entire original image, but only middle of it, so in real project it would be needed to make your image tri-part and apply below stretching approach only to middle (square) part.
Approach uses asynchronous state update, so works in Live Preview / Simulator / RealDevice. (Tested with Xcode 11.2 / iOS 13.2)
struct ContentView: View {
#State private var textHeigh: CGFloat = .zero
var body: some View {
VStack {
HStack(alignment: .top) {
VStack(alignment: .leading, spacing: 130) {
Text("Title")
.font(.headline)
.foregroundColor(.primary)
Text("text")
.font(.subheadline)
.foregroundColor(.secondary)
Text("padding")
}
.padding(.vertical)
.alignmentGuide(.top, computeValue: { d in
DispatchQueue.main.async {
self.textHeigh = d.height // !! detectable height of left side text
}
return d[.top]
})
Spacer()
Image("rightTag")
.resizable()
.frame(maxWidth: 20, maxHeight: max(60, textHeigh)) // 60 just for default
}
.frame(maxWidth: screen.width - 60)
.padding(.leading)
.background(Color.white)
}
}
}