Exclude button from disabling - swift

I have custom view with different content inside including Button.
For example:
VStack {
Text("Some text")
Button() // 1-th
Button() // 2-th
.disabled(false) // This doesn't help, despite it logical
}
.disabled(true) // Line with disabling
I want 2-th button to be always enabled no matter what is set in "Line with disabling".

According to the documentation this does not work that way. It works the other way around. As you allready discovered the .disable on the parent overrides the value set in the child.
Possible solution would be to not use the parent .disable instead use it on each child element.

Related

Better way of handling Tap Gesture on Lists

I'm trying to implement a 1 count tap gesture and 2 count tap gesture on rows of a list view.
Currently I'm achieving this by expanding the contents of the rows to fill the entire width and height, by changing the row insets with .listRowInsets(EdgeInsets()) and adding an HStack with a Spacer inside. As seen below:
My ListRow View, which serves to attempt to fill out the the entire rows' width and height. (With a red border for debugging):
struct ListRow<Content: View> : View {
let content: () -> Content
var body: some View {
HStack {
content()
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.contentShape(Rectangle())
.border(Color.red)
}
}
And here's a snippet of one of the two places I'm using a list with my ListRow:
List(selection: $selectedItem) {
Section(header: Text("Favourites")) {
ForEach($sidebarItems, id: \.self) { $item in
ListRow {
FileLabel(URL(string: item.path)!, size: 14, text: item.text)
}.gesture(TapGesture().onEnded {
selectedItem = item
fileState.updatePath(path: item.path)
}).listRowInsets(EdgeInsets())
}
}
}.listStyle(SidebarListStyle())
A few issues happen here, which both feels hacky and incorrect to do.
I have to manually select the row when the content is tapped.
I actually manually have to focus the list, if it's not actually focused when clicking a row, otherwise the selection is a very faint color.
The contents aren't actually expanding to the leading and trailing edges of the row, no matter if I give my EdgeInsets negative values (This just results in the contents getting clipped, rather than expanding to the edge).
Clicking the areas outside of the red border (seen below) results in the row being selected, but the tap action not firing.
Preferably I'd love if there was a way to listen for tap gestures on a list and get the row that was tapped. It would fix having to manually reimplement features that the List already has built-in and lowering the risk of introducing bugs + it just feels like the right way to do it, unfortunately I haven't been able to find other ways of implementing this, other than creating an HStack with a Spacer.
EDIT:
I'm curious as to how NavigationLink works as no matter where you click, or if you navigate using your keyboard, it'll actually trigger the navigation. Makes me think there's some kind of binding or event fired?

SwiftUI Animation Bindings

struct ContentView: View {
#State private var animationAmount = 1.0
var body: some View {
VStack
{
Stepper("Scale amount", value: $animationAmount.animation(.linear), in: 1...10)
Spacer()
Button("Tap Me")
{
animationAmount += 1
}
.padding(50)
.background(.red)
.foregroundColor(.white)
.clipShape(Circle())
.scaleEffect(animationAmount)
}
}
}
So I have a tiny question, here I made a Stepper view with value being some way two binding of a variable and then I called the .animation method on that binding which from what I understood, if any changes happen to that binding they simply get animated.
My question is, is it specifically only changes that relate to the binding value that get animated? Or if some other changes happen to this view but coincidentally they happened a bit before the binding changed would those changes get animated too?
And another super super tiny question, why is it exactly that I can't put an if statement in this VStack that will increment animationAmount?
like
if animationAmount > 1.0
{
animationAmount += 0.25
}
Just says that () doesn't conform to View.
By definition, .animation(_:value:):
Applies the given animation to this view when the specified value changes.
So yes, the animation applies only when the value you passed changes, see more: .animation(_:value:)
To answer your second question,VStack, HStack,... & body are ViewBuilders. Meaning they require you to pass in a View, whereas animationAmount += 0.25 is of type Void != View. So what you should do is use .onChange:
.onChange(of: animationAmount) { newValue in
if animationAmount > 1.0 {
animationAmount += 0.25
}
}
First question: .animation works by animating a specific component whenever the value of this component changes.
eg: foregroundColor(color.animation) meaning that if the value of variable color changes, animation will happen BUT only to this foregroundColor component, unless you give another component color.animation too. Any other changes in view/variable beside this variable color will not apply animation to this foregroundColor. Any change even a very small change of variable color will animate the foregroundColor.
There is another different type of animation called withAnimation.
eg: withAnimation { isViewed = true }, now all the views or modifiers that relate to this variable isViewed will be animated.
Second question: To make it easy to understand, you simply can’t make any calculation/logic process inside a SwiftUI View Bracket. An ifelse{} statement inside a VStack or var body expects Views, so you can’t make any calculation there because it is not a view. Any code inside this ifelse bracket {. . .} shall be views only.
However, an ifelse{} statement inside a Button Action or onTapGesture is an opposite story. You can make any calculation/logic process there except displaying views. To understand formally about these concepts you should explore more about the basic of SwiftUI.

Issue with giving a title to a menu

I want to give a text name for this menu but it won't let me saying there's an Extra argument in call what's wrong ? PS: I'm a beginner in coding
Divider()
Menu("\(buttonTitle)" ) {
Button("Riyadh",action: {SelectRiyadh()})
Button("Dammam",action: {SelectDammam()})
Button("Jeddah",action: {SelectJeddah()})
Button("Mecca",action: {SelectMecca()})
}
We need to see the ContentView page, but try to wrap all that code in some group or into stack, for example VStack.
Anyway, read this article first: How to show a menu when a button is pressed
VStack{
Divider()
Menu("\(buttonTitle)" ) {
Button("Riyadh",action: {option()})
}
}

SwiftUI: How to Disable List Scrolling on Reusable View

I've got an interesting glitch in SwiftUI -
I'm using a List as part of my interface that is intended to be un-scrollable. This is how I've designed it:
List {
ForEach(myArr) {
...
}
}
.listStyle(.plain)
.onAppear {
UIScrollView.appearance().isScrollEnabled = false
UIScrollView.appearance().showsVerticalScrollIndicator = false
}
Now, when I first load the view containing this list, it works perfectly; you cannot scroll this list. However, if I navigate to a different page in my application and then back to the page containing this list (which creates a new instance of the view), scrolling becomes enabled.
How can I fix this?
Use .disabled(true) on the list to disable interaction with the list.

SwiftUI TextField wobble on text change. Doesn't reproduce on all machine

So I made a simple app with simple text field instance bound to a local variable in SwiftUI
TextField("Main task", text: $store.mainTask)
.textFieldStyle(RoundedBorderTextFieldStyle())
.font(Font.custom("SF Pro Display", size: 14))
The text field is wrapped inside a view with transition and animation.
// text field is inside custom View
// conditional rendering—if that matters
if (true) {
CustomView()
.transition(.asymmetric(insertion: AnyTransition.opacity.animation(Animation.easeInOut(duration: 1).delay(0.5)), removal: AnyTransition.opacity.animation(Animation.easeInOut(duration: 0.1))))
}
I distributed the beta. Some people say they experienced the text wobbling as they typed. Some didn't. Does anyone know what's the reason?
I think it might be related with the animation, but I'm not so sure.