Getting rid of SwiftUI ScrollView top padding - swiftui

I just can't seem to get rid of the ~6 height padding(?) at the top of ScrollView. I've tried setting padding to 0 on both the ScrollView itself and on it's content. I've tried using SwiftUI-Introspect to get at the content insets, but they appear to already be 0 for the top. I could just use offset(y: -6), but I'd like to understand what is causing the padding. Does anyone know?
var body: some View {
VStack(spacing: 0) {
Rectangle()
.frame(width: UIScreen.main.bounds.width, height: 200)
.foregroundColor(.blue)
Rectangle()
.frame(width: UIScreen.main.bounds.width, height: 200)
.foregroundColor(.red)
ScrollView {
Rectangle()
.frame(width: UIScreen.main.bounds.width, height: 200)
.foregroundColor(.black)
}
}
}

Related

SwiftUI - Sheet shows Data half way down the sheet

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)

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

How to detect whether the scrollview was scrolled or not in SwiftUI?

I have a horizontal ScrollView and would like to provide a function that when the first element is not visible anymore an arrow should appear to signalize that there are some other elements.
I've tried the DragGesture() to read the translation.width but it seems to be buggy in combination with the ScrollView.
So I'm looking for a way to detect whether the ScrollView was scrolled and how far. Is there any way?
private let gridItems = [GridItem(.flexible())]
ScrollView(.horizontal, showsIndicators: false) {
HStack{
LazyHGrid(rows: gridItems){
ForEach(viewModel.imageOptions, id: \.self){ image in
ZStack {
Image(image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 60, height: 60)
.background(Color.white)
.clipShape(Circle())
.background(
Circle()
.clipShape(Circle())
.shadow(color: Color.black.opacity(0.4), radius: 3, x: 5.0, y: 5.0)
)
.onTapGesture {
print("selected")
}
.padding(15)
Circle()
.strokeBorder(Color.orange, lineWidth: 5)
.frame(width: 70, height: 70)
}
}
}
}
}
}

Force SwiftUI view to overflow in trailing direction instead of expanding in both directions

I have a SwiftUI view in an HStack that will be wider than it's parent. When this happens, the HStack expands in both leading and trailing directions, despite being put in a VStack with alignment set to .leading (which I had hoped would anchor the leading edge).
Consider the following simplified Playground code:
import SwiftUI
import PlaygroundSupport
struct TestView : View {
var body: some View {
VStack {
VStack(alignment: .leading) {
HStack {
Rectangle()
.foregroundColor(Color.red)
.frame(width: 20)
Rectangle()
.foregroundColor(.green)
}.frame(height: 40)
HStack {
Rectangle()
.foregroundColor(.orange)
.frame(width: 10)
Rectangle()
.foregroundColor(.green)
.frame(width: 200)
Rectangle()
.foregroundColor(.yellow)
.frame(width: 10)
}
.frame(height: 40)
HStack {
Rectangle()
.foregroundColor(.orange)
.frame(width: 10)
Rectangle()
.foregroundColor(.green)
.frame(width: 200)
Rectangle()
.foregroundColor(.yellow)
.frame(width: 10)
}
.frame(height: 40)
}
.border(Color.red)
}
.frame(width: 300, height: 400)
.border(Color.black)
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = UIHostingController(rootView: TestView())
In the above example, everything fits within the view and behaves as expected:
However, change the last green Rectangle to a width of 500 instead of 200, and the following happens:
You can see that the orange leading Rectangle has disappeared, pushed off to the left. Similarly, the yellow Rectangle at the end has been pushed to the right.
What I would like to have happen is have the orange Rectangle visible, meaning that all 3 HStacks would have the same x origin (0). So, the result would be seeing the orange Rectangle on the left, the green visible, but spilling over to the right, and the yellow invisible, since it would be pushed off the screen.
I assume this may have to do with using clipped() or fixedSize but I haven't been able to find a working solution yet.
The easiest solution (no workarounds or other views required) is to set the alignment in the frame modifier of the outer VStack to .leading like this:
struct TestView : View {
var body: some View {
VStack {
VStack(alignment: .leading) {
HStack {
Rectangle()
.foregroundColor(Color.red)
.frame(width: 20)
Rectangle()
.foregroundColor(.green)
}.frame(height: 40)
HStack {
Rectangle()
.foregroundColor(.orange)
.frame(width: 10)
Rectangle()
.foregroundColor(.green)
.frame(width: 200)
Rectangle()
.foregroundColor(.yellow)
.frame(width: 10)
}
.frame(height: 40)
HStack {
Rectangle()
.foregroundColor(.orange)
.frame(width: 10)
Rectangle()
.foregroundColor(.green)
.frame(width: 500)
Rectangle()
.foregroundColor(.yellow)
.frame(width: 10)
}
.frame(height: 40)
}
.border(Color.red)
}
.frame(width: 300, height: 400, alignment: .leading) //<= here
.border(Color.black)
}
}
struct TestView : View {
var body: some View {
VStack {
VStack(alignment: .leading) {
HStack {
Rectangle()
.foregroundColor(Color.red)
.frame(width: 20)
Rectangle()
.foregroundColor(.green)
}.frame(height: 40)
HStack {
Rectangle()
.foregroundColor(.orange)
.frame(width: 10)
Rectangle()
.foregroundColor(.green)
.frame(width: 200)
Rectangle()
.foregroundColor(.yellow)
.frame(width: 10)
}
.frame(height: 40)
HStack {
GeometryReader{_ in
Rectangle()
.foregroundColor(.orange)
.frame(width: 10)
.offset(x: 0)
Rectangle()
.foregroundColor(.green)
.frame(width: 500)
.offset(x: 10)
Rectangle()
.foregroundColor(.yellow)
.frame(width: 10)
.offset(x: 510)
}
}
.frame(height: 40)
}
.border(Color.red)
}
.frame(width: 300, height: 400)
.border(Color.black)
}
}

Aligning image to navigationBarTitle in SwiftUI

I'm trying to add a User Image (button) next to the .navigationBarTitle, but with the code bellow, the image appears on top of the title alignment. (picture attached). Many thanks for your help!
.navigationBarTitle(Text("Watch"))
.navigationBarItems(trailing:
Image("User")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 36, height: 36)
.clipShape(Circle())
)
Image should be bottom - aligned to the text
This code produces this view:
struct ContentView: View {
var body: some View {
NavigationView {
List {
Text("Chocolate")
Text("Vanilla")
Text("Strawberry")
}.navigationBarTitle(Text("Watch"))
.navigationBarItems(trailing:
Image(systemName: "person.circle")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 36, height: 36)
.clipShape(Circle())
.padding(.top, 90)
)
}
}
}
There is a default space for the Items and a default space for the Text. Imagine it like two HStacks in a VStack. Where the Title is in the lower HStack and the items are in the upper one. There is no "real" way on getting in the lower one.
I'd recommend to create an own NavigationBar for your purposes.
Thanks #Simon, the best option for what I was looking for is to Add the User Icon to the Title (not NavBar) and apply an Offset of y: -55. When scrolling up the icon disappears under the NavBar. The same effect on the Apple TV app (mobile).` VStack(alignment: .leading) {
HStack {
Text("Children")
.font(.title)
.fontWeight(.bold)
.padding(.leading, 24)
.padding(.top, 20)
Spacer ()
Image("User")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 36, height: 36)
.clipShape(Circle())
.offset(y: -55)
.padding(.trailing, 24)[final result][1]`