Reputation: 16730
How to remove highlight on tap of List with SwiftUI?
List {
}.whatModifierToAddHere?
The selection manager documentation doesnt say anything about it.
Upvotes: 74
Views: 45657
Reputation: 18344
I had to add .listRowBackground(Color(UIColor.secondarySystemGroupedBackground))
to my rows.
This preserves the default background color, rather than making it clear.
Upvotes: 11
Reputation: 886
This needs different approaches depending on the iOS.
For iOS 14:
.onAppear {
UITableViewCell.appearance().selectionStyle = .none
}
For iOS 15:
List {
ListItem()
.listRowBackground(Color.clear)
}
Upvotes: 8
Reputation: 1385
If I understand the question right, you want to select an item by clicking/tapping on it, and deselecting it when you click again.
struct SimpleSelectionView: View {
@State var items = ["First", "Second", "Third"]
@State var selectedItem: String?
var body: some View{
List{
ForEach(items, id: \.self) { item in
Text(item)
.onTapGesture {
if selectedItem == nil || selectedItem != item {
selectedItem = item
} else {
selectedItem = nil
}
}
.listRowBackground(self.selectedItem == item ? Color(red: 0.275, green: 0.420, blue: 0.153, opacity: 0.3) : .white)
}
}
}
}
The downside is that on macOS, you have to click the content (Text) rather than the row as such, but it's a nice lightweight solution, and if you want to do something with the selection, you can do it in didSet.
Upvotes: 0
Reputation: 777
.listRowBackground worked for me
List {
ListItem()
.listRowBackground(Color.clear)
}
Upvotes: 36
Reputation: 51
.onDisappear {
UITableViewCell.appearance().isSelected = false
}
You can set selected to false when the interface disappears or appears.
Upvotes: 0
Reputation: 97
I met the same question, and I think it's a bug.
If I put a Text top the List, the navigation link item will be highlight;
If I remove it or put it below List, the navigation link item won't be highlight.
VStack {
Text("Some word") // Remove it or put it below List
List {
NavigationLink(destination: RedirectionFromList(data: data.first!)) {
Text("test")
}
}
}
If put the Text top the List, I can't find a way to dismiss highlight, very annoyed.
Upvotes: 0
Reputation: 688
A possible solution is to use a ZStack. And adjust insets to .zero. Change Color.red to your color. Your List:
ForEach(items) { item in
ZStack {
NavigationLink(destination: DetailView()) {
EmptyView()
}
ItemRowWrap(item: item)
.background(Color.red)
}
}
.listStyle(InsetListStyle())
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
Your ItemRowView:
struct ItemRowWrap: View {
let item: ListItem
var body: some View {
ItemRow(item: item)
.padding(EdgeInsets(top: 5, leading: 8, bottom: 5, trailing: 8))
}
}
You can adjust paddings as you need.
Upvotes: 0
Reputation: 167
Edit:
The following only works if the SwiftUI view is embedded in a UIKit parent.
For anyone still wondering, you can use .onAppear modifier to achieve this.
.onAppear {
UITableViewCell.appearance().selectionStyle = .none
}
This is similar to viewWillAppear in UIKit. Source: HackingWithSwift
Upvotes: 0
Reputation: 55
Just adding the .buttonStyle(PlainButtonStyle())
modifier to the item in the List, unfortunately didn't work for my case.
Instead I was able to obtain the desired effect -- not seeing any highlighting effect when tapping on a row -- by using the .onAppear()
modifier on the List and the Appearance API for UITableViewCell.
As in the following example:
List {
ForEach(items) { item in
NavigationLink(destination: DetailView(item)) {
RowView(item)
}
}
}
.onAppear {
// this will disable highlighting the cell when is selected
UITableViewCell.appearance().selectionStyle = .none
// you can also remove the row separators
UITableView.appearance().separatorStyle = .none
}
Upvotes: 2
Reputation: 3843
Simple answer to you question. Any cell that you don't want to highlight when tapped just add this modifier
.buttonStyle(PlainButtonStyle())
Therefore the modifier is not for the whole List is for each cell inside
var body: some View{
List{
ForEach(self.getElementsForList()){ element in
ElementCell(element: element)
.buttonStyle(PlainButtonStyle())
}
}
}
Upvotes: 50
Reputation: 2040
I know I'm a bit late but hope this will solve your problem.
You need to use UIKit modifiers to remove this. I recommend you to place them on SceneDelegate.swift
.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
let contentView = TabController()
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
//MARK: Disable selection.
UITableView.appearance().allowsSelection = false
UITableViewCell.appearance().selectionStyle = .none
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
}
EDIT: This will disable all table view selections in your app. If instead, you want to disable the selection on a specific table view, you can disable it inside init()
.
struct SomeViewWithTableView: View {
init() {
//MARK: Disable selection.
UITableView.appearance().allowsSelection = false
UITableViewCell.appearance().selectionStyle = .none
}
var body: some View {
//your view code here
}
}
Upvotes: 16
Reputation: 2917
I guess you should take a look at the short article How to disable the overlay color for images inside Button and NavigationLink from @TwoStraws
Just add the .buttonStyle(PlainButtonStyle())
modifier to your item in the List
and you'll have what you wanted. It also makes the Button
s work again in the List
, which is another problem I encountered.
import Combine
import SwiftUI
struct YourItem: Identifiable {
let id = UUID()
let text: String
}
class YourDataSource: ObservableObject {
let willChange = PassthroughSubject<Void, Never>()
var items = [YourItem]()
init() {
items = [
YourItem(text: "Some text"),
YourItem(text: "Some other text")
]
}
}
struct YourItemView: View {
var item: YourItem
var body: some View {
VStack(alignment: .leading) {
Text(item.text)
HStack {
Button(action: {
print("Like")
}) {
Image(systemName: "heart.fill")
}
Button(action: {
print("Star")
}) {
Image(systemName: "star.fill")
}
}
}
.buttonStyle(PlainButtonStyle())
}
}
struct YourListView: View {
@ObservedObject var dataSource = YourDataSource()
var body: some View {
List(dataSource.items) { item in
YourItemView(item: item)
}
.navigationBarTitle("List example", displayMode: .inline)
.edgesIgnoringSafeArea(.bottom)
}
}
#if DEBUG
struct YourListView_Previews: PreviewProvider {
static var previews: some View {
YourListView()
}
}
#endif
As said in the article, it also works with NavigationLink
s. I hope it helped some of you 🤞🏻
Upvotes: 77