Как удалить разделители строк из списка в SwiftUI без использования ForEach?

У меня есть этот код для отображения списка пользовательских строк.

struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading) {
            List(1...10) {_ in
                CustomRow()
            }
        }
    }
}

Однако я хочу удалить строку в каждой строке. Я пытался не использовать List и вместо этого использовать ForEach внутри ScrollView, но это полностью удаляет все стили, включая отступы и поля. Я просто хочу удалить линии и ничего больше.

Пожалуйста, помогите, спасибо.

Возможный дубликат Удалите лишние разделители под списком в SwiftUI

Matteo Pacini 12.06.2019 05:52

Привет, вопрос в ссылке относится к удалить лишние строки для пустых строк, это к удалить все строки для всех строк (пустых или непустых), спасибо.

grey 12.06.2019 07:55

Да, немного другие вопросы, но, к сожалению, тот же вывод (пока): не представляется возможным. См. также ответы на этот вопрос: stackoverflow.com/questions/56517904/…

Marius Waldal 12.06.2019 09:46
LazyVStack внутри ScrollView глючит и не имеет всех функций List
visc 27.09.2020 05:27
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
117
4
75 011
22
Перейти к ответу Данный вопрос помечен как решенный

Ответы 22

iOS 15+:

Просто добавьте .listRowSeparator(.hidden) в качестве модификатора к представлению, содержащемуся в List. https://developer.apple.com/documentation/swiftui/texteditor/listrowseparator(_:edges:)

List {
    ForEach(garage.cars) { car in
        Text(car.model)
            .listRowSeparator(.hidden)
    }
}

Только iOS 13:

Добавление UITableView.appearance().separatorColor = .clear в любом месте вашего кода до появления List должно работать. Хотя это решение удаляет разделители, обратите внимание, что все экземпляры List будут привязаны к этому стилю, поскольку в настоящее время нет официального способа удалить только разделители определенных экземпляров. Вы можете запустить этот код в onAppear и отменить его в onDisappear, чтобы сохранить разные стили.

Также обратите внимание, что этот код предполагает, что Apple использует UITableView для возврата List, что неверно в iOS 14 SDK. Надеюсь, в будущем они добавят официальный API. Кредит на https://twitter.com/singy/status/1169269782400647168.

Хотя этот код может ответить на вопрос, было бы лучше объяснить, как он решает проблему, не вводя других, и зачем его использовать. Ответы, содержащие только код, в долгосрочной перспективе бесполезны.

Al Foиce ѫ 12.09.2019 22:14

Наконец, спасибо! Все просто и работает (по крайней мере, на данный момент), Ура!

grey 27.09.2019 09:33

Спасибо! Просто обратите внимание, что вместо этого я бы изменил стиль разделителя, так как его легче восстановить в исходное состояние .onAppear { UITableView.appearance().separatorStyle = .none } .onDisappear { UITableView.appearance().separatorStyle = .singleLine }

Artemiy Sobolev 12.10.2019 22:30

Использование этого API по какой-то причине приводит к сбою приложения, нужно найти другой обходной путь.

Karen Karapetyan 25.11.2019 21:08

Apple, скорее всего, откажется от использования List под капотом. Когда это произойдет, эта реализация сломается. Вместо этого вы можете использовать UITableView в подвидах вашего списка.

Pigpocket 07.01.2020 00:47

Одна из проблем с использованием этого в .onAppear и .onDisappear заключается в том, что последний не вызывается, когда вы представляете модальный лист, поэтому все списки и формы внутри модального окна по-прежнему обрабатываются .onAppear.

iMaddin 10.04.2020 08:33

Может быть, использовать сетку с одним столбцом в iOS 14?

Ever Uribe 28.06.2020 02:31

@EverUribe можно было даже использовать простой VStack, чтобы избежать разделителей, но вы не получаете преимуществ от использования List. Не уверен, насколько это важно для 14, особенно с введением LazyVStack, который откладывает инициализацию будущих строк до тех пор, пока они не понадобятся для отображения пользователю. Кроме того, улучшения анимации могут сделать обновления строк более естественными. Использование LazyVGrid, конечно, возможно и в 14 с дополнительными преимуществами.

Natanel 28.06.2020 20:17
Ответ принят как подходящий

iOS 15:

В этом году Apple представила новый модификатор .listRowSeparator, который можно использовать для стилизации разделителей. вы можете передать .hidden, чтобы скрыть это:

List {
    ForEach(items, id:\.self) { 
        Text("Row \($0)")
            .listRowSeparator(.hidden)
    }
}

iOS 14:

вместо этого вы можете рассмотреть возможность использования LazyVStack внутри ScrollView (поскольку iOS НЕТ больше не поддерживает UIAppearance для списков SwiftUI).

LazyVStack Preview


iOS 13:

⚠️ This method is deprecated and it's not working from iOS 14

За SwiftUI стоит UITableView для iOS 13. Поэтому, чтобы удалить

Дополнительные разделители (под списком):

вам нужен List и удалить

Все разделители (включая актуальные):

вам нужно tableFooterView быть separatorStyle

Пример использования

init() {
    if #available(iOS 14.0, *) { 
        // iOS 14 doesn't have extra separators below the list by default.
    } else {
        // To remove only extra separators below the list:
        UITableView.appearance().tableFooterView = UIView()
    }

    // To remove all separators including the actual ones:
    UITableView.appearance().separatorStyle = .none
}

var body: some View {
    List {
        Text("Item 1")
        Text("Item 2")
        Text("Item 3")
    }
}

Обратите внимание, что в статическом списке по умолчанию не отображаются дополнительные разделители под списком.

спасибо, это работает, и вы также можете добавить это в .onAppear

Sky 06.12.2019 06:43
UITableView.appearance().separatorStyle = .none странным образом у меня не работает, тоже не .introspectTableView { tableView in tableView.separatorStyle = .none }SwiftUI-Introspect...)
User 31.07.2020 15:56

Какая версия iOS?

Mojtaba Hosseini 31.07.2020 17:50

Разработчики iOS 14, использующие формы, которые хотят, чтобы в одном разделе не было разделителей между определенными элементами, но сохранялись разделители в других областях одного и того же представления: просто используйте LazyVStack вокруг представлений, в которых вы хотите, чтобы не было разделительных линий.

Beginner 30.08.2020 00:28

Просто отметим, что очень важно убедиться, что .listRowSeparator(.hidden) является внутриList.

George 13.06.2021 01:24

Спасибо. Это сработало.

Minhaz Panara 14.12.2021 14:46

Не могли бы вы обновить описание в разделе «iOS 14» здесь? > вместо этого вы можете рассмотреть возможность использования LazyVStack внутри ScrollView (поскольку iOS больше НЕ поддерживает внешний вид для списков SwiftUI). // Раздел «iOS 15» выше, кажется, противоречит этому. Судя по всему, iOS продолжит поддерживать внешний вид списков SwiftUI?

FateNuller 26.02.2022 00:56

Проверьте SwiftUI-Интроспект. Он предоставляет базовые представления UIKit/AppKit.

Только сборки iOS 13:

В этом случае вы можете напрямую манипулировать UITableView (без необходимости изменять все представления таблицы через прокси-сервер внешнего вида):

    import Introspect
    :
    :
    List {
        ...
    }.introspectTableView { tableView in
         tableView.separatorStyle = .none
    }

Да, это больше не работает в сборках iOS 14. В зависимости от вашего варианта использования вы можете попробовать SidebarListStyle скрыть разделители: .listStyle(SidebarListStyle())

markiv 21.09.2020 10:46

Делать что-то вроде:

UITableView.appearance().separatorColor = .clear

работает, но во многих случаях это не то, что я бы рекомендовал. Это глобальные изменения, т.е. они затронут экземпляры все UITableView. Это проблема, если у вас есть несколько UITableView, которым нужны разные стили. Или, если вы разрабатываете фреймворк, клиенты, использующие ваш фреймворк, также наследуют эти изменения!

Более безопасное решение состоит в том, чтобы нацеливаться только на UITableView, которые находятся внутри указанного контейнера. К счастью, appearance API дает нам возможность быть конкретным:

UITableView.appearance(whenContainedInInstancesOf: [UIHostingController<YourSwiftUiViewHere>.self]).separatorColor = .clear

Во-первых, ваш код даже не скомпилируется, так как правильное имя appearance(whenContainedInInstancesOf:). В целом, однако, это звучит как лучший подход, действительно. К сожалению, это не сработало для меня. Я заменил глобальную перезапись внешнего вида (сработало, как и ожидалось) на целевую, и это не дало никакого эффекта...

NeverwinterMoon 05.04.2020 09:22

@NeverwinterMoon, спасибо, что сообщили мне об опечатке! Я обновлю его сейчас. Я написал это прямо в переполнении стека, так что это плохо. У меня он работал для цвета разделителя, цвета фона ячейки и других свойств. не уверен, почему это не работает правильно для вас. Я могу только проверить иерархию представлений и проверить, что для вас перекрывает неправильный цвет. проверьте это для инспектора иерархии представлений developer.apple.com/library/archive/documentation/…

tomcully 06.04.2020 13:00

Использовать ScrollView?

Некоторое состояние, которое представляет ваш список

@State var menuItems: [String] = ["One", "Two", "Three"]

Петля SwiftUIForEach внутри ScrollView

ScrollView {
    ForEach(self.menuItems, id: \.self) { item in
        Text(item)
    }
}

Это правильное предложение, но ответ @Mojtaba Hosseini более полный, когда он также предлагает LazyVStack внутри ScrollView. Можно было бы пояснить здесь, в чем заключаются компромиссы при замене List на ScrollView — один из них исправлен с помощью LazyVStack (iOS 14+), так что хотя бы не все ячейки инициализируются сразу, но вы все равно не получаете полное поведение повторного использования, которое List/UITableView даст вам, ни какой-либо другой стиль, когда первоначальный вопрос касался только сокрытия разделителя и явного упоминания ScrollView была предпринята попытка.

Gobe 27.09.2020 02:04

Только сборки iOS 13:

Хотя эти ответы технически правильны, по моему опыту, они повлияют на List или Form глобально (во всем приложении).

Хакерский способ, который я нашел для решения этой проблемы, по крайней мере, в моем приложении, состоит в том, чтобы добавить следующий код в «основное» представление содержимого приложения:

.onAppear(perform: {
    UITableView.appearance().separatorStyle = .none
})

Затем в любом другом представлении, которое вы хотите добавить в разделительные линии, добавьте это в конец представления List или Form.

.onAppear(perform: {
    UITableView.appearance().separatorStyle = .singleLine
})

Это, кажется, добавляет разделитель одной строки к любому листу просмотра, который находится над основным видом контента. Опять же, все это не соответствует моему недавнему опыту работы со SwiftUI.

По моему опыту, мне нужно было только добавить метод .onAppear(... = .singleLine) к одному из моих «подробных» представлений, и разделительная линия появлялась на всех последующих представленных представлениях.

Редактировать: Еще одно замечание, поскольку этот ответ продолжает привлекать внимание. Это решение, которое я опубликовал, не решает все случаи, оно, конечно, не решило это для меня, опять же, в некоторых случаях. В итоге я использовал Самоанализ для SwiftUI для решения этой проблемы во всем приложении.

Я надеюсь, что это прояснит некоторую путаницу и разочарование, когда люди наткнутся на этот пост.

iOS 14

В настоящее время нет решения скрыть разделители в бета-версии iOS 14.

Если вам не нужен редактируемый List, вы должны использовать LazyVStack внутри ScrollView.

Но если вы хотите остаться на List. Я нашел решение на форуме Apple от samwarner. https://developer.apple.com/forums/thread/651028

Это временное решение. В некоторых случаях вам может понадобиться настроить вставки. Вот его реализация:

struct HideRowSeparatorModifier: ViewModifier {
    static let defaultListRowHeight: CGFloat = 44
    var insets: EdgeInsets
    var background: Color
    
    init(insets: EdgeInsets, background: Color) {
        self.insets = insets
        var alpha: CGFloat = 0
        UIColor(background).getWhite(nil, alpha: &alpha)
        assert(alpha == 1, "Setting background to a non-opaque color will result in separators remaining visible.")
        self.background = background
    }
    
    func body(content: Content) -> some View {
        content
            .padding(insets)
            .frame(
                minWidth: 0, maxWidth: .infinity,
                minHeight: Self.defaultListRowHeight,
                alignment: .leading
            )
            .listRowInsets(EdgeInsets())
            .background(background)
    }
}

extension EdgeInsets {
    static let defaultListRowInsets = Self(top: 0, leading: 16, bottom: 0, trailing: 16)
}

extension View {
    func hideRowSeparator(insets: EdgeInsets = .defaultListRowInsets, background: Color = .white) -> some View {
        modifier(HideRowSeparatorModifier(insets: insets, background: background))
    }
}

Наконец, вот реализация в списке. Вы должны добавить .hideRowSeparator() в ячейку списка.

struct CustomRow: View {
    let text: String
    
    var body: some View {
        HStack {
            Text(self.text)
            Image(systemName: "star")
        }
    }
}

struct ContentView : View {
    @State private var fruits = ["Apple", "Orange", "Pear", "Lemon"]
    
    var body: some View {
        VStack(alignment: .leading) {
            List {
                ForEach(self.fruits, id: \.self) { str in
                    CustomRow(text: str)
                        .hideRowSeparator()
                }
            }
        }
        .padding(.top)
    }
}

используя этот обходной путь, первая строка показывает разделитель сверху

JAHelia 01.09.2020 10:30

...отличный модификатор, большое спасибо. Если вы делаете пользовательскую ячейку смахивания, вы можете установить .listRowBackground(background) в дополнение к существующему .background(background) в теле HideRowSeparatorModifiers...

iKK 06.05.2021 15:32

@JAHelia да, у меня такая же проблема

LiangWang 25.08.2021 13:37

Я начал проект, чтобы решить эту проблему в iOS14, так как обходные пути iOS 13 больше не работают. Он позволяет установить стиль разделителя, цвет разделителя и вставку разделителя.

Скрыть разделители в списке

List { <content> }
    .listSeparatorStyle(.none)

Показать одну разделительную линию с настраиваемым цветом и вставками

List { <content> }
    .listSeparatorStyle(.singleLine, color: .red, inset: EdgeInsets(top: 0, leading: 50, bottom: 0, trailing: 20)

https://github.com/SchmidtyApps/SwiftUIListSeparator

если вы примените фон, все разделители снова появятся

Leonif 28.04.2021 20:57

Все ответы говорят вам использовать ScrollView (что я тоже рекомендую)

Но если вы хотите использовать список и хотите удалить разделительные строки..

Установите SwiftPM: https://github.com/siteline/SwiftUI-Интроспект

ОБРАЗЕЦ:

List {
    Text("Item 1")
    Text("Item 2")
}
.introspectTableView { tableView in
    tableView.separatorStyle = .none
}

Это мое расширение ListRowExtensions для разделителя строк списка Спрятать и обычай для этого.

import SwiftUI

// MARK: List row extensions

extension View {
    
    func hideListRowSeparator() -> some View {
        return customListRowSeparator(insets: .init(), insetsColor: .clear)
    }
    
    func customListRowSeparator(
        insets: EdgeInsets,
        insetsColor: Color) -> some View {
        modifier(HideRowSeparatorModifier(insets: insets,
                                          background: insetsColor
        )) .onAppear {
            UITableView.appearance().separatorStyle = .none
            UITableView.appearance().separatorColor = .clear
        }
    }
}

// MARK: ViewModifier

private struct HideRowSeparatorModifier: ViewModifier {
        
    var insets: EdgeInsets
    var background: Color
    
    func body(content: Content) -> some View {
        content
            .padding(insets)
            .frame(
                minWidth: 0,
                maxWidth: .infinity,
                maxHeight: .infinity,
                alignment: .leading
            )
            .listRowInsets(EdgeInsets())
            .background(background)
    }
}

Использовать :

// Without list row separator
List {
    ForEach(self.viewModel.data, id: \.id) { item in
        Text("Text")
    }
    .hideRowSeparatorItemList()
}

// With list row separator with color and size
List {
    ForEach(self.viewModel.data, id: \.id) { item in
        Text("Text")
    }
    .customListRowSeparator(insets: EdgeInsets(top: 0,
                                               leading: 0,
                                               bottom: 5,
                                               trailing: 0),
                            insetsColor: Color.red)
}

Я не уверен, нужны ли вам все функции «UITableView» в SwiftUI, но если вы просто хотите просто отобразить список представлений в iOS 13 или более поздней версии, не могли бы вы просто сделать:

ScrollView {
    VStack(alignment: .leading) {
        ForEach(1...10) { _ in
            CustomRow()
        }
    }
}

А затем добавьте .padding() для любых полей, которые вы хотите?

Удалить отступы и разделитель

iOS 14.2, Xcode 12.2

ScrollView {
    LazyVStack {
        ForEach(viewModel.portfolios) { portfolio in
            PortfolioRow(item: portfolio)
        }
    }
}

Это дает вам полный контроль над списком. Текущая реализация List не обеспечивает полного контроля и содержит некоторые проблемы.

Хороший! Работает как шарм.

LineDrop 17.03.2021 19:14

Это работает, но не позволяет вам иметь плавающие заголовки Section, как если бы вы использовали List или UITableView.

Eugene 29.04.2021 21:14

Для iOS 14 у вас есть это:

.listStyle(SidebarListStyle()) # IOS 14

Спасибо, что указали на это. Он удалил разделитель и стрелку раскрытия, но теперь добавляет серый фон, который я не могу удалить. Есть ли способ изменить фон? Зачем Apple все так усложняет?...

Emil 23.01.2021 23:32

@Эмиль, я не знаю :)

YannSteph 18.08.2021 09:24

Вы можете удалить разделители, установив для listStyle значение InsetListStyle(), например:

.listStyle(InsetListStyle())

Добавьте это в конец вашего кода

Кажется, это единственное, что работает для меня.

List() {

}
.listStyle(SidebarListStyle())

Отличный ответ для тех, кто делает боковое меню из List

Yunwei.W 25.04.2021 09:11

Простое решение, которое будет работать как на iOS 13, так и на 14.

extension List {
func removeSeparator() -> some View {
    if #available(iOS 14.0, *) {
        return self.listStyle(SidebarListStyle()).erasedToAnyView()
    } else {
        return self.onAppear {
            UITableView.appearance().separatorStyle = .none
        }.erasedToAnyView()
    }
}

Можно просто использовать негативные вставки и сплошной цвет, чтобы замаскировать разделитель.

У меня та же проблема. Но я знаю самодельное решение для этого. Итак, если вы установите параметры строки списка, например:

.listRowInsets(EdgeInsets(top: -5, leading: 0, bottom: 0, trailing: 0))

и заполнение тела представления строки, например

.padding(EdgeInsets(top: Statics.adjustValue(v: 10), leading: Statics.adjustValue(v: 10), bottom: Statics.adjustValue(v: 10), trailing: Statics.adjustValue(v: 10)))

тогда разделители будут скрыты.

ДЛЯ ВСЕХ ВЕРСИЙ iOS

Что такое Statics.adjustValue?

Mumtaz Hussain 04.09.2021 16:38

Метод Statics.adjustValue() является регулятором размера по плотности экрана.

Ulvi Valiyev 07.09.2021 09:20

Для iOS13,iOS14 удалите разделитель в верхней части первой ячейки.

Добавить модификатор представления

extension View {
    func hideRowSeparator(insets: EdgeInsets = .init(top: 0, leading: 0, bottom: 0, trailing: 0),
                          background: Color = .white) -> some View {
        modifier(HideRowSeparatorModifier(insets: insets, background: background))
    }
}

struct HideRowSeparatorModifier: ViewModifier {

  static let defaultListRowHeight: CGFloat = 44

  var insets: EdgeInsets
  var background: Color

  init(insets: EdgeInsets, background: Color) {
    self.insets = insets

    var alpha: CGFloat = 0
    if #available(iOS 14.0, *) {
        UIColor(background).getWhite(nil, alpha: &alpha)
        assert(alpha == 1, "Setting background to a non-opaque color will result in separators remaining visible.")
    }
    self.background = background
  }

  func body(content: Content) -> some View {
    content
        .padding(insets)
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: Self.defaultListRowHeight)
        .listRowInsets(EdgeInsets())
        .overlay(
            VStack {
                HStack {}
                .frame(maxWidth: .infinity)
                .frame(height: 1)
                .background(background)
                Spacer()
                HStack {}
                .frame(maxWidth: .infinity)
                .frame(height: 1)
                .background(background)
            }
            .padding(.top, -1)
        )
  }
}

Применение

struct ContentView: View {
    var body: some View {
        List {
            ForEach(0 ..< 30) { item in
                HStack(alignment: .center, spacing: 30) {
                    Text("Hello, world!:\(item)").padding()
                }
                .hideRowSeparator(background: .white)
            }
        }
        .listStyle(PlainListStyle())
    }
}

Для iOS 14:

Поскольку .listRowSeparator(.hidden) доступен только для iOS 15, вы можете скрыть разделитель в более ранних версиях, явно установив значение edgeinsets равным 0.

Просмотр содержимого:

List {
    ForEach(viewModel.items, id: \.id) { item in
        YourListItem(item)
        .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
    }
}

Сопровождайте вышеуказанное изменение, сделав фон элемента строки белым (или цветом корневой страницы).

Элемент строки:

var body: some View {
    VStack {
        ..... your content
    }
    .background(Colors.white)
}

VStack — это просто пример. Это может быть любой компонент.

Это мое решение, которое содержит все соображения:

    
    let style: UITableViewCell.SeparatorStyle
    
    public func body(content: Content) -> some View {
        content
            .introspectTableView { tableView in
                     tableView.separatorStyle = .none
            }
    }
}
 
public extension View {
    
    func listSeparator(style: UITableViewCell.SeparatorStyle) -> some View {
        ModifiedContent(content: self, modifier: ListSeparatorStyle(style: style))
    }
}

Реализовано:

List {
   // code...
}
.listSeparator(style: .none)

Можете ли вы завершить начало кода?

herve 28.01.2022 18:21

Чтобы удалить разделитель строк в SwiftUI, вы можете настроить представление List, присоединив модификатор onAppear и вызвать API внешнего вида UITableView, чтобы отключить разделитель строк:

.onAppear {
 UITableView.appearance().separatorStyle = .none
}

С помощью этого кода все разделители строк списка должны быть удалены.

Другие вопросы по теме