SwiftUI - Buttons not working with BorderlessButtonStyle - ios

I am attempting to create a list row that contains among other things, multiple individually usable buttons. Previously, I was able to accomplish this by overlaying the buttons on top of the HStacks in the list, but recently this has ceased to function properly.
From searching around, I found this question where the accepted answer suggests using the BorderlessButtonStyle on all buttons to allow them to be individually clicked. However, whenever I apply this property to my button, as in the following code, the button no longer is able to be clicked at all.
Is this an issue with how I am implementing the BorderlessButtonStyle or a bug in SwiftUI?
List{
HStack {
Text("Display Name").bold()
Divider()
if !self.editing_name{
Text(Auth.auth().currentUser?.displayName ?? "Unknown Name")
}
else{
TextField("Name", text: self.$new_name)
}
Spacer()
Button(action: {
print("Edit")
}) {
Image(systemName: "pencil")
.font(.body)
.foregroundColor(Color.blue)
}.buttonStyle(BorderlessButtonStyle())
}
}
I am currently using Xcode 11.5 / iOS 13.5

Related

How can I create a navigation view for iOS using Swift to swipe left and right through a set of images

I would like to create a navigation view for iOS using swift to scroll through a collection of images in a similar fashion to the Photo application on an iPhone. I believe that I need to create a UISwipeGestureRecognizer and add it to the View using addGestureRecognizer. The problem is View does not have a function addGestureRecognizer. UIView does but not View. Also are there any examples of how to do this? Most of the examples that I have seen are quite old and mention ViewControllers.
I am using Swift version 5.7.2 XCode version 14.2 and MACOS Ventura 13.1
Thanks in advance
struct ContentView: View {
let leftSwipe: LeftSwipeRecognizer = LeftSwipeRecognizer()
var body: some View {
VStack {
Image(systemName: "lizard")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
.padding()
.onAppear()
{
leftSwipe.direction = .left
leftSwipe.numberOfTouchesRequired = 1
**self.addGestureRecognizer(leftSwipe)**
}
}
}
the starred line gives the error
Value of type 'ContentView' has no member 'addGestureRecognizer'

What is wrong with the iOS Keyboard toolbar in SwiftUI

I am aware I asked a similar question before, but it seems like I have not understood the core concept of how to present a custom toolbar above a keyboard.
I successfully solved my problem on how to present one with a search field (SwiftUI 2.0: Custom keyboard elements).
Now I want to present a keyboard when a textfield within a detail view of a list is clicked, but again the keyboard toolbar does not show. Does anyone have an idea why?
VStack {
Text("Weight:")
TextField("0", text: $weight)
.keyboardType(.decimalPad)
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
HStack {
Button(action: {
print("Set bodyweight")
},
label: {Text("Bodyweight")
})
Picker("", selection: $weightType) {
ForEach(weightSuffix.allCases, id: \.self) {
Text($0.rawValue)
}
}
.pickerStyle(.segmented)
}
}
}
}
.border(Color.red)
[EDIT]
After AsperiĀ“s comment I Created a small git: https://gist.github.com/joni8a/bc021ef597cb6efa1ab0ca277d602478
Now it gets even weirder, if I attach the toolbar modifier to the list element I get the intended behavior, showing 1 button above the toolbar
If I append the toolbar modifier to the textfield inside the detail view I get the following result:
I think this is a weird behavior. It seems like I have not understood a core concept of SwiftUI. On the other hand if I can't attach the viewmodifer to the textfield itself, it is hard to uncouple the detail view from the list view ...

iOS SwiftUI Form onTapGesture blocks child user interface functionality

the Form view seems to create troubles using the newest SwiftUI (I'm new to it and haven't tested it in older version tbh).
The simple code executes the onTapGesture function correctly when clicking on the button, although it disables all the user feedback (so not visual change in the button on pressing, hold and release) and also does not execute the button action anymore:
var body: some View
{
Form
{
Button(action: {
print("button action")
})
{
Text("Button")
}
.onTapGesture
{
print("tap button")
}
}
.onTapGesture
{
print("tap form")
}
}
When exchanging Form with HStack the visual feedback and console prints work. So it definitely seems to be an issue with the Form view.
When commenting the onTapGesture Form function the button feedback works again. So only the onTapGesture on the Form blocks all child interaction.
Does anyone know what this is - and is there a workaround?

Why does swiftUI give me errors for correct code?

SwiftUI has been giving me errors and refusing to build when I know that the code is correct. For instance the following code was working all of 15 minutes ago. I tried to wrap the List in JumpToBookView in a VStack and add a Button underneath the list, and it started spitting out errors on my Image in BookRow. This code was compiling and showing in the preview before I added the Button and VStack, after I removed them, it still won't let me preview the view. I have tried cleaning the build folder, deleting derived data, and quitting the application, all at the same time, and still nothing. No preview, and the project won't compile. For background, the project is mainly UIKit, but I'm trying to incorporate SwiftUI into it, even though that shouldn't matter because this view is not called anywhere. I am currently running the latest version of Xcode, and have attached my code and a screenshot of the errors. For search, I will also paste the errors here. Missing argument label 'imageName:' in call, Value of type 'Image' has no member 'resizable', and Cannot infer contextual base in reference to member 'fit'
import SwiftUI
struct JumpToBookView: View {
var body: some View {
List {
BookRow(selected: true)
BookRow(selected: true)
BookRow(selected: true)
BookRow(selected: true)
BookRow(selected: true)
BookRow(selected: true)
}
}
func testJump()
{
print("test")
}
}
struct BookRow: View {
var selected: Bool
var body: some View {
ZStack {
Rectangle()
.fill(Color(RaiseColor.red))
HStack{
Text("1.2 What is an Ecosystem?")
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color(.white))
Spacer()
Image(selected ? "pauseButton" : "playButton")
.resizable()
.aspectRatio(1, contentMode: .fit)
.frame(maxWidth: 25)
.foregroundColor(Color(.white))
}
.padding(.all)
}
}
}
struct JumpToBookView_Previews: PreviewProvider {
static var previews: some View {
JumpToBookView()
}
}
EDIT: I just want to add that it was also working with RaiseColor.red before, so there shouldn't be any issues with that custom color.
The issue ended up being that my codebase had previously defined a class named Image, so SwiftUI was having issues figuring out which Image I was trying to reference. Without making other changes to the codebase, this issue was resolved by specifying SwiftUI as the parent of Image, which can be done by the following SwiftUI.Image(selected ? "pauseButton" : "playButton")". This fixes all of the issues I was having, but the best thing to do would be to refactor your codebase in order to not have conflicting names with SwiftUI classes and structs.
When I replace this
Rectangle()
.fill(Color(RaiseColor.red))
with this
Rectangle()
.fill(Color.red)
all compiled well... so look for error in that custom color.
My issue was that i named an intentdefinition enum to Color. I renamed it and it's working fine again.

How to disable SwiftUI's default behavior?

SwiftUI makes it very easy to build declarative UIs. However, sometimes they assume defaults that are not necessarily what we want.
Example:
When adding two buttons inside a list row, SwiftUI automatically makes the whole row touchable, and both button's actions are called on row tap. This is the default behavior, as demonstrated in their WWDC videos.
But I do not want this behavior. I want both buttons to work properly, and the row to not be tappable.
Question:
How can we tell our Guacamole expert (to use the WWDC reference) to stop assuming how I want my list (or any other behavior) to work?
Any help would be appreciated.
If the List's default behavior is not required, you could use a VStack:
struct ContentView: View {
var body: some View {
VStack {
Button(action: {
print("foo")
}) {
Image(systemName: "photo")
}
Button(action: {
print("bar")
}) {
Image(systemName: "photo")
}
}
}
}
However if List is really required, then it could be customized by writing a custom ListStyle.
(Also take a look at this question: How to change ListStyle in List.)
It seems that SomethingStyle protocol is the way Apple wants developers to use to modify native SwiftUI elements/behavior. Another example would be ButtonStyle or TextFieldStyle, etc.
I am under the impression that Apple wants to enforce their style guidelines. Also to add onto #backslash-f answer you could also just use a for each instead of a list, this will give you a similar effect and allow much more customization.
struct doubleList: View {
var body: some View {
VStack{
ForEach(1 ..< 10) {index in
Button(action: {
print("foo")
}) {
Image(systemName: "photo")
}
}
}
}
}
Another option to try would be to wrap an UITableView into an UIViewRepresentable and try to enable buttons that way
It seems there might be another way around this by using tap gestures
Image(systemName: "photo")
.gesture(TapGesture().onEnded() {
print("action2")
})

Resources