My code is giving me an error. How do I fix it?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor (r: 13, g: 214, b: 151)
view.addSubview(inputsContainerView)
setupInputsContainerView()
}
func setupInputsContainerView() {
//need x, y, width, height constraints
inputsContainerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
inputsContainerView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
inputsContainerView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -24).isActive = true
inputsContainerView.heightAnchor.constraint(equalToConstant: 150).isActive = true
func PreferredStatusBarStyle() ->UIStatusBarStyle {
return.lightContent
}
}
extension UIColor {
convenience init(r: CGFloat, g: CGFloat, b: CGFloat) {
self.init(red: r/255, green: g/255 , blue: b/255, alpha: 1)
}
}
but thing is I'm only getting an error in the extension UIColor {
and the view.backgroundColor = UIColor < is there any fix?
Update
Like I mentioned in the comment, keep the extension of UIColor outside of LoginController scope. The correct code looks like below:
class LoginController: UIViewController {
let inputsContainerView: UIView = {
let view = UIView()
let inputsContainerView = UIView()
inputsContainerView.backgroundColor = UIColor.white
inputsContainerView.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = 5
view.layer .masksToBounds = true
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor (r: 13, g: 214, b: 151)
view.addSubview(inputsContainerView)
setupInputsContainerView()
}
func setupInputsContainerView() {
//need x, y, width, height constraints
inputsContainerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
inputsContainerView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
inputsContainerView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -24).isActive = true
inputsContainerView.heightAnchor.constraint(equalToConstant: 150).isActive = true
}
func PreferredStatusBarStyle() -> UIStatusBarStyle {
return.lightContent
}
}
extension UIColor {
convenience init(r: Int, g: Int, b: Int) {
self.init(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0 , blue: CGFloat(b)/255.0, alpha: 1)
}
}
Isn't that obvious?
You are missing a trailing curly bracket for closing the setupInputsContainerView scope
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor (r: 13, g: 214, b: 151)
view.addSubview(inputsContainerView)
setupInputsContainerView()
}
func setupInputsContainerView() {
//need x, y, width, height constraints
inputsContainerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
inputsContainerView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
inputsContainerView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -24).isActive = true
inputsContainerView.heightAnchor.constraint(equalToConstant: 150).isActive = true
}
func PreferredStatusBarStyle() ->UIStatusBarStyle {
return.lightContent
}
extension UIColor {
convenience init(r: CGFloat, g: CGFloat, b: CGFloat) {
self.init(red: r/255, green: g/255 , blue: b/255, alpha: 1)
}
}
You pass parameters of type Int instead of CGFloat. I would recommend to change custom init method singature (use Int params instead of CGFloat) and convert Int parameters to CGFloat that are passed to framework init method.
extension UIColor {
convenience init(r: Int, g: Int, b: Int) {
self.init(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0 , blue: CGFloat(b)/255.0, alpha: 1)
}
}
Related
I am trying to create a collection view similar to Apple's shortcuts app. I was able to create the cells themselves but I am having a hard time create an individual data cell (if that makes sense). My goal is to have each cell display a title, subtitle, and possible a play button.
Right now, I am having a hard time figuring out where I am going wrong with my constraints or possible my data structure (its crashing on the background and the text isn't showing on the colored cell).
struct customData {
var title: String
var subtitle: String
}
class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
//Mark : All Cards
fileprivate let data = [
customData (title: "iOS", subtitle: "12 Tips"),
customData (title: "iPadOS", subtitle: "11 Tips"),
customData (title: "macOS", subtitle: "10 Tips"),
customData (title: "tvOS", subtitle: "19 Tips"),
customData (title: "watchOS", subtitle: "18 Tips"),
customData (title: "Accessories", subtitle: "17 Tips"),
]
//MARK : Properites
let cellId = "Cell"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
setupCollectionView()
setupNavigationBarController()
}
//MARK : Setup Methods
fileprivate func setupNavigationBarController() {
self.navigationController?.navigationBar.shadowImage = UIImage()
navigationItem.title = "Lists"
if #available(iOS 13.0, *) {
self.navigationController?.navigationBar.prefersLargeTitles = true
}
}
fileprivate func setupCollectionView() {
collectionView?.backgroundColor = .red
collectionView.register(customCell.self, forCellWithReuseIdentifier: cellId)
collectionView.alwaysBounceVertical = true
}
//MARK : CollectionView Delegate Methods
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// 6
return data.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! customCell
cell.data = self.data[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: (view.frame.width / 2) - 20, height: 110)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
}
}
class customCell: UICollectionViewCell {
var data: customData? {
didSet {
guard let data = data else { return }
listName.text = data.title
subName.text = data.subtitle
}
}
fileprivate let listName: UILabel = {
let iv = UILabel ()
iv.textColor = .white
iv.font = UIFont(name: "Times" , size: 12)
return iv
}()
fileprivate let subName: UILabel = {
let iv = UILabel ()
return iv
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupCell()
contentView.addSubview(listName)
listName.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true
listName.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 30).isActive = true
listName.widthAnchor.constraint(equalTo: contentView.widthAnchor, constant: 12).isActive = true
listName.heightAnchor.constraint(equalTo: contentView.heightAnchor, constant: 80).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: Setup Cell
fileprivate func setupCell() {
roundCorner()
gradientBackgroundColor()
setCellShadow()
}
// MARK: Methods
func setCellShadow() {
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 1)
self.layer.shadowOpacity = 0.2
self.layer.shadowRadius = 1.0
self.layer.masksToBounds = false
self.layer.cornerRadius = 3
self.clipsToBounds = false
}
func cellRandomBackgroundColors() -> [UIColor] {
//Colors
let red = [#colorLiteral(red: 0.9654200673, green: 0.1590853035, blue: 0.2688751221, alpha: 1),#colorLiteral(red: 0.7559037805, green: 0.1139892414, blue: 0.1577021778, alpha: 1)]
let orangeRed = [#colorLiteral(red: 0.9338900447, green: 0.4315618277, blue: 0.2564975619, alpha: 1),#colorLiteral(red: 0.8518816233, green: 0.1738803983, blue: 0.01849062555, alpha: 1)]
let orange = [#colorLiteral(red: 0.9953531623, green: 0.54947716, blue: 0.1281470656, alpha: 1),#colorLiteral(red: 0.9409626126, green: 0.7209432721, blue: 0.1315650344, alpha: 1)]
let yellow = [#colorLiteral(red: 0.9409626126, green: 0.7209432721, blue: 0.1315650344, alpha: 1),#colorLiteral(red: 0.8931249976, green: 0.5340107679, blue: 0.08877573162, alpha: 1)]
let green = [#colorLiteral(red: 0.3796315193, green: 0.7958304286, blue: 0.2592983842, alpha: 1),#colorLiteral(red: 0.2060100436, green: 0.6006633639, blue: 0.09944178909, alpha: 1)]
let greenBlue = [#colorLiteral(red: 0.2761503458, green: 0.824685812, blue: 0.7065336704, alpha: 1),#colorLiteral(red: 0, green: 0.6422213912, blue: 0.568986237, alpha: 1)]
let kindaBlue = [#colorLiteral(red: 0.2494148612, green: 0.8105323911, blue: 0.8425348401, alpha: 1),#colorLiteral(red: 0, green: 0.6073564887, blue: 0.7661359906, alpha: 1)]
let skyBlue = [#colorLiteral(red: 0.3045541644, green: 0.6749247313, blue: 0.9517192245, alpha: 1),#colorLiteral(red: 0.008423916064, green: 0.4699558616, blue: 0.882807076, alpha: 1)]
let blue = [#colorLiteral(red: 0.1774400771, green: 0.466574192, blue: 0.8732826114, alpha: 1),#colorLiteral(red: 0.00491155684, green: 0.287129879, blue: 0.7411141396, alpha: 1)]
let bluePurple = [#colorLiteral(red: 0.4613699913, green: 0.3118675947, blue: 0.8906354308, alpha: 1),#colorLiteral(red: 0.3018293083, green: 0.1458326578, blue: 0.7334778905, alpha: 1)]
let purple = [#colorLiteral(red: 0.7080290914, green: 0.3073516488, blue: 0.8653779626, alpha: 1),#colorLiteral(red: 0.5031493902, green: 0.1100070402, blue: 0.6790940762, alpha: 1)]
let pink = [#colorLiteral(red: 0.9495453238, green: 0.4185881019, blue: 0.6859942079, alpha: 1),#colorLiteral(red: 0.8123683333, green: 0.1657164991, blue: 0.5003474355, alpha: 1)]
let colorsTable: [Int: [UIColor]] = [0: red, 1: orangeRed, 2: orange, 3: yellow, 4: green, 5: greenBlue, 6: kindaBlue, 7: skyBlue, 8: blue, 9: bluePurple, 10: bluePurple, 11: purple, 12: pink]
let randomColors = colorsTable.values.randomElement()
return randomColors!
}
func gradientBackgroundColor() {
let colors = cellRandomBackgroundColors()
self.contentView.setGradientBackgroundColor(colorOne: colors[0], colorTow: colors[1])
}
func roundCorner() {
self.contentView.layer.cornerRadius = 12.0
self.contentView.layer.masksToBounds = true
self.contentView.layer.borderWidth = 1.0
self.contentView.layer.borderColor = UIColor.clear.cgColor
}
}
This is what I see:
To fix the warnings that say constraint cannot be satisfied you should set translatesAutoresizingMaskIntoConstraints of listName to false.
override init(frame: CGRect) {
super.init(frame: frame)
setupCell()
contentView.addSubview(listName)
listName.translatesAutoresizingMaskIntoConstraints = false // Add this
listName.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true
listName.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 30).isActive = true
listName.widthAnchor.constraint(equalTo: contentView.widthAnchor, constant: 12).isActive = true
listName.heightAnchor.constraint(equalTo: contentView.heightAnchor, constant: 80).isActive = true
}
anyone please help me, I have a drop down but the I can't select it the second row. I can't figure out why, I try playing with bringSubviewsToFront or back. I try using layer.zPosition it still can't select the second row, but when I choose the first row it work. is it my auto layout setup incorrectly?
here is my ui and code setup
// This is my custom Button
class GDropdownSchedule: UIButton {
let headerLbl = GTitleLabel(name: "Schedule Type".localized(), fontSize: 13, color: #colorLiteral(red: 0.4588235294, green: 0.4941176471, blue: 0.5647058824, alpha: 1))
let bodyLbl = GSubtitleLabel(name: "Additional Note".localized(), fontSize: 16, color: #colorLiteral(red: 0.09803921569, green: 0.09803921569, blue: 0.09803921569, alpha: 1))
let dropDownIV = GIconImageView(img: #imageLiteral(resourceName: "down-chevron"))
var isOpen = false
let dropView = DropDownView()
var delegate: AddScheduleVCDelegate?
var height: NSLayoutConstraint!
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func configure() {
backgroundColor = #colorLiteral(red: 0.9764705882, green: 0.9764705882, blue: 0.9764705882, alpha: 1)
layer.cornerRadius = 5
layer.borderWidth = 1
layer.borderColor = #colorLiteral(red: 0.9411764706, green: 0.9411764706, blue: 0.9450980392, alpha: 1)
dropView.completion = { text in
self.bodyLbl.text = text
self.bodyLbl.font = UIFont(name: "NunitoSans-Regular", size: 12)
self.delegate?.toggleHide(selected: text)
self.dismissDropDown()
}
}
override func didMoveToSuperview() {
addSubview(headerLbl)
headerLbl.anchor(top: topAnchor, trailing: nil, bottom: nil, leading: leadingAnchor, topPadding: 10, rightPadding: 0, bottomPadding: 0, leftPadding: 10, width: 70, height: 18)
addSubview(bodyLbl)
bodyLbl.anchor(top: headerLbl.bottomAnchor, trailing: nil, bottom: bottomAnchor, leading: leadingAnchor, topPadding: 2, rightPadding: 10, bottomPadding: 10, leftPadding: 10, width: 0, height: 0)
addSubview(dropDownIV)
dropDownIV.tintColor = #colorLiteral(red: 0.2549019608, green: 0.3019607843, blue: 0.3568627451, alpha: 1)
dropDownIV.anchor(top: nil, trailing: trailingAnchor, bottom: bottomAnchor, leading: nil, topPadding: 0, rightPadding: 18, bottomPadding: 17, leftPadding: 0, width: 12, height: 10)
addSubview(dropView)
dropView.translatesAutoresizingMaskIntoConstraints = false
dropView.layer.zPosition = 1
height = dropView.heightAnchor.constraint(equalToConstant: 0)
NSLayoutConstraint.activate([
dropView.topAnchor.constraint(equalTo: headerLbl.bottomAnchor),
dropView.leadingAnchor.constraint(equalTo: leadingAnchor),
dropView.trailingAnchor.constraint(equalTo: trailingAnchor)
])
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if isOpen == false {
isOpen = true
NSLayoutConstraint.deactivate([height])
if self.dropView.tableView.contentSize.height > 150 {
height.constant = 150
} else {
height.constant = dropView.tableView.contentSize.height
}
NSLayoutConstraint.activate([height])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.dropView.layoutIfNeeded()
self.dropView.center.y += self.dropView.frame.height / 2
})
} else {
isOpen = false
NSLayoutConstraint.deactivate([height])
height.constant = 0
NSLayoutConstraint.activate([height])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.dropView.center.y -= self.dropView.frame.height / 2
self.dropView.layoutIfNeeded()
})
}
}
func dismissDropDown() {
isOpen = false
NSLayoutConstraint.deactivate([height])
height.constant = 0
NSLayoutConstraint.activate([height])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.dropView.center.y -= self.dropView.frame.height / 2
self.dropView.layoutIfNeeded()
})
}
}
class DropDownView: UIView, UITableViewDelegate, UITableViewDataSource {
let tableView = UITableView()
var options = [String]()
var completion: ((String) -> Void)?
var isHideSchedule = false
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func configure() {
translatesAutoresizingMaskIntoConstraints = false
addSubview(tableView)
tableView.backgroundColor = #colorLiteral(red: 0.9764705882, green: 0.9764705882, blue: 0.9764705882, alpha: 1)
tableView.separatorStyle = .none
tableView.delegate = self
tableView.dataSource = self
tableView.anchor(top: topAnchor, trailing: trailingAnchor, bottom: bottomAnchor, leading: leadingAnchor, topPadding: 0, rightPadding: 0, bottomPadding: 0, leftPadding: 0, width: 0, height: 0)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return options.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = options[indexPath.row]
cell.textLabel?.font = UIFont(name: "NunitoSans-Regular", size: 12)
cell.textLabel?.textColor = #colorLiteral(red: 0.09803921569, green: 0.09803921569, blue: 0.09803921569, alpha: 1)
cell.backgroundColor = #colorLiteral(red: 0.9764705882, green: 0.9764705882, blue: 0.9764705882, alpha: 1)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
completion?(options[indexPath.row])
tableView.deselectRow(at: indexPath, animated: true)
}
}
// This is in my viewController, the chooseScheduleDropDown is my customButton
[chooseScheduleDropDown, entryView, chooseDateView, chooseClass, startTimeView, endTimeView, descriptionView, saveBtn].forEach {
v in
v.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(v)
}
scrollView.insertSubview(entryView, belowSubview: chooseScheduleDropDown)
Because of the hit-test mechanism
You add the dropView on the Button GDropdownSchedule
The layout is
addSubview(dropView)
dropView.translatesAutoresizingMaskIntoConstraints = false
dropView.layer.zPosition = 1
height = dropView.heightAnchor.constraint(equalToConstant: 0)
NSLayoutConstraint.activate([
dropView.topAnchor.constraint(equalTo: headerLbl.bottomAnchor),
dropView.leadingAnchor.constraint(equalTo: leadingAnchor),
dropView.trailingAnchor.constraint(equalTo: trailingAnchor)
])
From the looking and the existing code,
dropView's frame is out of the Button GDropdownSchedule's bounds Partly.
So u can see it , and your clicking does not work.
To override the hit-test mechanism is OK
class GDropdownSchedule: UIButton {
// ...
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// if the button is hidden/disabled/transparent it can't be hit
if self.isHidden || !self.isUserInteractionEnabled || self.alpha < 0.01 { return nil }
let dropViewF = dropView.frame
var index = 9
if bounds.contains(point){
index = 0
}
if dropViewF.contains(point){
index = 1
}
switch index {
case 0:
for subV in subviews.reversed(){
let realPoint = subV.convert(point, from: self)
let hit = subV.hitTest(realPoint, with: event)
if let v = hit{
return v
}
}
return self
case 1:
if dropView.alpha > 0.01{
let realPoint = dropView.convert(point, from: self)
let hit = dropView.hitTest(realPoint, with: event)
if let v = hit{
return v
}
}
default:
()
}
return nil
}
}
From Apple's Doc
hitTest(_:with:)
This method traverses the view hierarchy by calling the
point(inside:with:) method of each subview to determine which subview
should receive a touch event.
If point(inside:with:) returns true,
then the subview’s hierarchy is similarly traversed until the
frontmost view containing the specified point is found. If a view does
not contain the point, its branch of the view hierarchy is ignored.
You rarely need to call this method yourself, but you might override
it to hide touch events from subviews.
Rounded corner is working great on iOS 12 and below, but it's broken on iOS 13. I've created a custom Segment control class.
Code:
class SegmentedControl: UISegmentedControl {
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = self.bounds.size.height / 2.0
layer.borderColor = UIColor(red: 170.0/255.0, green: 170.0/255.0, blue: 170.0/255.0, alpha: 1.0).cgColor
layer.borderWidth = 1.0
layer.masksToBounds = true
clipsToBounds = true
}
}
I've gone through this post - How to change the colors of a segment in a UISegmentedControl in iOS 13?
but I couldn't get any solution.
Screenshot:
I was facing the same issue on iOS 13. Then I dug into its view hierarchy then I found it has multiple subviews. So I made a trick for iOS 13. You have to do following changes for iOS 13 -
ChangeselectedSegmentTintColor to Clear - self.selectedSegmentTintColor = .clear
Add following code snippet inside layoutSubviews -
for i in 0...subviews.count - 1{
if let subview = subviews[i] as? UIImageView{
if i == self.selectedSegmentIndex {
subview.backgroundColor = UIColor(red: 170.0/255.0, green: 170.0/255.0, blue: 170.0/255.0, alpha: 1.0)
}else{
subview.backgroundColor = .clear
}
}
}
I hope it will help you.
Similar to other solution I have Following Sub-Class Segment control
UISegmentedControl
Which gives following result -
class OYSegmentControl: UISegmentedControl {
override func layoutSubviews(){
super.layoutSubviews()
let segmentStringSelected: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.font : UIFont.fontActionLabel(ofSize: 14.0),
NSAttributedString.Key.foregroundColor : UIColor.white
]
let segmentStringHighlited: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.font : UIFont.fontActionLabel(ofSize: 14.0),
NSAttributedString.Key.foregroundColor : #colorLiteral(red: 0.5567105412, green: 0.5807551742, blue: 0.6022000909, alpha: 1)
]
setTitleTextAttributes(segmentStringHighlited, for: .normal)
setTitleTextAttributes(segmentStringSelected, for: .selected)
setTitleTextAttributes(segmentStringHighlited, for: .highlighted)
layer.masksToBounds = true
if #available(iOS 13.0, *) {
selectedSegmentTintColor = #colorLiteral(red: 0, green: 0.861200273, blue: 0.67304039, alpha: 1)
} else {
tintColor = #colorLiteral(red: 0, green: 0.861200273, blue: 0.67304039, alpha: 1)
}
backgroundColor = #colorLiteral(red: 0.9191747308, green: 0.9334954619, blue: 0.9506797194, alpha: 1)
//corner radius
let cornerRadius = bounds.height / 2
let maskedCorners: CACornerMask = [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner]
//background
clipsToBounds = true
layer.cornerRadius = cornerRadius
layer.maskedCorners = maskedCorners
let foregroundIndex = numberOfSegments
if subviews.indices.contains(foregroundIndex),
let foregroundImageView = subviews[foregroundIndex] as? UIImageView {
foregroundImageView.image = UIImage()
foregroundImageView.clipsToBounds = true
foregroundImageView.layer.masksToBounds = true
foregroundImageView.backgroundColor = #colorLiteral(red: 0, green: 0.861200273, blue: 0.67304039, alpha: 1)
foregroundImageView.layer.cornerRadius = bounds.height / 2 + 5
foregroundImageView.layer.maskedCorners = maskedCorners
}
}
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
return false
}
}
Language: Swift 5.1
NOTE: This only works if you have outlet / frame set from Storyboard.
Frame from code will cause issues.
The extra 5 px on cornerRadius,a hack to make it better round rect.
I ended up using - https://github.com/alokc83/MASegmentedControl as my use-case was from Code only view.
Swift 5
If you use a subclass:
override func layoutSubviews() {
super.layoutSubviews()
roundCorners(radius: frame.height / 2)
if #available(iOS 13.0, *) {
selectedSegmentTintColor = .clear
} else {
tintColor = .clear
}
for (index, subview) in subviews.enumerated() {
if ((subviews[index] as? UIImageView) != nil) && index == selectedSegmentIndex {
subview.backgroundColor = .white
subview.roundCorners(radius: subview.frame.height / 2)
} else {
subview.backgroundColor = .clear
}
}
}
Conienience method:
extension UIView {
func roundCorners(radius: CGFloat) {
layer.roundCorners(radius: radius)
self.clipsToBounds = true
}
}
If you use the default segmented control, you just prefix with name of your segmented control:
mySegmentedControl.selectedSegmentTintColor = .clear
for (index, subview) in mySegmentedControl.subviews.enumerated() {
.....
}
Make a custom class for segment
class CustomSegmentedControl: UISegmentedControl {
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = self.bounds.size.height / 2.0
layer.borderColor = use_your_custom_color
layer.borderWidth = 1.0
layer.masksToBounds = true
clipsToBounds = true
for i in 0...subviews.count - 1{
if let subview = subviews[i] as? UIImageView{
if i == self.selectedSegmentIndex {
subview.backgroundColor = use_your_custom_color
}else{
subview.backgroundColor = .white
}
}
}
}}
May be this will easy to use like this
#IBOutlet weak var reminderSegmentControl: CustomSegmentedControl!
this code works for me iOS 13 - Swift 5.1
segment.layer.cornerRadius = 12
segment.layer.borderWidth = 1
segment.layer.borderColor = UIColor.black.cgColor
segment.font(name: "TheSans-Plain", size: 14)
segment.clipsToBounds = true
segment.layer.masksToBounds = true
if #available(iOS 13.0, *) {
segment.selectedSegmentTintColor = .red
}
Recently I updated a codebase from Swift 3.2 to Swift 4.2
All of the sudden, any UI element that is assigned the color UIColor.lightGray produces a black result at runtime:
self.emptyTableView.messageLabel.textColor = UIColor.lightGray
Any idea what's causing this?
Thank you for any insights
Edit:
Here are the extensions for UIColor I found:
extension UIColor {
func colorWithRedValue(_ redValue: CGFloat, greenValue: CGFloat, blueValue: CGFloat, alpha: CGFloat) -> UIColor {
return UIColor(red: redValue/255.0, green: greenValue/255.0, blue: blueValue/255.0, alpha: alpha)
}
func facebookBlue() -> UIColor {
return UIColor(red:0.23, green:0.35, blue:0.60, alpha:1.0)
}
func twitterBlue() -> UIColor {
return UIColor(red:0.25, green:0.60, blue:1.00, alpha:1.0)
}
func goOutGreen() -> UIColor {
return UIColor(red:0.56, green:0.78, blue:0.25, alpha:1.0)
}
func goOutTransparent() -> UIColor {
return UIColor.white.withAlphaComponent(0.2)
}
func goOutClearGreen() -> UIColor {
return UIColor(red:0.00, green:0.91, blue:0.44, alpha:1.0)
}
func transparentBlack() -> UIColor {
return UIColor(red:0.00, green:0.00, blue:0.00, alpha:0.6)
}
func darkShade() -> UIColor {
return UIColor(red:0.13, green:0.13, blue:0.13, alpha:1.0)
}
func greenNormal() -> UIColor {
return UIColor(red:0.00, green:0.83, blue:0.15, alpha:1.0)
}
func goOutRed() -> UIColor {
return UIColor(red:0.77, green:0.05, blue:0.05, alpha:1.0)
}
func goOutBlue() -> UIColor {
return UIColor(red:0.29, green:0.56, blue:0.89, alpha:1.0)
}
func goOutGray() -> UIColor {
return UIColor(red:0.29, green:0.29, blue:0.29, alpha:1.0)
}
func adminBlack() -> UIColor {
return UIColor(red:0.09, green:0.09, blue:0.12, alpha:1.0)
}
func adminGray() -> UIColor {
return UIColor(red:0.902, green:0.902, blue:0.902, alpha:1)
}
func adminBackground() -> UIColor {
return UIColor(red:0.95, green:0.95, blue:0.96, alpha:1.0)
}
func adminPurple() -> UIColor {
return UIColor(red:0.36, green:0.33, blue:0.40, alpha:1.0)
}
func adminDarkPurple() -> UIColor {
return UIColor(red:0.265, green:0.24, blue:0.301, alpha:1)
}
func adminLightPurple() -> UIColor {
return UIColor(red:0.47, green:0.47, blue:0.47, alpha:1.0)
}
func eventDraft() -> UIColor {
return UIColor(red:0.91, green:0.21, blue:0.16, alpha:1.0)
}
func eventPending() -> UIColor {
return UIColor(red:0.08, green:0.54, blue:0.90, alpha:1.0)
}
convenience init(hexString: String) {
var cString: String = hexString.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
if (cString.hasPrefix("#")) {
cString = (cString as NSString).substring(from: 1)
}
if (cString.characters.count != 6) {
self.init(white: 0.5, alpha: 1.0)
} else {
let rString: String = (cString as NSString).substring(to: 2)
let gString = ((cString as NSString).substring(from: 2) as NSString).substring(to: 2)
let bString = ((cString as NSString).substring(from: 4) as NSString).substring(to: 2)
var r: CUnsignedInt = 0, g: CUnsignedInt = 0, b: CUnsignedInt = 0;
Scanner(string: rString).scanHexInt32(&r)
Scanner(string: gString).scanHexInt32(&g)
Scanner(string: bString).scanHexInt32(&b)
self.init(red: CGFloat(r) / CGFloat(255.0), green: CGFloat(g) / CGFloat(255.0), blue: CGFloat(b) / CGFloat(255.0), alpha: CGFloat(1))
}
}
}
and this one:
import Foundation
internal extension UIColor {
/// Hexadecimal representation of the UIColor.
/// For example, UIColor.blackColor() becomes "#000000".
var hex: String {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
self.getRed(&red, green: &green, blue: &blue, alpha: nil)
let r = Int(255.0 * red)
let g = Int(255.0 * green)
let b = Int(255.0 * blue)
let str = String(format: "#%02x%02x%02x", r, g, b)
return str
}
}
I'm trying to add a custom UI Segmented control I created into my root view controller's navbar. Here's my code:
Segmented Control:
#IBDesignable class FeedViewSC: UIControl {
fileprivate var labels = [UILabel]()
var thumbView = UIView()
var items: [String] = ["Tab1", "Tab2"] {
didSet {
setupLabels()
}
}
var selectedIndex : Int = 0 {
didSet{
displayNewSelectedIndex()
}
}
#IBInspectable var font : UIFont! = UIFont.systemFont(ofSize: 13) {
didSet {
setFont()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
func setupView() {
layer.cornerRadius = 2
layer.borderColor = UIColor(red: 2/255, green: 239/255, blue: 23/255, alpha: 1).cgColor
backgroundColor = UIColor(red: 239/255, green: 29/255, blue: 239/255, alpha: 1)
setupLabels()
insertSubview(thumbView, at: 0)
}
func setupLabels() {
for label in labels {
label.removeFromSuperview()
}
labels.removeAll(keepingCapacity: true)
for index in 1...items.count {
let label = UILabel(frame: CGRect.zero)
label.text = items[index-1]
label.textAlignment = .center
label.font = UIFont(name: "timesnr",size: 17)
label.textColor = UIColor(red: 51/255, green: 51/255, blue: 51/255, alpha: 1)
self.addSubview(label)
labels.append(label)
}
}
override func layoutSubviews() {
super.layoutSubviews()
var selectFrame = self.bounds
let newWidth = selectFrame.width / CGFloat(items.count)
selectFrame.size.width = newWidth
thumbView.frame = selectFrame
thumbView.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1)
thumbView.layer.cornerRadius = 5
let labelHeight = self.bounds.height
let labelWidth = self.bounds.width / CGFloat(labels.count)
for index in 0...labels.count - 1 {
let label = labels[index]
let xPosition = CGFloat(index) * labelWidth
label.frame = CGRect(x: xPosition, y: 0, width: labelWidth, height: labelHeight)
}
}
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
let location = touch.location(in: self)
var calculatedIndex: Int?
for (index, item) in labels.enumerated() {
if item.frame.contains(location){
calculatedIndex = index
}
}
if calculatedIndex != nil {
selectedIndex = calculatedIndex!
sendActions(for: .valueChanged)
}
return false
}
func displayNewSelectedIndex (){
if(self.selectedIndex == -1){
self.selectedIndex = self.items.count-1
}
let label = labels[selectedIndex]
}
func setFont(){
for item in labels {
item.font = font
}
}
}
My VC that I would liek to add this Segmented Control to:
class FeedViewController: UIViewController {
let feedViewSC: FeedViewSC = {
let sc = FeedViewSC()
sc.translatesAutoresizingMaskIntoConstraints = false
return sc
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
view.addSubview(feedViewSC)
setupFeedViewSC()
}
func setupFeedViewSC() {
feedViewSC.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor, constant: 5).isActive = true
feedViewSC.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
feedViewSC.heightAnchor.constraint(equalToConstant: 35).isActive = true
feedViewSC.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 60).isActive = true
feedViewSC.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -60).isActive = true
}
override func viewDidAppear(_ animated: Bool) {
let img = UIImage()
self.navigationController?.navigationBar.shadowImage = img
self.navigationController?.navigationBar.setBackgroundImage(img, for: UIBarMetrics.default)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
If you can tell me how I can add my custom UIControl to my View Controller's Navigation bar title.
If the FeedViewController is the initial view controller of the NavigationController you can do it very simply by
let feedControl = FeedViewSC(frame: (self.navigationController?.navigationBar.bounds)!)
feedControl.autoresizingMask = [.flexibleWidth,.flexibleHeight]
self.navigationController?.navigationBar.addSubview(feedControl)
feedControl.addTarget(self, action: #selector(FeedViewController.changingTab), for: .valueChanged)
At least I don't see a reason that this would not work for getting it in the navigation bar.
Also not part of the question but if you are having any trouble seeing your control in IB might I suggest.
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
layer.cornerRadius = 2
layer.borderColor = UIColor(red: 2/255, green: 239/255, blue: 23/255, alpha: 1).cgColor
backgroundColor = UIColor(red: 239/255, green: 29/255, blue: 239/255, alpha: 1)
setupLabels()
insertSubview(thumbView, at: 0)
}
As for the control itself I did not test it but your events and your handling may be slightly different than value changed I am not sure.
You could also make the navigation bar of the controller a special designable class and never add it in code but you would probably have to get a reference in the viewDidLoad to use it. The designable would look like
import UIKit
#IBDesignable class DesignableNavBar: UINavigationBar {
var feedControl : FeedViewSC!
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
func setupView() {
if feedControl == nil{
feedControl = NavControl(frame: self.bounds)
feedControl.autoresizingMask = [.flexibleHeight,.flexibleWidth]
self.addSubview(feedControl)
}
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setupView()
}
}
And then in your controller in say the viewDidLoad you could do this.
if let navController = self.navigationController{
if navController.navigationBar is DesignableNavBar{
let control = (navController.navigationBar as! DesignableNavBar). feedControl
control?.addTarget(self, action: #selector(ViewController.changingTab), for: .valueChanged)
}
}