I have a problem managing my UITableView
with IBDesignable ButtonView
and orientation. Basically, the problem happens when I switch to landscape, right border of customView inside UITableViewCell
is overlapping. This is only happening when I change the orientation to landscape. It should be able to show right border properly inside the cell.
Anyone have any ideas on this problem? I included a image on how my layout is organized and the behavior:
In Portrait
, working as expected
In Landscape
, right border overlapping
To add more details, each ButtonView
has boolean defined as User Defined Runtime Attributes
in Storyboard
, which is true for first 2 buttons.
Here is the IBDesignable ButtonView
implementation
import UIKit
@IBDesignable
class ButtonView: UIView {
// MARK: - Properties
@IBInspectable var image: UIImage? {
didSet {
imageView.image = image
}
}
@IBInspectable var title: String? {
didSet {
titleLabel.text = title
}
}
@IBInspectable var hasRightBorder: Bool = false
@IBInspectable var disabledColor: UIColor = Colors.lightGray
@IBInspectable var enabledColor: UIColor = Colors.primary
@IBInspectable var iconSize: CGFloat = 16.0 {
didSet {
imageView.addConstraints(width: iconSize, height: iconSize)
}
}
var imageView = UIImageView()
var titleLabel = UILabel()
var button = UIButton(type: .custom)
var isEnabled = true {
didSet {
if isEnabled {
imageView.tintColor = enabledColor
titleLabel.textColor = enabledColor
} else {
imageView.tintColor = disabledColor
titleLabel.textColor = disabledColor
}
button.isEnabled = isEnabled
}
}
var buttonClosure: (() ->Void)?
// MARK: - Initializers
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
// MARK: - View lifecycle
override func layoutSubviews() {
super.layoutSubviews()
if hasRightBorder {
layer.addBorder(edge: .right, color: Colors.lightGray, thickness: 1.0)
} else {
layer.addBorder(edge: .right, color: UIColor.clear, thickness: 0.0)
}
}
// MARK: - Actions
@objc fileprivate func buttonTapped() {
buttonClosure?()
}
// MARK: - Private API
fileprivate func setupView() {
imageView.tintColor = enabledColor
imageView.translatesAutoresizingMaskIntoConstraints = false
addSubview(imageView)
imageView.topAnchor.constraint(equalTo: topAnchor, constant: 5.0).isActive = true
imageView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
titleLabel.textColor = Colors.primary
titleLabel.font = FontBook.regular.of(size: .extraSmall)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(titleLabel)
titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -5.0).isActive = true
titleLabel.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
addSubview(button)
button.fillSuperview(with: -10.0)
}
}
addBorder implementation
extension CALayer {
func addBorder(edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer();
switch edge {
case UIRectEdge.top:
border.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: thickness)
break
case UIRectEdge.bottom:
border.frame = CGRect(x:0, y:self.frame.height - thickness, width:self.frame.width, height:thickness)
break
case UIRectEdge.left:
border.frame = CGRect(x:0, y:0, width: thickness, height: self.frame.height)
break
case UIRectEdge.right:
border.frame = CGRect(x:self.frame.width - thickness, y: 0, width: thickness, height:self.frame.height)
break
default:
break
}
border.backgroundColor = color.cgColor;
addSublayer(border)
}
}
I resolve the issue using different approach. I came to know by looking at this answer that many things including rotating a device calls layoutSubview
. that's why a border was repeating. I'm posting my solution incase someone facing the same issue.
First, instead of defining a boolean hasRightBorder
, I created a border
of width 1 inside Storyboard
Then, I define a UIView
inside ButtonView
class, set the width and frame heightened add it to the view. Worked like charm :)
@IBDesignable
class ButtonView: UIView {
// MARK: - Properties
@IBInspectable var image: UIImage? {
didSet {
imageView.image = image
}
}
//Add the rightBorder support
@IBInspectable var border: CGFloat = 1.0 {
didSet {
view.addConstraints(width: border, height: frame.size.height)
}
}
// MARK: - Initializers
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
//view to add right border
var view = UIView()
// MARK: - Private API
fileprivate func setupView() {
//Set the color & add it to view
view.backgroundColor = Colors.lightGray
view.translatesAutoresizingMaskIntoConstraints = false
addSubview(view)
view.rightAnchor.constraint(equalTo: rightAnchor, constant: 0).isActive = true
}
}