swift 中的 Tableview 单元格边框未占据全宽
Tableview cell border not occupying full width in swift
我正在尝试在我的 table 视图单元格的所有边上添加边框,我能够添加边框,但遇到右侧边框未占据整个宽度的问题如下面的屏幕截图所示。单元格边框似乎采用设置故事板 UI 的初始宽度,例如,我将 UI 设置为 iPhone SE 但如果我 运行 在 iPhone11出现这个问题。布局未刷新似乎是一些问题。我尝试添加 setNeedsLayout、setNeedsDisplay 和 layoutSubviews,但其中 none 似乎有效。
故事板布局
下面是完整代码
class ViewController: UIViewController {
var dataSource = [String] ()
override func viewDidLoad() {
super.viewDidLoad()
for index in 1...10 {
dataSource.append("Cell value \(index)")
}
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell: MyTableViewCell = tableView.dequeueReusableCell(withIdentifier: "MyTableViewCell", for: indexPath) as? MyTableViewCell else{return UITableViewCell()}
cell.titleLabel.text = dataSource[indexPath.row]
if indexPath.row == 0 {
cell.containerView.addBorder(toEdges: [.left, .top, .right], color: .gray, thickness: 1.0)
} else if indexPath.row == dataSource.count - 1 {
cell.containerView.addBorder(toEdges: .all, color: .gray, thickness: 1.0)
} else {
cell.containerView.addBorder(toEdges: [.left, .top, .right], color: .gray, thickness: 1.0)
}
return cell
}
}
class MyTableViewCell: UITableViewCell {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var containerView: UIView!
}
extension UIView {
func addBorder(toEdges edges: UIRectEdge, color: UIColor, thickness: CGFloat) {
func addBorder(toEdge edges: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer()
border.backgroundColor = color.cgColor
switch edges {
case .top:
border.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness)
case .bottom:
border.frame = CGRect(x: 0, y: frame.height - thickness, width: frame.width, height: thickness)
case .left:
border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.height)
case .right:
border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
default:
break
}
layer.addSublayer(border)
}
if edges.contains(.top) || edges.contains(.all) {
addBorder(toEdge: .top, color: color, thickness: thickness)
}
if edges.contains(.bottom) || edges.contains(.all) {
addBorder(toEdge: .bottom, color: color, thickness: thickness)
}
if edges.contains(.left) || edges.contains(.all) {
addBorder(toEdge: .left, color: color, thickness: thickness)
}
if edges.contains(.right) || edges.contains(.all) {
addBorder(toEdge: .right, color: color, thickness: thickness)
}
}
}
我同意@Asperi 的回答。要么你必须将它子类化并在drawrect中编写这个方法。或者为了快速解决方案,将 frame.width 更改为 UIScreen.main.bounds.width.Check 它将符合您当前的要求和当前代码。
您可能会发现使用 UIView
subclass 来处理“边缘”要容易得多。
将此 class 添加到您的项目中:
class BorderedView: UIView {
var edges: UIRectEdge = []
var color: UIColor = .clear
var thickness: CGFloat = 0
var shapeLayer: CAShapeLayer!
override class var layerClass: AnyClass {
return CAShapeLayer.self
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
shapeLayer = self.layer as? CAShapeLayer
shapeLayer.fillColor = UIColor.clear.cgColor
}
override func layoutSubviews() {
super.layoutSubviews()
let pth = UIBezierPath()
if edges.contains(.top) || edges.contains(.all) {
pth.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
pth.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
}
if edges.contains(.bottom) || edges.contains(.all) {
pth.move(to: CGPoint(x: bounds.minX, y: bounds.maxY))
pth.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
}
if edges.contains(.left) || edges.contains(.all) {
pth.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
pth.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY))
}
if edges.contains(.right) || edges.contains(.all) {
pth.move(to: CGPoint(x: bounds.maxX, y: bounds.minY))
pth.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
}
shapeLayer.lineWidth = thickness
shapeLayer.strokeColor = color.cgColor
shapeLayer.path = pth.cgPath
}
}
然后将您的 containerView
的自定义 Class 分配给 BorderedView
。在您的单元格中正常连接 class:
@IBOutlet weak var containerView: BorderedView!
将您的单元格 class 更改为:
class MyTableViewCell: UITableViewCell {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var containerView: BorderedView!
func configureContainer(toEdges edges: UIRectEdge, color: UIColor, thickness: CGFloat) -> Void {
containerView.edges = edges
containerView.color = color
containerView.thickness = thickness
}
}
然后,在 cellForRowAt
中,而不是调用:
cell.containerView.addBorder(toEdges: [.left, .top, .right], color: .gray, thickness: 1.0)
这样称呼它:
cell.configureContainer(toEdges: [.left, .top, .right], color: .gray, thickness: 1.0)
结果 - tableView 每边插入 8 磅,这样您就可以看到 left/right 条边:
当 tableView / cells 改变大小时(例如在设备旋转时),边缘会自动更新:
我正在尝试在我的 table 视图单元格的所有边上添加边框,我能够添加边框,但遇到右侧边框未占据整个宽度的问题如下面的屏幕截图所示。单元格边框似乎采用设置故事板 UI 的初始宽度,例如,我将 UI 设置为 iPhone SE 但如果我 运行 在 iPhone11出现这个问题。布局未刷新似乎是一些问题。我尝试添加 setNeedsLayout、setNeedsDisplay 和 layoutSubviews,但其中 none 似乎有效。
故事板布局
下面是完整代码
class ViewController: UIViewController {
var dataSource = [String] ()
override func viewDidLoad() {
super.viewDidLoad()
for index in 1...10 {
dataSource.append("Cell value \(index)")
}
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell: MyTableViewCell = tableView.dequeueReusableCell(withIdentifier: "MyTableViewCell", for: indexPath) as? MyTableViewCell else{return UITableViewCell()}
cell.titleLabel.text = dataSource[indexPath.row]
if indexPath.row == 0 {
cell.containerView.addBorder(toEdges: [.left, .top, .right], color: .gray, thickness: 1.0)
} else if indexPath.row == dataSource.count - 1 {
cell.containerView.addBorder(toEdges: .all, color: .gray, thickness: 1.0)
} else {
cell.containerView.addBorder(toEdges: [.left, .top, .right], color: .gray, thickness: 1.0)
}
return cell
}
}
class MyTableViewCell: UITableViewCell {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var containerView: UIView!
}
extension UIView {
func addBorder(toEdges edges: UIRectEdge, color: UIColor, thickness: CGFloat) {
func addBorder(toEdge edges: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer()
border.backgroundColor = color.cgColor
switch edges {
case .top:
border.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness)
case .bottom:
border.frame = CGRect(x: 0, y: frame.height - thickness, width: frame.width, height: thickness)
case .left:
border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.height)
case .right:
border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
default:
break
}
layer.addSublayer(border)
}
if edges.contains(.top) || edges.contains(.all) {
addBorder(toEdge: .top, color: color, thickness: thickness)
}
if edges.contains(.bottom) || edges.contains(.all) {
addBorder(toEdge: .bottom, color: color, thickness: thickness)
}
if edges.contains(.left) || edges.contains(.all) {
addBorder(toEdge: .left, color: color, thickness: thickness)
}
if edges.contains(.right) || edges.contains(.all) {
addBorder(toEdge: .right, color: color, thickness: thickness)
}
}
}
我同意@Asperi 的回答。要么你必须将它子类化并在drawrect中编写这个方法。或者为了快速解决方案,将 frame.width 更改为 UIScreen.main.bounds.width.Check 它将符合您当前的要求和当前代码。
您可能会发现使用 UIView
subclass 来处理“边缘”要容易得多。
将此 class 添加到您的项目中:
class BorderedView: UIView {
var edges: UIRectEdge = []
var color: UIColor = .clear
var thickness: CGFloat = 0
var shapeLayer: CAShapeLayer!
override class var layerClass: AnyClass {
return CAShapeLayer.self
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
shapeLayer = self.layer as? CAShapeLayer
shapeLayer.fillColor = UIColor.clear.cgColor
}
override func layoutSubviews() {
super.layoutSubviews()
let pth = UIBezierPath()
if edges.contains(.top) || edges.contains(.all) {
pth.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
pth.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
}
if edges.contains(.bottom) || edges.contains(.all) {
pth.move(to: CGPoint(x: bounds.minX, y: bounds.maxY))
pth.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
}
if edges.contains(.left) || edges.contains(.all) {
pth.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
pth.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY))
}
if edges.contains(.right) || edges.contains(.all) {
pth.move(to: CGPoint(x: bounds.maxX, y: bounds.minY))
pth.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
}
shapeLayer.lineWidth = thickness
shapeLayer.strokeColor = color.cgColor
shapeLayer.path = pth.cgPath
}
}
然后将您的 containerView
的自定义 Class 分配给 BorderedView
。在您的单元格中正常连接 class:
@IBOutlet weak var containerView: BorderedView!
将您的单元格 class 更改为:
class MyTableViewCell: UITableViewCell {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var containerView: BorderedView!
func configureContainer(toEdges edges: UIRectEdge, color: UIColor, thickness: CGFloat) -> Void {
containerView.edges = edges
containerView.color = color
containerView.thickness = thickness
}
}
然后,在 cellForRowAt
中,而不是调用:
cell.containerView.addBorder(toEdges: [.left, .top, .right], color: .gray, thickness: 1.0)
这样称呼它:
cell.configureContainer(toEdges: [.left, .top, .right], color: .gray, thickness: 1.0)
结果 - tableView 每边插入 8 磅,这样您就可以看到 left/right 条边:
当 tableView / cells 改变大小时(例如在设备旋转时),边缘会自动更新: