I'm trying to modify the color of the Image in the swipe action of a list in SwiftUI.
I have tried a few things:
Setting the image with rendering template and after that applied the foregroundColor modifier
Setting foregroundColor modifier directly to button
Tried to set a custom image
I searched a lot for this, and I didn't found anything, not only didn't found solution, I didn't found a NO, like "You can't do that", so this question is for me and anyone in the future trying to do the same thing and they being able to found a quick solution or a quick "Thats impossible".
A piece of my code, really simple:
List {
if viewModel.showSkeleton {
ForEach(0...4, id: \.self) { _ in
SkeletonTransactionRowView().listRowSeparator(.hidden)
}
} else {
ForEach(viewModel.transactions) { transaction in
TransactionRowView(transaction: transaction)
.swipeActions {
Button { viewModel.delete(transaction: transaction) } label: {
Label("Delete", systemImage: "trash")
}
.tint(.red)
}
}
.listRowSeparator(.hidden)
}
}
.listStyle(PlainListStyle())
NOTE: I know i can make a custom drag gesture and do all this stuff manually, but I want to know if it's possible to do it with the swipe action modifier.
Related
I have an app that allows the user to paste an image from the pasteboard, if it has an image on it. There is also an option for the user to choose a photo from the library. I had two buttons with a matching style, like this:
struct ButtonView: View {
var body: some View {
VStack {
Button {
// Paste from pasteboard
} label: {
HStack {
Image(systemName: "doc.on.clipboard")
Text("Paste Photo")
}
.font(.title)
}
.padding(.bottom, 8)
Button
{
// Open photo library
} label: {
Image(systemName: "photo.on.rectangle.angled")
Text("Pick a Photo")
}
.font(.title)
}
}
}
I'm trying to adopt the new PasteButton in iOS 16 to avoid the user prompt every time, but I can't find any documentation about how to customize it. In the WWDC 2022 session What's new in privacy, there is a section about the button and the speaker says "customize these buttons to fit with your app's interface," but I can't find any documentation about how to customize or what types of customization are allowed.
I have tried adding a .font(.title) modifier, for example, but that does not affect the text size. Ideally I'd like to change the button text to "Paste Photo" and get rid of the background, in addition to changing the font size, so that it matches how the app used to look with the custom button. How can I achieve this?
struct ButtonView: View {
private let supportedTypes: [UTType] =
[UTType("public.image")!]
var body: some View {
VStack {
PasteButton(supportedContentTypes: supportedTypes) { itemProviders in
// Handle paste
}
.padding(.bottom, 8)
Button
{
// Open photo library
} label: {
Image(systemName: "photo.on.rectangle.angled")
Text("Pick a Photo")
}
.font(.title)
}
}
}
From the Apple Document of PasteButton:-
The system provides a button appearance and label appropriate to the current environment. However, you can use view modifiers like buttonBorderShape(_:), labelStyle(_:), and tint(_:) to customize the button in some contexts.
PasteButton(supportedContentTypes: supportedTypes) { itemProviders in
// Handle paste
}
.labelStyle(.iconOnly) // To show icon only or .titleOnly to show title only
.tint(.red) // To change background color
.buttonBorderShape(.capsule) // To give capsule shape
So you cannot change the title of PasteButton but you can customize the button like above.
Note: You cannot clear the button background using .tint(.clear) this will make the background a little grey and I have also checked it doesn't even support custom LabelStyle.
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 ...
I'm working on a new app using SwiftUI and I need some help in the context menu.
I want to know how I can add a custom preview for the context menu in SwiftUI?
& how I can group menu items in multiple groups & add children for any item in the menu?
also how I can make the delete button in red color? or change the colors for them?
another thing, how I can add a menu on the app icon to open a specific View or make an action like this:
In order to add a custom preview, you can use this https://developer.apple.com/documentation/swiftui/view/contextmenu(menuitems:preview:)
The preview should be something that conforms to View.
To split the items in multiple groups, just add a Divider() between the items.
In order to change the color to red for a Delete item, change the button role to .destructive as in the example below.
To add children to one item, use a Menu as below, but I don't think this approach is encouraged.
Here is an example that includes all the above.
.contextMenu {
Menu("This is a menu") {
Button {
doSomething()
} label: {
Text("Do something")
}
}
Button {
doSomethingAgain()
} label: {
Text("Something")
}
Divider()
Button(role: .destructive) {
performDelete()
} label: {
Label("Delete", systemImage: "trash")
}
} preview: {
Text("This is the preview") // you can add anything that conforms to View here
}
I would like to be able to tap a concrete button on my stack of views. To achieve this, first I set on my code an accessibility id:
Button(action: {
withAnimation(.easeOut(duration: 1)) {
self.modalShown.toggle()
}
}) {
FilterButton()
.accessibility(identifier: "modalFilterViewBtn")
}
.buttonStyle(PlainButtonStyle())
}
So, then on my text case I tried to look for that id:
IOSElement elem1 = driver.findElementByAccessibilityId("modalFilterViewBtn");
wait.until(ExpectedConditions.elementToBeClickable(elem1));
elem1.click();
And I obtain as a result: An element could not be located on the page using the given search parameters.(..)
Finally if I use the Appium inspector to know the accessibility id of my desired element, it seems to be another name that is not the same that I had set in code:
Even if I look for the element with that id("Filter"), it also can not be found during my test case.
So, what is the correct way to set this accessibility id using SwiftUI?
Thank you
I assume it should be like
Button(action: {
// action here
}) {
// button label view here
}
.buttonStyle(PlainButtonStyle())
.accessibility(identifier: "modalFilterViewBtn")
Note in iOS 14+ there is .accessibilityIdentifier(_ identifier: String) instead. accessibility(identifier: String) is deprecated.
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")
})