SwiftUI - Sheet shows Data half way down the sheet - swiftui

I am building a small APP where I wanna present a Sheet when a Button is pressed, it all works fine, but when the Sheet is presented the Data starts half way down the Screen rather than at the Top. I am using a ScrollView in the Sheet and above the ScrollView I have a Text and an Image which is Static.
I tried pretty much everything I could find and think of without any success. So now I am hoping someone out there can help me with this.
Here is what it looks like:
Here is the start of the code:
import SwiftUI
struct PopupView: View {
#State var painted = CGFloat(10)
#State var unpainted = CGFloat(1)
#State var sPainted = CGFloat(5)
#State var sUnpainted = CGFloat(6)
var body: some View {
Color.white
VStack(alignment: .leading, spacing: 0) {
HStack {
Text("T'IS IS STATIC HEADER TXT")
.tracking(2)
.foregroundColor(Color.euGray)
.fontWeight(.bold)
.font(.system(size: 12))
.padding(.leading, 100)
.padding(.trailing, 20)
Image("close")
.frame(width: 35, height: 35, alignment: .trailing)
}
}.frame(width: 400, alignment: .topLeading)
ScrollView(showsIndicators: false) {
VStack(alignment: .center) {
Image("qr")
.resizable()
.clipped()
.padding(.top)
.frame(width: 320, height: 320, alignment: .center)
.padding(.top, 5)
Text("JOHN APPLESEED")
.foregroundColor(Color.nameGray)
.fontWeight(.heavy)
.font(Font.custom("Source Sans Pro" ,size: 27))
.padding(.top, 10)
Text("01.01.1976")
.foregroundColor(.gray)
.fontWeight(.regular)
.font(.system(size: 13))
}.frame(width: 320)

Related

Variable Rectangle() dimension based on cell size to draw a timeline

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)
}
}

Center Image in VStack leading alignment

I'm having troubles figuring out the proper solution to centre an Image inside a VStack with an alignment of .leading. I've attempted and got these results but is there a more efficient way instead of adding two Spacer()'s in an HStack?
struct ContentView: View {
var body: some View {
ZStack {
ScrollView {
VStack (alignment: .leading, spacing: 10) {
Text("Title ")
HStack {
Spacer()
Image(systemName:"star.fill")
.resizable()
.frame(width: 20, height: 20, alignment: .center)
Spacer()
}
Divider()
}
}
}
.padding(.all)
}
}
Here is a solution. Tested with Xcode 12.1 / iOS 14.1
ScrollView {
VStack (alignment: .leading, spacing: 10) {
Text("Title ")
Image(systemName:"star.fill")
.resizable()
.frame(width: 20, height: 20)
.frame(maxWidth: .infinity, alignment: .center)
Divider()
}
}

SwiftUI bug or code issue with onTapGesture combine with other View?

I want SwiftUI could understand where I am tapping on my app, therefore I gave .onTapGesture possibility to my Views, in this codes a View is bigger than its parent View but I could fix the issue with clip, the issue get fixed visually, but in codes SwiftUI see the Rec in original size, I wanted to know if this miss-behaviour is a bug in SwiftUI, or code we solve it with some magic codes? thanks for all.
gif:
struct ContentView: View {
var body: some View {
ZStack {
Color.white.ignoresSafeArea()
.onTapGesture { print("you tapped on Screen!") }
Circle()
.fill(Color.red)
.frame(width: 300, height: 300, alignment: .center)
.overlay(
Rectangle()
.fill(Color.yellow)
.frame(width: 100, height: UIScreen.main.bounds.height, alignment: .center)
.onTapGesture { print("you tapped on Rectangle!") }
)
.clipShape(Circle())
.onTapGesture { print("you tapped on Circle!") }
}
}
}
Just use contentShape(Circle()) before the onTapGesture and it is fixed
Circle()
.fill(Color.red)
.frame(width: 300, height: 300, alignment: .center)
.overlay(
Rectangle()
.fill(Color.yellow)
.frame(width: 100, height: UIScreen.main.bounds.height, alignment: .center)
.onTapGesture { print("you tapped on Rectangle!") }
)
.clipShape(Circle())
.contentShape(Circle()) //<< contentShape here
.onTapGesture { print("you tapped on Circle!") }

SwiftUI Two Row NavigationBar

Is there a way using SwiftUI to get a two row NavigationBar like instagram has? Even better would be two rows with a fullwidth search bar like in the image.
ex.
Here you go an example close to the image, of course it can be redesigned to suit your needs I did it very quickly it doesn't look nice, but as I said it can be redesigned to look much nicer:
#State var testok = ""
var body: some View {
VStack {
VStack {
TextField("search here man", text: $testok)
.frame(maxWidth: .infinity)
.frame(height: 40)
.background(Color.red)
.cornerRadius(10)
.padding()
ScrollView(.horizontal){
HStack(spacing: 0) {
Text("ok")
.frame(width: 80, height: 50)
.background(Color.green)
.cornerRadius(8)
.padding(.horizontal, 10)
Text("yumyum")
.frame(width: 80, height: 50)
.background(Color.green)
.cornerRadius(8)
.padding(.horizontal, 10)
Text("lool")
.frame(width: 80, height: 50)
.background(Color.green)
.cornerRadius(8)
.padding(.horizontal, 10)
Text("pewpew")
.frame(width: 80, height: 50)
.background(Color.green)
.cornerRadius(8)
.padding(.horizontal, 10)
}
}
}
NavigationView {
NavigationLink(destination: Text("ok")) {
Text("ok")
.navigationTitle(Text("navigation title"))
}
}
}
}

how to strech image on one side in swiftUI, like a .9 file in Android?

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)
}
}
}