SwiftUI: Button Nested Inside ScrollView Won't Fire (WatchOS) - swift

I've tried everything I can think of but I can't get this button to fire consistently when nested inside a ScrollView. If I change the ScrollView to a List, it works fine, but I don't want the UI of a list on the Watch, I would prefer to use a ScrollView. I think it's related to the system detecting taps to scroll and taps on the button but not sure how to fix or any workarounds?
struct WatchWorkoutSummaryView: View {
#EnvironmentObject var workoutManager: WorkoutManager
var body: some View {
ScrollView {
EffortLevelRingViewForWatch(workoutState: WatchWorkoutState.After)
Divider()
.padding(.horizontal)
IntensityViewForWatch()
Divider()
.padding(.horizontal)
HeartRateZonesViewForWatch(workoutState: WatchWorkoutState.After)
Divider()
.padding(.horizontal)
AerobicAnaerobicWatchMasterView()
Divider()
.padding(.horizontal)
VStack {
SummaryView().environmentObject(workoutManager)
Button(action: {
print("button is tapped")
workoutManager.dismissLiveWorkoutTabViewSheet()
workoutManager.resetWorkoutManager()
}, label: {
Text("Done")
.foregroundColor(.white)
})
.background(
Color.buttonColor
.cornerRadius(10)
)
.buttonStyle(BorderedButtonStyle(tint: .clear))
.padding(.horizontal)
.animation(nil)
}
.padding(.vertical)
}
//This doesn't work.
.animation(nil)
}
}

Related

Why the button doesn't work in SwiftUI when it is located in some condition

Why the button doesn't work in this code by using SwiftUI?
I can't click the button.
When I lay the button on the top in VStack, it can work.
But when it is in below code, it can't work properly.
Is this related to VStack, TabView or button's overlay?
I think it is caused by button's offset and padding & tabview's padding.
Can I change it to ZStack in all same layout?
Please tell me how to do.
Thank you.
struct Profile: View {
#State private var selection = 0
var body: some View {
VStack{
VStack{
HStack{
Spacer()
Image(systemName: "person.circle")
Spacer()
}
HStack{
Text("|")
.foregroundColor(.white)
Image(systemName: "birthday.cake")
Text("birthDay")
}
}
.frame(height: 300)
.padding(.bottom,50)
Button(action: {
print("hello")
}){
Text("edit")
.fontWeight(.semibold)
.frame(width: 200, height: 48)
.foregroundColor(Color(.red))
.background(Color(.white))
.cornerRadius(24)
.overlay(
RoundedRectangle(cornerRadius: 24)
.stroke(Color(.red), lineWidth: 1.0)
)
.offset(y: -35)
.padding(.bottom, -20)
.contentShape(RoundedRectangle(cornerRadius: 20))
}
TabView(selection: $selection) {
VStack{
HStack{
Text("note")
}
}
.tag(0)
VStack{
Text("phone")
}
.tag(1)
}
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
.frame(height:200)
.padding(.top,-60)
.padding(.horizontal)
}
}
}
The padding
.padding(.top,-60)
is covering your button.
Add the below line just after the padding, you'll see tabview covering the button with green transparent background.
.background(Color.green.opacity(0.4))
Just remove the .padding(.top,-60) and the button will click.
Add "Spacer()" underneath the Button
Spacer()
Spacer between Button() and Tabview() will enable the button to be clickable.

Disable to Change Page On Swipe of Tab View in SwiftUI

I am using Tab View in my SwiftUI app. I want the changing of page disabled, while swiping left or right. And I had achieved it from this. This works fine but the issue I am facing is I have a button on the bottom of every view, and when I try to swipe from the button, it is swiping left right. I want to disable it too but don't know how to do it. Here is my code:
struct TabViewTesting: View {
#State var tabSelection = 0
var body: some View {
TabView(selection: $tabSelection) {
firstView().tag(0).contentShape(Rectangle()).gesture(DragGesture())
secondView().tag(1).contentShape(Rectangle()).gesture(DragGesture())
thirdView().tag(2).contentShape(Rectangle()).gesture(DragGesture())
}.tabViewStyle(.page(indexDisplayMode: .never))
}
}
And this is the code for the Views:
extension TabViewTesting {
func firstView() -> some View {
VStack {
Text("First screen")
Spacer()
Button {
self.tabSelection = 1
} label: {
ZStack {
RoundedRectangle(cornerRadius: 20)
.frame(height: 50)
Text("move to 2nd view")
.foregroundColor(.white)
}
}.padding()
}.background(.green)
}
func secondView() -> some View {
VStack {
Text("second screen")
Spacer()
Button {
self.tabSelection = 2
} label: {
ZStack {
RoundedRectangle(cornerRadius: 20)
.frame(height: 50)
Text("move to 3rd view")
.foregroundColor(.white)
}
}.padding()
}.background(.red)
}
func thirdView() -> some View {
VStack {
Text("Third screen")
Spacer()
Button {
self.tabSelection = 0
} label: {
ZStack {
RoundedRectangle(cornerRadius: 20)
.frame(height: 50)
Text("move to first view")
.foregroundColor(.white)
}
}.padding()
}.background(.yellow)
}
}
And this is what happening:
I actually found an answer in the comments of this question.
The issue is: any view that has an "onTapGesture" will ignore ".gesture(DragGesture())".
The solution is to use ".simulataneousGesture(DragGesture())" instead to ensure the gesture is capture and handled by both view/modifier.
It worked perfectly in my case after changing it. The only exception is for 2 finger drag gesture.

Spacer not pushing view to top of screen inside ZStack?

How can I position my search-bar and button to the top of the screen with 65 padding from the top AND KEEP the onTapGestureFunctionality?
I tried the modifiers .edgesIgnoringSafeArea(.top) with padding(.top, 65) applied to the VStack inside my ZStack but then my onTapGesture would not work when tapping on either the search bar or the button...
Why does the Spacer() only push the elements about 80% to the top of the screen? Could this be because its inside a navigation view?
See image below.
Thank you
struct MapScreen: View {
var body: some View {
NavigationView {
ZStack(alignment: .bottom) {
VStack {
HStack(spacing: 15) {
SearchBar()
.padding(.leading, 5)
.onTapGesture {
print("search pressed")
}
ActivateClaimButton()
.onTapGesture {
print("claim pressed")
}
}
// 2 modifiers below positions correctly but
// onTapGesture doesn't work
// .padding(.top, 65)
// .edgesIgnoringSafeArea(.top)
Spacer()
}.zIndex(2)
MapView(locations: $locations, spotArray: $spotArray).edgesIgnoringSafeArea([.top, .bottom])
BottomNavBar().zIndex(1).edgesIgnoringSafeArea(.all).offset(y: 35)
}
.navigationViewStyle(StackNavigationViewStyle())
.fullScreenCover(isPresented: $presentSearchView, content: {
SearchView()
})
}
}
}
The answer that worked for me was
.navigationBarHidden(true)

SwiftUI Button Size/Shape/Color Not Changing

I'm trying to make custom buttons for a MacOS app using SwiftUI, however, I seem to be unable to resize the button area and the button's color doesn't seem to be changeable. All the examples I find online say to either use .frame or .padding to set width and height but that doesn't change the shape of the button. Has anyone else experienced this while developing a MacOS app? Image of button here
struct customButton: View {
var body: some View {
Button(action: {
print("Delete button tapped!")
}) {
HStack {
Image(systemName: "trash")
.resizable()
.scaledToFit()
.imageScale(.large)
Text("Delete")
}
.padding()
.background(
Capsule().strokeBorder(Color.white, lineWidth: 1.25)
)
}
.accentColor(Color.white)
}
}
You have to use .buttonStyle(PlainButtonStyle()) to get rid of the default button UI.
Button(action: {
print("Delete button tapped!")
}) {
HStack {
Image(systemName: "trash")
.resizable()
.scaledToFit()
.imageScale(.large)
Text("Delete")
}
.padding()
.background(
Capsule().strokeBorder(Color.white, lineWidth: 1.25)
)
}
.accentColor(Color.white)
.buttonStyle(PlainButtonStyle())

NavigationBarTitle automatic display mode doesn't work

I am unsure how to fix this. I have implemented a ScrollView and a NavigationView with ZStacks. However, the automatic display mode doesn't work and the ScrollView sits behind it, with the Title overlapping.
https://i.stack.imgur.com/KPkGh.png
https://i.stack.imgur.com/H8NwS.png
Here is my current code:
struct Overview: View {
var body: some View {
ZStack{
NavigationView {
ZStack {
Color.init("Background")
.navigationBarHidden(false)
.navigationBarTitle("Overview", displayMode: .automatic)
.edgesIgnoringSafeArea(.top)
ScrollView(showsIndicators: false) {
VStack(spacing: 10) {
ForEach(0..<10) {
Text("Item \($0)")
.foregroundColor(.white)
.font(.largeTitle)
.frame(width: 340, height: 200)
.background(ColorManager.BoxColor)
.cornerRadius(10)
}
}
.frame(maxWidth: .infinity)
}
}
}
}
}
}
var body: some View {
NavigationView {
ScrollView(showsIndicators: false) {
VStack(spacing: 10) {
ForEach(0..<10) {
Text("Item \($0)")
.foregroundColor(.blue)
.font(.largeTitle)
.frame(width: 340, height: 200)
.background(Color(.gray))
.cornerRadius(10)
}
}
.frame(maxWidth: .infinity)
}
.navigationBarHidden(false)
.navigationBarTitle("Overview", displayMode: .automatic)
}
}
You had the navigation item in a ZStack. A ZStack is used to display overlapping views on top of each other.
I believe what you really were looking to achieve stacking the title above the scrollView. That would be achieved with VStack. That however, would still be wrong.
Because it's a navigational setting, it goes inline with the NavigationView. So it can be displayed in the NavigationBar. It doesn't need to be apart of any Stacks.