I have several UI Segment Controls across an iOS app written in swift.
Whilst simulating on an iOS device, on the initial load they use the correct custom font set in the code but certain instances where I go to other views and come back, the fonts in the segment control tabs seem to revert to system fonts automatically.
What is causing this issue?
I am creating all of my segmented controls using this function in each view controller. This is where the custom fonts are set.
override func viewDidLoad() {
super.viewDidLoad()
isHirer = AppSettings.boolValue(.isHirer)
setupUI()
setupSegmentControl()
downloadData()
configureLocationManager()
}
func setupSegmentControl() {
var items = [String]()
items = AppSettings.boolValue(.isHirer) ? ["Posts", "Manage"] : ["Search", "Manage"]
let segmentedControl = UISegmentedControl(items: items)
segmentedControl.selectedSegmentIndex = 0
UISegmentedControl.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor:UIColor.init(displayP3Red: 0/255, green: 0/255, blue: 0/255, alpha: 1), NSAttributedString.Key.font : UIFont.init(name: "Cabin-SemiBold", size: 16)!], for: .selected)
UISegmentedControl.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor:UIColor.init(displayP3Red: 138/255, green: 145/255, blue: 172/255, alpha: 0.7), NSAttributedString.Key.font : UIFont.init(name: "Cabin-SemiBold", size: 16)!], for: .normal)
segmentedControl.frame = CGRect.init(x: 0, y: 42, width: tableView.frame.width/2-20, height: 48)
if AppSettings.boolValue(.isHirer) {
segmentedControl.setContentOffset(CGSize(width: 0, height: -5), forSegmentAt: 0)
segmentedControl.setContentOffset(CGSize(width: 0, height: -5), forSegmentAt: 1)
} else {
segmentedControl.setContentOffset(CGSize(width: 5, height: -5), forSegmentAt: 0)
segmentedControl.setContentOffset(CGSize(width: 0, height: -5), forSegmentAt: 1)
}
segmentedControl.setBackgroundImage(backgroundWithColor(color: .backgroundGray, frame: CGRect(x: 0, y: 0, width: segmentedControl.frame.width, height: segmentedControl.frame.height)), for: .normal, barMetrics: .default)
segmentedControl.setDividerImage(imageWithColor(color: UIColor.white), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
segmentedControl.addTarget(self, action: #selector(showSection), for: .valueChanged)
seg = segmentedControl
}
#objc func showSection(sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
isSegment0 = true
tableView.reloadData()
case 1:
isSegment0 = false
tableView.reloadData()
default:
break
}
}
Then in ViewForHeaderInSection function of table view added seg to the header view.
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 && AppSettings.boolValue(.isHirer) || section == 0 && !AppSettings.boolValue(.isHirer) {
let headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 90))
headerView.backgroundColor = .backgroundGray
let segmentControl = seg
segmentControl.tag = section
headerView.addSubview(segmentControl)
return headerView
Please try modifying your code as follows:
Before:
UISegmentedControl.appearance().setTitleTextAttributes(...)
After:
segmentedControl.setTitleTextAttributes(...)
i.e. do not use appearance proxy on the UISegmentedControl class
The appearance proxy would typically be done once in an app early in its lifecycle before any controls of that class are instantiated. For example, you might instead use the appearance proxy in your AppDelegates didFinishLaunching() API, this would replace the need to call setTitleTextAttributes() elsewhere in your code.
Please report back if this helps.
Related
I have a header in my sectioned table view that contains a button that expands its cells when tapped, I have a right ward facing arrow in the header as well, and when the header is tapped I want to change that arrow image to a downward facing arrow, how can I alter the section's header? Specifically the arrowButton
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 50))
let button = UIButton(frame: CGRect(x: 0, y: 0, width: tableView.frame.width - 30, height: 50))
button.setTitle(tableDataSource[section][0].mod.modType!, for: .normal)
button.titleLabel?.font = UIFont(name: "Helvetica neue", size: 20)
button.addTarget(self, action: #selector(headerPressed(sender:)), for: .touchUpInside)
button.titleLabel?.textAlignment = .left
button.tag = section
let arrowButton = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
arrowButton.setImage(UIImage(systemName: "chevron.right", compatibleWith: nil), for: .normal)
header.addSubview(arrowButton)
header.addSubview(button)
header.backgroundColor = UIColor.green
return header
}
#objc func headerPressed(sender: UIButton){
if(tableDataSource[sender.tag][0].clicked == false){
tableDataSource[sender.tag][0].clicked = true
} else {
tableDataSource[sender.tag][0].clicked = false
}
let sections = IndexSet.init(integer: sender.tag)
tableView.reloadSections(sections, with: .fade)
}
You need to change this inside viewForHeaderInSection
let name = tableDataSource[section][0].clicked ? "chevron.right" : "chevron.left"
arrowButton.setImage(UIImage(systemName:name, compatibleWith: nil), for: .normal)
And calling this tableView.reloadSections(sections, with: .fade) will do the reload job
I have created a common nevigation method in view controller extension to show back, close and cart item on navigation bar through out my application. It shows the items on nav bar properly. But the cart item which is at the right side of the nav bar, has a button icon and a round badge icon with label. I need to update the label and increase the count on label every time an item is added in the cart. But somehow the label is not changing. Below is my code -
UIViewController Extension -
func setCartBarButtonItem() {
let cartBarButton = UIBarButtonItem.init(customView: getCartButton())
self.navigationItem.rightBarButtonItem = cartBarButton
}
func getCartButton() -> UIButton{
let frame = CGRect.init(x: UIScreen.main.bounds.width - 40, y: 14, width: 44, height:44)
let cartButton = UIButton.init(frame: frame)
cartButton.setImage(UIImage(named: "cart"), for: .normal)
cartButton.addTarget(self, action: #selector(self.cartButtonTapped), for: .touchUpInside)
let cartLabelView = UIView(frame: CGRect(x: cartButton.layer.bounds.width/2, y: 10, width: 16, height: 16))
cartLabelView.backgroundColor = UIColor(red: 255.0/255.0, green: 234.0/255.0, blue: 41.0/255.0, alpha: 1.0)
cartLabelView.layer.cornerRadius = 8
cartLabelView.layer.borderWidth = 0.5
cartLabelView.layer.borderColor = UIColor(red: 54.0/255.0, green: 54.0/255.0, blue: 54.0/255.0, alpha: 1.0).cgColor
cartButton.addSubview(cartLabelView)
let cartLabel = UILabel(frame: CGRect(x: cartLabelView.layer.bounds.width/3, y: 0, width: cartLabelView.layer.bounds.width, height: cartLabelView.layer.bounds.height))
cartLabel.textColor = UIColor.black
cartLabel.font = UIFont(name: "Arial", size: 9)
cartLabelView.addSubview(cartLabel)
cartLabelView.isHidden = true
var count = 0
count = getNumberOfItemInCart()
if count > 0 {
cartLabelView.isHidden = false
cartLabel.text = String(count)
}
return cartButton
}
In one delegate function which is called when item is added in cart, I call the this setCartBarButtonItem() to update the label. But label does not update. It shows the last value only.
I am attempting to animate the background image of my HomeController.
I would like to fade the image in, as such I was hoping to animate it's alpha property.
I have found many answers on here around this, however many seem dated (obj c, iOS 3/4/5 etc) and following the recommended approach, I still cannot get this animation to work.
Can anyone please tell me what is wrong with my code?
I would like to animate backgroundImage. I have placed my animation code at the end of my setupView method.
It does not 'fade in' as I would like, essentially the alpha jumps straight to 0.7
import UIKit
class HomeController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
private let backgroundImage: UIImageView = {
let image = UIImageView()
image.image = #imageLiteral(resourceName: "foggy").withRenderingMode(.alwaysOriginal)
image.contentMode = .scaleToFill
image.alpha = 0
image.isOpaque = false
return image
}()
private let currentLocation: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Southampton, UK", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 24)
button.contentMode = .center
button.setTitleColor(.black, for: .normal)
button.addTarget(self, action: #selector(onPressLocation), for: .touchUpInside)
return button
}()
private let currentTemp: UIButton = {
let button = UIButton(type: .system)
button.setTitle("37°C", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 54, weight: .thin)
button.contentMode = .center
button.setTitleColor(.white, for: .normal)
button.addTarget(self, action: #selector(onPressTemp), for: .touchUpInside)
return button
}()
}
extension HomeController {
#objc fileprivate func onPressLocation() -> Void {
print("Location pressed.")
}
#objc fileprivate func onPressTemp() -> Void {
self.currentTemp.setTitle("98°F", for: .normal)
}
fileprivate func setupView() -> Void {
view.backgroundColor = .white
// MARK: Background Image
view.addSubview(backgroundImage)
backgroundImage.anchor(
top: view.safeAreaLayoutGuide.topAnchor,
left: view.safeAreaLayoutGuide.leftAnchor,
bottom: view.safeAreaLayoutGuide.bottomAnchor,
right: view.safeAreaLayoutGuide.rightAnchor,
paddingTop: 0,
paddingLeft: 0,
paddingBottom: 0,
paddingRight: 0,
width: 0,
height: 0
)
// MARK: Current Location
view.addSubview(currentLocation)
currentLocation.anchor(
top: view.safeAreaLayoutGuide.topAnchor,
left: view.safeAreaLayoutGuide.leftAnchor,
right: view.safeAreaLayoutGuide.rightAnchor,
paddingTop: 50,
paddingLeft: 0,
paddingBottom: 0,
paddingRight: 0,
width: 0,
height: 26,
centerX: view.centerXAnchor
)
// MARK: Temp Button
view.addSubview(currentTemp)
currentTemp.anchor(
top: currentLocation.bottomAnchor,
paddingTop: 10,
paddingLeft: 0,
paddingBottom: 0,
paddingRight: 0,
width: 200,
height: 70,
centerX: view.centerXAnchor
)
// MARK: Animations
UIView.animate(withDuration: 6, delay: 3, options: .curveEaseInOut, animations: {
self.backgroundImage.alpha = 0.7
}, completion: nil)
}
}
IBOutlets does not get visible when viewDidLoad is called so call your setupView method in viewDidAppear which is called after your view appeared on screen.
Hope this helps.
You can put your code in viewDidAppear view life cycle method for any animation work ,because viewDidAppear method notifies the view controller that its view was added to a view hierarchy.Use below code for your solution.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated: animated)
//Call method like this
setupView()
}
I am very new to swift and I am stuck with the task described in the title.
My Problem:
I am building a product page programmatically, consisting of a few simple details and an offer button. Tapping offer button brings up an overlay on the view with some other details. You click "Ok" and the overlay disappears.
All good except the overlay does not disappear!
What I have tried:
func hideOverlay(_ sender: UIButton) {
containerView.backgroundColor = UIColor.white
buttonView.backgroundColor = UIColor.white
for subview in overlayView.subviews {
subview.removeFromSuperview()
}
}
Function is called on tapping the button within the overlayView. I will include the showOverlay function(working).
func showOverlay(_ sender: UIButton) {
//Load overlay view
let overlayHeight : CGFloat = 500
let overlayWidth : CGFloat = 290
let overlayView = UIView(frame: CGRect(x: centreView(masterView: view.frame.width, subView: overlayWidth), y: 64 + centreView(masterView: (view.frame.height - 64), subView: overlayHeight), width: overlayWidth, height: overlayHeight))
overlayView.backgroundColor = UIColor.white
let overlayTitle = UILabel(frame: CGRect(x: 0, y: 0, width: overlayWidth, height: overlayHeight*1/5))
overlayTitle.text = "Offer Taken"
overlayTitle.font = UIFont.boldSystemFont(ofSize: 35)
overlayTitle.textAlignment = .center
overlayView.addSubview(overlayTitle)
let overlayButtonView = UIView(frame: CGRect(x: 0, y: 0 + (overlayHeight * 4/5), width: overlayWidth, height: overlayHeight * 1/5))
overlayButtonView.backgroundColor = UIColor.red
let buttonWidth : CGFloat = 100
let buttonHeight : CGFloat = 35
let overlayButton = UIButton(type: UIButtonType.system)
overlayButton.frame = CGRect(x: centreView(masterView: overlayWidth, subView: buttonWidth), y: overlayButtonView.frame.origin.y + centreView(masterView: overlayButtonView.frame.height, subView: buttonHeight), width: buttonWidth, height: buttonHeight)
overlayButton.backgroundColor = UIColor.blue
overlayButton.setTitle("OK",for: .normal)
overlayButton.setTitleColor(UIColor.white, for: .normal)
overlayButton.setTitle("Offer Taken", for: .highlighted)
overlayButton.setTitleColor(UIColor.white, for: .highlighted)
overlayButton.addTarget(self, action: #selector(self.hideOverlay(_:)), for: .touchUpInside)
overlayView.addSubview(overlayButtonView)
overlayView.addSubview(overlayButton)
containerView.backgroundColor = UIColor(colorLiteralRed: 0, green: 0, blue: 0, alpha: 0.5)
buttonView.backgroundColor = UIColor(colorLiteralRed: 0, green: 0, blue: 0, alpha: 0.5)
view.addSubview(overlayView)
}
I have tried
overlayView.removeFromSuperview()
after the for loop, but I fear that overlayView.subviews is not correctly filled with the views I expect.
I appreciate anyone taking the time to help me, even if a little closer to a solution.
In func showOverlay(_ sender: UIButton) {...} you are creating a local variable "overlayView":
let overlayView = UIView(frame: ...)
You then add that as a subview to view. All that is fine, except you do not keep a reference to "overlayView" .. the view remains but you have no reference to it.
Add a class-level variable, outside of any function blocks:
var overlayView: UIView!
Then, inside func showOverlay(_ sender: UIButton) {...}, instead of let overlayView = just assign it to the existing variable:
overlayView = UIView(frame: ...)
When you're ready to remove it:
func hideOverlay(_ sender: UIButton) {
overlayView.removeFromSuperview()
}
and you're done :)
Try the viewWithTag method described in a similar thread here:
Swift addsubview and remove it
I upgraded xcode from 7.3.1 to 8 and converted to swift 2.2, other than the storyboard being a mess everything worked except adding a UIView programatically.
This was working fine before, now nothing shows up at all and there are no errors. Any ideas?
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
//create view
let vw = UIView()
vw.backgroundColor = UIColor(red: 0.9137, green: 0.9176, blue: 0.9216, alpha: 1.0) /* #e9eaeb */
//create label inside view
let label: UILabel = UILabel()
label.frame = CGRectMake(0, 0, 200, 28)
label.textAlignment = NSTextAlignment.Left
label.textColor = UIColor.grayColor()
label.font = label.font.fontWithSize(13)
if !clearSearch {
label.text = " Recent Searches"
} else {
label.text = " Search Results"
}
vw.addSubview(label)
//create button inside view
let button: UIButton = UIButton()
button.frame = CGRectMake(self.view.frame.size.width - 45, 0, 40, 28)
button.titleLabel?.font = UIFont.systemFontOfSize(13)
button.setTitle("Clear", forState: UIControlState.Normal)
button.addTarget(self, action: #selector(deleteSearches), forControlEvents: UIControlEvents.TouchUpInside)
button.setTitleColor(UIColor(red: 0.3216, green: 0.7176, blue: 0.5333, alpha: 1.0), forState: UIControlState.Normal)
vw.addSubview(button)
return vw
}
Thanks for any help.
Looks like this is now required.
override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 28
}