Ответ 1
Здесь мое решение:
self.tableView.separatorColor = self.tableView.backgroundColor
У меня есть сгруппированный UITableview, который создается программно. Кроме того, у меня есть ячейка с xib файлом, заполненная программным обеспечением tableview. Все идет нормально. Но я хочу только удалить внешнюю разделительную линию. Я использовал ниже код, но на этот раз удалил всю разделительную линию.
self.tableView.separatorColor = [UIColor clearColor];
Это не очень хороший вариант для моей ситуации. Вот скриншот, что я хочу сделать;
Здесь мое решение:
self.tableView.separatorColor = self.tableView.backgroundColor
После проверки иерархии представлений кажется, что каждый UITableViewCell имеет только три подпредставления: представление содержимого (UITableViewCellContentView
) и два представления разделителя (_UITableViewCellSeparatorView
). Я не фанат создания динамических классов из NSStrings (как и Apple Apple). Однако, поскольку contentView
UITableViewCell
доступен без использования частных API, решение оказывается довольно простым.
Идея состоит в том, чтобы просто contentView
вашего UITableViewCell
и удалить любые представления, которые не являются contentView
:
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
let subviews = cell.subviews
if subviews.count >= 3 {
for subview in subviews {
if subview != cell.contentView {
subview.removeFromSuperview()
break
}
}
}
}
tableView(:willDisplayCell:forRowAtIndexPath:)
вызывается несколько раз во время рендеринга табличного представления, поэтому вышеизложенное отслеживает состояние путем проверки количества подпредставлений в ячейке. Если у него есть три подпредставления, оба разделителя остаются без изменений. Он также удаляет только один из разделителей, но вы можете удалить оба, удалив break
. Вы также можете указать, удалять ли верхний или нижний разделитель, проверив рамку подпредставления. Если начало оси Y кадра равно 0
, это верхний разделитель. Если это не 0
, это внизу.
Надеюсь это поможет!
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let subviews = cell.subviews
guard subviews.count >= 3 else {
return
}
for subview in subviews where NSStringFromClass(subview.classForCoder) == "_UITableViewCellSeparatorView" {
subview.removeFromSuperview()
}
}
Вы можете удалить разделители даже в сгруппированном UITableView со статической ячейкой:
class Cell: UITableViewCell {
override func layoutSubviews() {
super.layoutSubviews()
for view in subviews where view != contentView {
view.removeFromSuperview()
}
}
Google, даже в 2018 году, обслуживает эту страницу как лучший результат для этого вопроса. Мне не повезло в iOS 11 с любым из предоставленных ответов, поэтому вот что я придумала:
extension UITableViewCell {
func removeSectionSeparators() {
for subview in subviews {
if subview != contentView && subview.frame.width == frame.width {
subview.removeFromSuperview()
}
}
}
}
Вызов .removeSectionSeparators() для любого экземпляра UITableViewCell теперь решит проблему. В моем случае, по крайней мере, разделители разделов являются единственными с той же шириной, что и сама ячейка (так как все остальные с отступом).
Единственный оставшийся вопрос - откуда мы должны это назвать. Вы могли бы подумать, что willDisplayCell будет лучшим выбором, но я обнаружил, что первоначальный вызов происходит до того, как сгенерируются сами представления разделителя, так что никаких кубиков.
Я закончил тем, что поместил это в мой метод cellForRowAtIndexPath непосредственно перед тем, как вернуть возвращенную ячейку:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyReusableIdentifier", for: indexPath)
Timer.scheduledTimer(withTimeInterval: 0.15, repeats: false) { (timer) in
cell.removeSectionSeparators()
}
return cell
}
Это не выглядит так элегантно, но я еще не сталкивался ни с какими проблемами.
РЕДАКТИРОВАТЬ: Похоже, нам это тоже нужно (для повторно используемых ячеек):
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.removeSectionSeparators()
}
Вот до/после на скриншотах с этим кодом:
Это действительно старый вопрос, но все же это одна из первых записей в google при поиске путей удаления верхних и нижних разделителей для каждого раздела.
После некоторого расследования я узнал, что нет никакого способа и просто не намерен от Apple сделать это каким-то образом без глупо сложных хаков иерархии представлений.
К счастью, существует абсолютно простой и простой способ достижения такого вида:
Я говорю просто, но для новичков это может быть затруднено из-за недостаточного понимания того, как работает UITableView
и как реализовать свои собственные ячейки. Позвольте мне объяснить это:
UITableViewCell
@IBOutlet weak var separatorView: UIView!
UITableView
Separator Style
на None
, чтобы скрыть разделитель по умолчаниюUIView
на свою ячейку и измените ее размер так, чтобы она находилась внизу (или в верхней части) ячейки. Используйте Size Inspector
Autoresizing
, чтобы прикрепить его к началу/концу/дну и присвоить ему ширину гибкости (или Autolayout, но в этом случае чуть выше)UITableViewDataSource
cellForRowAtIndexPath:
установите свойство isHidden
вашего пользовательского разделителя на основе, если indexPath.row
- это последняя строка (или первая, если ваш вид наверху) в разделеВот пример кода:
class MyCell: UITableViewCell {
@IBOutlet weak var separatorView: UIView!
}
class ViewController: UITableViewController {
override func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MyCell
cell.separatorView.isHidden = indexPath.row == 2
return cell
}
}
И вот несколько скриншотов:
Да, это какая-то работа, но при кодировании просто нет свободного места. В конце концов, мы программисты, и нам нужно делать кодирование. Всегда лучше потратить 5-10 минут на настройку, чем просто скопировать вставку какого-то взломанного кода, который не может продолжать работать в будущем, когда Apple решит изменить иерархию представлений.
На самом деле было больше работы написать этот ответ, чем реализовать разделитель. Я также искал легкое и быстрое решение, но, в конце концов, просто не было достаточно хорошего, которое, как мне казалось, стоило использовать.
Надеюсь, вы также почувствуете скептицизм, когда увидите, что вы просматриваете элементы подкадров в ящиках, чтобы скрыть или даже удалить просмотры во время выполнения из иерархии представлений, которую Apple предоставляет вам, когда есть простое, универсальное, стабильное и будущее доказательство за углом. 7 маленьких шагов - это все, что вам нужно, и их легко понять.
Вот что я, наконец, придумал:
Я не мог найти лучшего способа, чем это. Но он работает для меня очень. Последняя попытка с Xcode Version 7.3.1 (7D1014). Эта процедура была выполнена через раскадровку.
В основном я добавляю UIView из 0.5 pt Height в UITableViewCell, а затем устанавливаю цвет фона для этого UIView. Установите родительский разделитель UITableView как None.
Вот подробности:
Учитывая, что вы уже установили свой UITableViewCell, пользовательский или по умолчанию. На первом этапе установите разделитель UITableView как None.
Затем добавьте UIView из 1 pt Height и установите Background так, как вам нужно, в моем случае это красный цвет.
Начните устанавливать ограничения. Проблема заключается в том, чтобы установить высоту UIView как 0.5 pt. Это единственная проблемная проблема для этого рабочего процесса.
Разделите способ установки 0.5 pt высоты UIView.
Сначала (1) запишите вид, а затем (2) установите высоту как 0,5. Нажмите Enter.
Наконец, ваш UIView будет похож на следующий.
Мне не удалось установить высоту как 0,5, кроме этого.
Я только что разработал решение, так как ячейка имеет contentView
который представляет собой UIView
, поэтому я думаю, что вы можете просто сосредоточиться на нижней части contentView
.
Вот мой код:
во-первых, вы должны сделать разделитель для очистки
tableView.separatorColor = UIColor.clear
Во-вторых, в функции cellForRowAt
:
let bottomBorder = CALayer()
bottomBorder.frame = CGRect(x: 0.0, y: 43.0, width: cell.contentView.frame.size.width, height: 1.0)
bottomBorder.backgroundColor = UIColor(white: 0.8, alpha: 1.0).cgColor
cell.contentView.layer.addSublayer(bottomBorder)
здесь вы увидите такой интерфейс:
Здесь решение. Это для статических ячеек. Если вы хотите динамический, просто перепишите "count". Надеюсь, что это поможет.
extension NSObject {
var theClassName: String {
return NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
}
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.separatorStyle = .None
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
let count = tableView.numberOfRowsInSection(indexPath.section)
if ( indexPath.row != count - 1 ) {
for view in cell.subviews {
if view.theClassName == "_UITableViewCellSeparatorView" {
view.backgroundColor = UIColors.redColor()
}
}
}
}
Пробовал различные решения на основе обходного пути cell.separatorInset = UIEdgeInsetsMake()
, никто из них не работал должным образом.
Для моего проекта на основе iOS11 UITableViewStyleGrouped
это сделало это:
self.tableView.separatorColor = self.tableView.backgroundColor;
На основании ответа повара, но без таймера:
override func didAddSubview(_ subview: UIView) {
super.didAddSubview(subview)
if NSStringFromClass(subview.classForCoder) != "UITableViewCellContentView" && subview.frame.width == frame.width {
subview.removeFromSuperview()
}
}
Просто добавьте это в подкласс ячейки, и вам больше ничего не нужно. Работает на iOS 12.
У меня была аналогичная проблема, когда у меня был Grouped UITableView с пользовательскими ячейками, все из которых были разработаны с использованием интерфейса Build как .xib файлов. Ячейки имели белый фон, удаляли разделители по умолчанию и добавляли мои собственные. У меня также были собственные заголовки заголовков для каждого раздела. Я установил высоту этих заголовков, чтобы быть 44 (может быть что угодно...). Между моими разделами был вид высоты в 1 пункт, который казался странным. По-видимому, система добавляет некоторые четкие фоновые представления между разделами, даже если мы укажем пользовательскую высоту, например 44, а пользовательский заголовок Header View, который мы возвращаем, имеет белый (или некоторый конкретный цвет фона). Цвет, который мы видим за этим четким представлением, - это цвет фона настольного представления. В моем случае как представления таблиц, так и ячейки должны были быть белого цвета, а установка фона в виде таблицы была белой, чтобы решить проблему (по крайней мере визуально, но то, что я хотел в любом случае). Второе решение состояло бы в том, чтобы стиль Table View был простым, но реализовать метод делегата UITableView для возврата 2 или более разделов, а также создать собственные заголовки, если вам нужно. Но это приведет к тому, что заголовок загорится некоторое время (пока прокручивается) до тех пор, пока заголовок заголовка следующего раздела не приблизится к нему, а затем он тоже начнет подниматься (и это может быть не то, что вы действительно хотите, но там может быть простым способом исправить это, но не уверен, хотя).
Вы можете получить доступ к представлению, используя
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let header = view as! UITableViewHeaderFooterView
header.backgroundView . .....
Попробуйте это, это удалит верхнюю разделительную линию.
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == 0 && indexPath.section == 0) {
for (UIView *view in cell.subviews) {
if ([NSStringFromClass([view class]) containsString:@"CellSeparator"]) {
if (view.frame.origin.y == 0 && CGRectGetHeight(view.frame) < 1.01 ) { //Hide first UITableViewCellSeparatorView
NSLog(@"%s Remove View From Cell[Section:0 Row:0] for top border [%@]:%@",__FUNCTION__,NSStringFromClass([view class]),view);
view.hidden = YES; //Hide
}
}
}
}
}
Для снятия верхней и нижней части разделительной линии для каждой секции. Добавьте это к вашей статической ячейке.
override func layoutSubviews() {
super.layoutSubviews()
//Get the width of tableview
let width = subviews[0].frame.width
for view in subviews where view != contentView {
//for top and bottom separator will be same width with the tableview width
//so we check at here and remove accordingly
if view.frame.width == width {
view.removeFromSuperview()
}
}
}
Результат как изображение ниже
Здесь быстрое решение, которое работает на iOS 8 и 9.
Определите протокол с реализацией по умолчанию:
protocol CellSeparatorRemovable { }
extension CellSeparatorRemovable {
func removeSeparatorLinesFromCell(cell: UITableViewCell, section: Int, row: Int, indexPath: NSIndexPath) {
guard (section, row) == (indexPath.section, indexPath.row) else { return }
for view in cell.subviews where view != cell.contentView {
view.removeFromSuperview()
}
}
}
Затем, где бы вы ни захотели его использовать, совместите с протоколом CellSeparatorRemovable
и вызовите его метод из …willDisplayCell…
:
class SomeVC: UITableViewController, CellSeparatorRemovable {
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
removeSeparatorLinesFromCell(cell, section: 1, row: 1, indexPath: indexPath)
}
}
Это минимальное решение; вам может потребоваться реорганизовать его, если вы имеете дело со многими ячейками, чтобы избежать чрезмерной рекурсии и/или повторного использования ячеек.