我有一个应用程序,其中UITableView
的分隔符插入设置为自定义值 - 右0
,左0
。这在iOS 7.x
中完美地运行,但是在iOS 8.0
中我看到分隔符插入被设置为右边的15
的默认值。即使在xib文件中它设置为0
,它仍然显示不正确。
如何删除UITableViewCell
分隔符边距?
iOS 8.0在单元格和表视图上引入了layoutMargins属性。
此属性在iOS 7.0上不可用,因此您需要确保在分配之前进行检查!
简单的解决方法是子类化您的单元格并覆盖@ user3570727建议的布局边距属性。但是,您将丢失任何系统行为,如从安全区继承边距,因此我不建议使用以下解决方案:
(的ObjectiveC)
-(UIEdgeInsets)layoutMargins {
return UIEdgeInsetsZero // override any margins inc. safe area
}
(swift 4.2):
override var layoutMargins: UIEdgeInsets { get { return .zero } set { } }
如果您不想覆盖该属性,或者需要有条件地设置它,请继续阅读。
除了layoutMargins
属性之外,Apple还为您的单元格添加了一个属性,以防止它继承您的Table View边距设置。设置此属性后,您的单元格可以独立于表视图配置自己的边距。把它想象成一个覆盖。
此属性称为preservesSuperviewLayoutMargins
,将其设置为NO
将允许单元格的layoutMargin
设置覆盖在TableView上设置的任何layoutMargin
。它既节省了时间(您不必修改表视图的设置),而且更简洁。有关详细说明,请参阅Mike Abdullah的答案。
注意:以下是针对单元级边距设置的简洁实现,如Mike Abdullah的回答所述。设置单元格的preservesSuperviewLayoutMargins=NO
将确保您的表格视图不会覆盖单元格设置。如果您确实希望整个表格视图具有一致的边距,请相应地调整您的代码。
设置您的单元格边距:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// Remove seperator inset
if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
[cell setSeparatorInset:UIEdgeInsetsZero];
}
// Prevent the cell from inheriting the Table View's margin settings
if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
[cell setPreservesSuperviewLayoutMargins:NO];
}
// Explictly set your cell's layout margins
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
斯威夫特4:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// Remove seperator inset
if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
cell.separatorInset = .zero
}
// Prevent the cell from inheriting the Table View's margin settings
if cell.responds(to: #selector(setter: UITableViewCell.preservesSuperviewLayoutMargins)) {
cell.preservesSuperviewLayoutMargins = false
}
// Explictly set your cell's layout margins
if cell.responds(to: #selector(setter: UITableViewCell.layoutMargins)) {
cell.layoutMargins = .zero
}
}
将单元格上的preservesSuperviewLayoutMargins
属性设置为NO应该可以防止表格视图覆盖单元格边距。在某些情况下,它似乎无法正常运作。
如果全部失败,您可以强制执行表格视图边距:
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
// Force your tableview margins (this may be a bad idea)
if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
[self.tableView setSeparatorInset:UIEdgeInsetsZero];
}
if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) {
[self.tableView setLayoutMargins:UIEdgeInsetsZero];
}
}
斯威夫特4:
func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Force your tableview margins (this may be a bad idea)
if tableView.responds(to: #selector(setter: UITableView.separatorInset)) {
tableView.separatorInset = .zero
}
if tableView.responds(to: #selector(setter: UITableView.layoutMargins)) {
tableView.layoutMargins = .zero
}
}
......你去!这应该适用于iOS 7和8。
编辑:Mohamed Saleh引起我注意iOS 9中可能发生的变化。如果要自定义插图或边距,可能需要将Table View的cellLayoutMarginsFollowReadableWidth
设置为NO
。您的里程可能会有所不同,但未记录在案。
此属性仅存在于iOS 9中,因此请务必在设置之前进行检查。
if([myTableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)])
{
myTableView.cellLayoutMarginsFollowReadableWidth = NO;
}
斯威夫特4:
if myTableView.responds(to: #selector(setter: self.cellLayoutMarginsFollowReadableWidth)) {
myTableView.cellLayoutMarginsFollowReadableWidth = false
}
(以上来自iOS 8 UITableView separator inset 0 not working的代码)
编辑:这是一个纯粹的Interface Builder方法:
注意:iOS 11更改并简化了大部分此类行为,即将发布更新...
迅速:
override func viewDidLoad() {
super.viewDidLoad()
if self.tableView.respondsToSelector("setSeparatorInset:") {
self.tableView.separatorInset = UIEdgeInsetsZero
}
if self.tableView.respondsToSelector("setLayoutMargins:") {
self.tableView.layoutMargins = UIEdgeInsetsZero
}
self.tableView.layoutIfNeeded() // <--- this do the magic
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
...
if cell.respondsToSelector("setSeparatorInset:") {
cell.separatorInset = UIEdgeInsetsZero
}
if cell.respondsToSelector("setLayoutMargins:") {
cell.layoutMargins = UIEdgeInsetsZero
}
return cell
}
我这样做是通过这样做的:
tableView.separatorInset = UIEdgeInsetsZero;
tableView.layoutMargins = UIEdgeInsetsZero;
cell.layoutMargins = UIEdgeInsetsZero;
至于cdstamper建议的是什么而不是表视图,在单元格的layoutSubview方法中添加以下行对我有用。
- (void)layoutSubviews
{
[super layoutSubviews];
if ([self respondsToSelector:@selector(setSeparatorInset:)])
[self setSeparatorInset:UIEdgeInsetsZero];
if ([self respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)])
{
[self setPreservesSuperviewLayoutMargins:NO];;
}
if ([self respondsToSelector:@selector(setLayoutMargins:)])
{
[self setLayoutMargins:UIEdgeInsetsZero];
}
}
Swift 3.0示例:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// removing seperator inset
if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
cell.separatorInset = .zero
}
// prevent the cell from inheriting the tableView's margin settings
if cell.responds(to: #selector(setter: UIView.preservesSuperviewLayoutMargins)) {
cell.preservesSuperviewLayoutMargins = false
}
// explicitly setting cell's layout margins
if cell.responds(to: #selector(setter: UITableViewCell.layoutMargins)) {
cell.layoutMargins = .zero
}
}
这是完全控制这些东西的唯一方法(我能找到)
要完全控制每个单元格上的分隔符插入和布局边距。在你的willDisplayCell
的UITableviewDelegate
方法中这样做。
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
cell.layoutMargins = UIEdgeInsetsZero
cell.contentView.layoutMargins = UIEdgeInsetsMake(0, 10, 0, 10)
cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)
}
单元格对象控制分隔符,contentView
控制其他所有内容。如果您的分隔符插入空间以意外颜色显示,则应解决此问题:
cell.backgroundColor = cell.contentView.backgroundColor
Swift for iOS 8中的简单解决方案,带有自定义UITableViewCell
override func awakeFromNib() {
super.awakeFromNib()
self.layoutMargins = UIEdgeInsetsZero
self.separatorInset = UIEdgeInsetsZero
}
通过这种方式,您只需将layoutMargin
和separatorInset
设置为一次,而不是为每个willDisplayCell
设置,因为大多数上述答案都表明了这一点。
如果您使用自定义UITableViewCell
这是正确的地方。否则你应该在tableView:cellForRowAtIndexPath
做。
只是另一个提示:你不需要设置preservesSuperviewLayoutMargins = false
,因为默认值已经是NO
!
对我来说,简单的路线完成了这项工作
cell.layoutMargins = UIEdgeInsetsZero
只需添加以下代码即可解决此程序。
祝你好运!
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
[cell setSeparatorInset:UIEdgeInsetsZero];
}
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
Lukasz在Swift中回答:
// iOS 7:
UITableView.appearance().separatorStyle = .SingleLine
UITableView.appearance().separatorInset = UIEdgeInsetsZero
UITableViewCell.appearance().separatorInset = UIEdgeInsetsZero
// iOS 8:
if UITableView.instancesRespondToSelector("setLayoutMargins:") {
UITableView.appearance().layoutMargins = UIEdgeInsetsZero
UITableViewCell.appearance().layoutMargins = UIEdgeInsetsZero
UITableViewCell.appearance().preservesSuperviewLayoutMargins = false
}
这是在Swift中为我工作的代码:
override func viewDidLoad()
{
super.viewDidLoad()
...
if tableView.respondsToSelector("setSeparatorInset:") {
tableView.separatorInset = UIEdgeInsetsZero
}
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell,forRowAtIndexPath indexPath: NSIndexPath)
{
if cell.respondsToSelector("setSeparatorInset:") {
cell.separatorInset.left = CGFloat(0.0)
}
if tableView.respondsToSelector("setLayoutMargins:") {
tableView.layoutMargins = UIEdgeInsetsZero
}
if cell.respondsToSelector("setLayoutMargins:") {
cell.layoutMargins.left = CGFloat(0.0)
}
}
这对我来说似乎是最干净的(现在),因为所有的cell / tableView边缘/边距调整都是在qazxsw poi方法中完成的,而不会将不必要的代码塞入qazxsw poi。
顺便说一句,我只是设置单元格的左侧separatorInset / layoutMargins,因为在这种情况下我不想搞砸我在单元格中设置的约束。
代码更新为Swift 2.2:
tableView:willDisplayCell:forRowAtIndexPath:
精氨酸!在你的Cell
子类中执行此操作之后:
- (UIEdgeInsets)layoutMargins
{
return UIEdgeInsetsZero;
}
或者设置cell.layoutMargins = UIEdgeInsetsZero;
为我修复它。
大多数答案显示分隔符插入和布局边距是针对单元格和tableviews的各种方法(即tableView:cellForRowAtIndexPath:
, override func viewDidLoad() {
super.viewDidLoad()
if tableView.respondsToSelector(Selector("setSeparatorInset:")) {
tableView.separatorInset = UIEdgeInsetsZero
}
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell,forRowAtIndexPath indexPath: NSIndexPath) {
if cell.respondsToSelector(Selector("setSeparatorInset:")) {
cell.separatorInset.left = CGFloat(0.0)
}
if tableView.respondsToSelector(Selector("setLayoutMargins:")) {
tableView.layoutMargins = UIEdgeInsetsZero
}
if cell.respondsToSelector(Selector("setLayoutMargins:")) {
cell.layoutMargins.left = CGFloat(0.0)
}
}
等)设置的,但我发现只需将它们放在viewDidLayoutSubviews
中效果很好。似乎是最干净的方式。
willDisplayCell
使用下面的代码片段可以避免IOS 8和7中UITableView出现不必要的填充问题。
cellForRowAtIndexPath
每次细胞滚动时使用// kill insets for iOS 8
if ([[UIDevice currentDevice].systemVersion floatValue] >= 8) {
cell.preservesSuperviewLayoutMargins = NO;
[cell setLayoutMargins:UIEdgeInsetsZero];
}
// iOS 7 and later
if ([cell respondsToSelector:@selector(setSeparatorInset:)])
[cell setSeparatorInset:UIEdgeInsetsZero];
而不是更新-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
if ([tableView respondsToSelector:@selector(setSeparatorInset:)])
{
[tableView setSeparatorInset:UIEdgeInsetsZero];
}
if ([tableView respondsToSelector:@selector(setLayoutMargins:)])
{
[tableView setLayoutMargins:UIEdgeInsetsZero];
}
if ([cell respondsToSelector:@selector(setLayoutMargins:)])
{
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
和preservesSuperviewLayoutMargins
,我建议在layoutMargins
中执行一次:
willDisplayCell
在iOS8中:
将其添加到我的UITableViewCell子类:
cellForRowAtIndexPath:
这到“tableView:cellForRowAtIndexPath”或“tableView:willDisplayCell”:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)
cell.preservesSuperviewLayoutMargins = false
cell.layoutMargins = UIEdgeInsetsZero
return cell
}
为我工作。
这是一种全局删除插图的简便方法。
在- (UIEdgeInsets)layoutMargins {
return UIEdgeInsetsZero;
}
:
[editCell setSeparatorInset:UIEdgeInsetsZero];
在UITableViewCell+Extensions.swift
import UIKit
extension UITableViewCell {
override public var layoutMargins: UIEdgeInsets {
get { return UIEdgeInsetsZero }
set { }
}
}
:
AppDelegate
您可能认为a)也只是覆盖扩展中的application:didFinishLaunchingWithOptions:
,或者b)设置 UITableViewCell.appearance().separatorInset = UIEdgeInsetsZero
的外观代理。两者都不会起作用。尽管separatorInset
被指示为属性,但尝试将其作为属性(或方法)覆盖会生成编译器错误。并设置layoutMargins
的separatorInset
的外观代理(或者,就此而言,还设置了UITableViewCell
的layoutMargins
和UITableView
的外观代理)没有任何效果。
layoutMargins
对于要隐藏分隔符的任何特定单元格。
在3楼看到答案后,我试图找出在TableView和TableViewCell之间设置分隔符的关系,并进行了一些测试。以下是我的结论:
separatorInset
这是我的解决方案。这适用于自定义单元子类,只需将它们都添加到子类中。
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// ... Get the cell
cell.separatorInset = UIEdgeInsetsMake(0.f, 20.f, 0.f, [UIScreen mainScreen].bounds.size.width - 20);
// others
return cell;
}
2.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell()
cell.preservesSuperviewLayoutMargins = false
cell.separatorInset = UIEdgeInsetsZero
cell.layoutMargins = UIEdgeInsetsZero
return cell
}
您可以方便地自定义分隔符的位置,而无需要求您的设计师为您绘制一个..........
以比投票最多的答案更紧凑的方式......
- (UIEdgeInsets)layoutMargins {
return UIEdgeInsetsMake(0, 10, 0, 10);
}
}
添加这个片段,Swift中的简单优雅适用于iOS8 :)
self.separatorInset = UIEdgeInsetsMake(0, 10, 0, 10);
让我们花点时间了解问题,然后盲目收费以尝试解决问题。
在调试器中快速浏览将告诉您分隔线是UITableViewCell
的子视图。看起来细胞本身对这些细胞系的布局负有相当大的责任。
iOS 8引入了布局边距的概念。默认情况下,视图的布局边距在所有方面都是8pt
,并且它们是从祖先视图继承的。
我们可以说,在布置其分隔线时,UITableViewCell
选择尊重左侧布局边距,使用它来约束左边插图。
将所有这些组合在一起,以实现真正零的理想插入,我们需要:
0
就这样,这是一个非常简单的任务:
cell.layoutMargins = UIEdgeInsetsZero;
cell.preservesSuperviewLayoutMargins = NO;
注意事项:
preservesSuperviewLayoutMargins
指定用户定义的运行时属性。preservesSuperviewLayoutMargins
保留左边距,而不是设置0
,但这似乎更容易出错,因为您无法控制整个层次结构。0
并留下其他边距可能会稍微清晰一些。UITableView
在普通样式表的底部绘制的“额外”分隔符上有一个0插入,我猜这将需要在表级别指定相同的设置(没有尝试过这个!)这在iOS 8和iOS 9中对我来说非常适合。
对于OBJ-C
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if ([cell respondsToSelector:@selector(setSeparatorInset:)] && [cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)] && [cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setSeparatorInset:UIEdgeInsetsZero];
[cell setPreservesSuperviewLayoutMargins:NO];
[cell setLayoutMargins:UIEdgeInsetsZero];
}
我相信这是我在这里提出的问题:Remove SeparatorInset on iOS 8 UITableView for XCode 6 iPhone Simulator
在iOS 8中,从UIView
继承的所有对象都有一个新属性。因此,在iOS 7.x中设置SeparatorInset
的解决方案将无法删除您在iOS 8中的UITableView上看到的空白区域。
新属性称为“layoutMargins”。
@property(nonatomic) UIEdgeInsets layoutMargins
Description The default spacing to use when laying out content in the view.
Availability iOS (8.0 and later)
Declared In UIView.h
Reference UIView Class Reference
解决方案:-
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
if ([tableView respondsToSelector:@selector(setSeparatorInset:)]) {
[tableView setSeparatorInset:UIEdgeInsetsZero];
}
if ([tableView respondsToSelector:@selector(setLayoutMargins:)]) {
[tableView setLayoutMargins:UIEdgeInsetsZero];
}
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
如果您设置cell.layoutMargins = UIEdgeInsetsZero;
而不检查layoutMargins
是否存在,则应用程序将在iOS 7.x上崩溃。因此,最好的方法是检查layoutMargins
是否在setLayoutMargins:UIEdgeInsetsZero
之前存在。
您可以在应用程序启动时(在加载UI之前)使用UIAppearance一次,将其设置为默认全局设置:
// iOS 7:
[[UITableView appearance] setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
[[UITableView appearance] setSeparatorInset:UIEdgeInsetsZero];
[[UITableViewCell appearance] setSeparatorInset:UIEdgeInsetsZero];
// iOS 8:
if ([UITableView instancesRespondToSelector:@selector(setLayoutMargins:)]) {
[[UITableView appearance] setLayoutMargins:UIEdgeInsetsZero];
[[UITableViewCell appearance] setLayoutMargins:UIEdgeInsetsZero];
[[UITableViewCell appearance] setPreservesSuperviewLayoutMargins:NO];
}
这样,您可以保持UIViewController代码清洁,并且可以随时覆盖它。
iOS在单元格和表视图上引入了layoutMargins属性。
此属性在iOS 7.0中不可用,因此您需要确保在分配之前进行检查!
但是,Apple已将一个名为preservesSuperviewLayoutMargins的属性添加到您的单元格中,这将阻止它继承您的表格视图的边距设置。这样,您的单元格可以独立于表视图配置自己的边距。把它想象成一个覆盖。
此属性称为preservesSuperviewLayoutMargins,将其设置为NO可以允许您使用自己的单元格的layoutMargin设置覆盖Table View的layoutMargin设置。它既节省了时间(您不必修改表视图的设置),而且更简洁。有关详细说明,请参阅Mike Abdullah的答案。
注意:正如Mike Abdullah的回答所表达的那样,这是正确的,不那么混乱的实现;设置单元格的preservesSuperviewLayoutMargins = NO将确保您的表视图不会覆盖单元格设置。
第一步 - 设置细胞边距:
/*
Tells the delegate that the table view is about to draw a cell for a particular row.
*/
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell,
forRowAtIndexPath indexPath: NSIndexPath)
{
// Remove separator inset
if cell.respondsToSelector("setSeparatorInset:") {
cell.separatorInset = UIEdgeInsetsZero
}
// Prevent the cell from inheriting the Table View's margin settings
if cell.respondsToSelector("setPreservesSuperviewLayoutMargins:") {
cell.preservesSuperviewLayoutMargins = false
}
// Explictly set your cell's layout margins
if cell.respondsToSelector("setLayoutMargins:") {
cell.layoutMargins = UIEdgeInsetsZero
}
}
将单元格上的preservesSuperviewLayoutMargins属性设置为NO应该可以防止表视图覆盖单元格边距。在某些情况下,它似乎无法正常运作。
第二步 - 只有在所有操作都失败的情况下,您才可以强制执行Table View边距:
/*
Called to notify the view controller that its view has just laid out its subviews.
*/
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Force your tableview margins (this may be a bad idea)
if self.tableView.respondsToSelector("setSeparatorInset:") {
self.tableView.separatorInset = UIEdgeInsetsZero
}
if self.tableView.respondsToSelector("setLayoutMargins:") {
self.tableView.layoutMargins = UIEdgeInsetsZero
}
}
......你去!这应该适用于iOS 8和iOS 7。
注意:使用iOS 8.1和7.1进行测试,在我的情况下,我只需要使用此解释的第一步。
只有在渲染单元格下面有未填充的单元格时才需要第二步,即。如果表大于表模型中的行数。不执行第二步将导致不同的分隔符偏移。
在Swift中它稍微有点恼人,因为layoutMargins
是一个属性,所以你必须覆盖getter和setter。
override var layoutMargins: UIEdgeInsets {
get { return UIEdgeInsetsZero }
set(newVal) {}
}
这将有效地使layoutMargins
readonly,在我的情况下是好的。
对于iOS 9,您需要添加:
if([myTableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)])
{
myTableView.cellLayoutMarginsFollowReadableWidth = NO;
}
有关详细信息,请参阅question。
Swift 2.0扩展
我只是想分享一个扩展,我从tableview单元格分隔符中删除边距。
extension UITableViewCell {
func removeMargins() {
if self.respondsToSelector("setSeparatorInset:") {
self.separatorInset = UIEdgeInsetsZero
}
if self.respondsToSelector("setPreservesSuperviewLayoutMargins:") {
self.preservesSuperviewLayoutMargins = false
}
if self.respondsToSelector("setLayoutMargins:") {
self.layoutMargins = UIEdgeInsetsZero
}
}
}
用于上下文:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomCell
cell.removeMargins()
return cell