SwiftUI Horizontal ScrollView onTapGesture is Off - swift

I am experiencing some very odd behavior from a Horizontal ScrollView, it seems as if the clickable frame of the cells are offset. For example, if you click on left half of the first cell it will register the click for the first cell, but if you click the right half of the first cell it will register a click on the second cell. I'm not sure why this is happening.
I've included the code below, you can copy and paste this code into a playground to reproduce the issue. Any ideas here?
struct TestView: View {
var image: String
var body: some View {
ZStack {
Image(systemName: image)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 104, height: 168)
.cornerRadius(8)
.clipped()
VStack {
Spacer()
Text("Testing")
.foregroundColor(Color.white)
.frame(alignment: .leading)
.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
.shadow(radius: 5)
Text("1:40")
.foregroundColor(Color.white)
.frame(alignment: .leading)
.padding(EdgeInsets(top: 3, leading: 10, bottom: 10, trailing: 10))
.shadow(radius: 5)
}
.frame(width: 104, height: 168)
}
}
}
struct TestViewCollection: View {
var collection = ["tv", "faxmachine", "printer"]
var body: some View {
ScrollView {
HStack {
ForEach(collection, id: \.self) { image in
TestView(image: image)
.onTapGesture {
print(image)
}
}
}
}
}
}
PlaygroundPage.current.setLiveView(TestViewCollection())

The issue is that your images are not the same aspect ratio as the frame you have put them in, so they are overflowing the frame. The solution is pretty simple. Instead of using .clipped() which just clips what you can see, use .contentShape() which will will provide an area that the .tapGesture() will use as its tappable area. Like this:
Image(systemName: image)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 104, height: 168)
.cornerRadius(8)
.contentShape(Rectangle())

the problem is:
Image(systemName: image)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 104, height: 168)
.cornerRadius(8)
.clipped()
Change that .aspectRatio(contentMode: .fill). -> into .fit
if you just move .clipped() like this:
Image(systemName: image)
.resizable()
.aspectRatio(contentMode: .fill)
.clipped()
.frame(width: 104, height: 168)
You are going to see:
That's why is happening.

Related

SwiftUI how to make UI Responsiv

UI on iPhone Pro Max here the UI is not in the right place
UI on iPhone Pro thats perfectly
Hello I am new to SwiftUI and have a question. I had to implement the UI with the Star and the Number Count. I did everything, but when I switch the phones my UI is miss placed depends on the iPhone I choose. How can I fix that ? I search in the Internet for Responsiveness in SwiftUI but it didn't really helped me. I thought also that SwiftUI does most of the Responsiveness because I know in UIKIT you have to declare the constraints by yourself. Thanks for helping me, the Code is below. I also have after the CustomerCardPoints an List which works perfectly but since I added the CustomerCardPoints there is a small space between the Views, if anybody has experience how can I fix that also? (Not Necessary)
var body: some View {
VStack(spacing: 0) {
shopModel.logo
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 200, maxHeight: 100)
.padding([.top, .leading, .trailing])
Text(shopModel.name)
.fontWeight(.bold)
.padding()
CustomerCardPoints()
}
struct CustomerCardPoints: View {
var body: some View {
VStack(){
ZStack() {
Image("Slice")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 180, maxHeight: 60)
.offset(x: 160, y: -127)
HStack(alignment: .firstTextBaseline) {
Text("22")
.font(.system(size: 19))
.fontWeight(.bold)
.foregroundColor(.white)
.offset(x: 237, y: -126)
Image("favoriten")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 110, height: 25)
.offset(x: 132, y: -120)
}
}
}
}
}

Format number inside image bubble

I'm having some trouble understanding how to properly align items in top of each other:
So I have the following VStack:
VStack(spacing: 0) {
Text("\(placeC.places.count)")
Image("map-pin-full-cluster-1")
.renderingMode(.template)
.resizable()
.frame(width: 35, height: 35)
.foregroundColor(.brown)
} //: END VStack
Which produces the following output:
What is the best way to have the number inside the circle? Is there a recommended SwiftUI builder that you all use that I can explore?
Typically you would use an .overlay:
Image("map-pin-full-cluster-1")
.renderingMode(.template)
.resizable()
.frame(width: 35, height: 35)
.foregroundColor(.brown)
.overlay(alignment: .top) {
Text("\(placeC.places.count)")
}
or a ZStack:
ZStack(alignment: .top) { // other alignments: .center, .bottom, .leading, .trailing
Image("map-pin-full-cluster-1")
.renderingMode(.template)
.resizable()
.frame(width: 35, height: 35)
.foregroundColor(.brown)
Text("\(placeC.places.count)")
.padding(.top, 4) // adjust this to move the text up/down
}

SwiftUI NavigationLink doesn't work with Spacer

I build the following View:
NavigationView{
VStack(spacing: 120){
HStack{
Spacer()
NavigationLink(destination: LoginView()){
Image(systemName: "person.crop.circle")
.resizable()
.frame(width: 40, height: 40)
.foregroundColor(.primary)
.padding()
}
}
VStack{
Image("pic1")
.resizable()
.frame(width: 200, height: 160)
.padding()
Image(colorScheme == .dark ? "pic2" : "pic3")
.resizable()
.frame(width: 200, height: 65)
.padding()
}
Spacer(minLength: 250)
}
}
I need this Spacer(minLength: 250) to get the image (circle) on the top left corner. But when I do this, the Image does not work as a NavigationLink. When I delete this Spacer everything is centered and the Link works. How can I get it in the position I want and get the link work?
use navigationBarHidden(true):
NavigationView {
VStack(spacing: 120) {
...
Spacer() // no need for minHeight
}
.navigationBarHidden(true) // << here
}
not sure if you have got your issue sorted
but based on your question, if I understand it properly you want to have the Image(systemName: "person.crop.circle") in the top left corner when clicked it should navigate to the new View
if you want the image to be in the top right corner instead you just need to change the placement of the ToolbarItem
i can't post any images yet so I included a gif link
here is the code, i use the ToolbarItem and add NavigationLink in it
let me know if this help
Cheers,
Jono
NavigationView{
VStack(spacing: 120){
VStack{
Image("pic1")
.resizable()
.frame(width: 200, height: 160)
.padding()
Image(colorScheme == .dark ? "pic2" : "pic3")
.resizable()
.frame(width: 200, height: 65)
.padding()
}
Spacer(minLength: 250)
}
.toolbar {
ToolbarItem(placement: .navigationBarLeading){
NavigationLink(destination: LoginView()){
Image(systemName: "person.crop.circle")
.resizable()
.frame(width: 40, height: 40)
.foregroundColor(.primary)
.padding()
}
}
}
}

onTapGesture does only partially work on a ZStack

I have build a ZStack containing an image, an overlay and a systemImage. I want to open a sheet when the user taps on this image but it only works when the user clicks on a very specific point on the very bottom of the ZStack. Does anyone know how I can make this work? And also why this doesn't work?
My code:
NavigationView {
VStack {
VStack {
ZStack {
if let image = pfimage {
Image (uiImage: image)
.resizable()
.frame(width: 100, height: 100)
} else {
Image ("testimage")
.resizable()
.frame(width: 100, height: 100)
}
Image(systemName: "photo")
.resizable()
.frame(width: 30, height: 25)
.foregroundColor(Color.white)
}
.clipShape(Circle())
.contentShape(Circle())
.onTapGesture {
print("tap")
changepfsheet = true
}
Text("Displayname")
.padding(.top)
.foregroundColor(Color.white)
.font(.title3)
}
.frame(width: UIScreen.main.bounds.width, height: 225)
.background(Color.red)
HStack {
Image(systemName: "person.2.circle")
TextField("Enter newdisplayname", text: $newdisplayname)
}
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
.padding(.horizontal)
.padding(.top, 25)
Text("Change displayname")
Spacer()
HStack {
Spacer()
Text("Change password")
.foregroundColor(Color.white)
Spacer()
Image(systemName: "key")
.foregroundColor(Color.white)
}
.padding()
.background(Color.red)
.cornerRadius(15)
.padding(.horizontal)
.padding(.bottom, 5)
HStack {
Spacer()
Text("Logout")
Spacer()
}
.padding(.horizontal)
.padding(.bottom, 20)
}
.edgesIgnoringSafeArea(.top)
Spacer()
}
.navigationBarHidden(false)
.navigationBarBackButtonHidden(false)
You have interfering tap gestures. Instead, just have one tap gesture on the ZStack. Now you can tap anywhere on it:
ZStack {
Image(uiImage: image)
.resizable()
.frame(width: 100, height: 100)
Color.black.opacity(0.5)
.frame(width: 100, height: 100)
Image(systemName: "photo")
.resizable()
.frame(width: 30, height: 25)
.foregroundColor(.white)
}
.clipShape(Circle())
.contentShape(Circle())
.onTapGesture {
print("tap")
showsheet = true
}
I suspect the real issue is that you using a NavigationView, and putting content behind where the title would be. That means that you can't click through the view that the title is in, even if it's an empty title. You should either remove the NavigationView (as you aren't making use of it) or don't ignore safe area and use a NavigationView as you should do.
Removing edgesIgnoringSafeArea(.top) makes your code work, because the content will no longer be behind the navigation bar.

SwiftUI NavigationView not see Image

I have a code and make NavigationLink Button, I write Text and Image, But my Image not a see. Pls help me.
VStack{
Image("Coachs")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 370, height: 200)
//.clipped()
.cornerRadius(20.0)
NavigationLink(destination: Text("Detail view here")){
ZStack{
Text("Press on me")
.foregroundColor(.white)
.font(.largeTitle)
Image("Coachs")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 370, height: 200)
//.clipped()
.cornerRadius(20.0)
}
}}
I make screen if you can't understand
ok, I looked at other image types, try this, it should work:
Image("IMG_4944")
.renderingMode(.original) // <----- this
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 370, height: 200)
.clipped()
.cornerRadius(20.0)
This looks like SwiftUI bug of handling raster images. Please find below approach for workaround. Tested with Xcode 11.4 / iOS 13.4
This is an example of cell to be used for your goal. Of course in real case the image name and navigation link destination, etc., can be injected via constructor parameters for reuse purpose.
struct TestImageCell: View {
#State private var isActive = false
var body: some View {
Image("large_image") // raster !! image
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 370, height: 200)
.cornerRadius(20.0)
.overlay(
Text("Press on me") // text is over
.foregroundColor(.white)
.font(.largeTitle)
)
.onTapGesture { self.isActive.toggle() } // activate link on image tap
.background(NavigationLink(destination: // link in background
Text("Detail view here"), isActive: $isActive) { EmptyView() })
}
}
I made this test from your code, and all works well, ios 13.4 and catalyst, xcode 11.4 and macos catalina 10.15.4
var body: some View {
NavigationView {
VStack {
Image(systemName: "person.2.fill")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 370, height: 200)
//.clipped()
.cornerRadius(20.0)
NavigationLink(destination: Text("Detail view here")){
ZStack{
Image(systemName: "person.2.fill")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 370, height: 200)
//.clipped()
.cornerRadius(20.0)
Text("Press on me")
.foregroundColor(.black)
.font(.largeTitle)
}
}
}
}.navigationViewStyle(StackNavigationViewStyle())
}