Referring Above Image :
I want to place UISwitch in Subcell of cell4.
I did this code to do this inside cellForRowAt indexPath
if(indexPath.section == 3) {
if(indexPath.row == 0) {
let mySwitch = UISwitch()
let xpos = cell.frame.width - 60
let ypos = cell.frame.origin.y + 6
mySwitch.frame = CGRect(x: xpos, y: ypos, width:50, height: 26)
mySwitch.setOn(true, animated: false)
mySwitch.onTintColor = UIColor.init(red: 0.91, green: 0.30, blue: 0.24, alpha: 1.0)
mySwitch.addTarget(self, action: #selector(switchChanged(sender:)), for: UIControlEvents.valueChanged)
menuTableView.addSubview(mySwitch)
}
}
Now What happening is :
Initially Switch appearing on cell 1 when table view loads. After expanding and collapsing cell4 once , it appears at submenu of cell4. How to resolve this incorrect position issue?
You should append your switch to your cell instead of the tableView.
Related
I have a tableView that displays hidden cells when the user scrolls. Not sure why this behavior is happening.
In viewDidLoad()
watchListTable = UITableView(frame: CGRect(x: self.view.frame.width * 0.25, y: 0, width: self.view.frame.width * 0.75, height: 300)) //height = 200
watchListTable.isHidden = true
watchListTableFrame = CGRect(x: self.view.frame.width * 0.25, y: 0, width: self.view.frame.width * 0.75, height: 300)
watchListTableFrameHide = CGRect(x: self.view.frame.width * 0.25, y: 0, width: self.view.frame.width * 0.75, height: 0)
watchListTable.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
watchListTable.register(UITableViewCell.self, forCellReuseIdentifier: "closeCell")
watchListTable.dataSource = self
watchListTable.delegate = self
watchListTable.CheckInterfaceStyle()
watchListTable.roundCorners(corners: .allCorners, radius: 8)
watchListTable.backgroundColor = .systemGray6
//remove the bottom line if there is only one option
watchListTable.tableFooterView = UIView()
view.addSubview(watchListTable)
Once the user taps on a button, the table expands in an animatable fashion.
//watchlist won't animate properly on the initial setup. So we set it to be
hidden, then change the frame to be 0, unhide it, and then animate it. Only will
be hidden on the initial setup.
if(watchListTable.isHidden == true)
{
watchListTable.isHidden = false
watchListTable.frame = watchListTableFrameHide
}
UIView().animateDropDown(dropDown: watchListTable, frames:
self.watchListTableFrame)
watchListTable.reloadData()
In func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
if(indexPath.row >= watchListStocks.count)
{
let cell = tableView.dequeueReusableCell(withIdentifier: "closeCell",
for: indexPath as IndexPath)
cell.selectionStyle = .none
cell.textLabel?.text = indexPath.row == watchListStocks.count + 1 ?
"Close List" : "Create New Watchlist"
cell.textLabel?.textColor = .stockOrbitTeal
cell.textLabel?.textAlignment = .center
cell.backgroundColor = .systemGray6
cell.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right:
.greatestFiniteMagnitude)
return cell
}
else
{
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for:
indexPath as IndexPath)
cell.selectionStyle = .none
if(indexPath.row == 0)
{
cell.layer.cornerRadius = 8
cell.layer.maskedCorners = [.layerMinXMinYCorner,
.layerMaxXMinYCorner]
}
else
{
cell.layer.cornerRadius = 8
cell.layer.maskedCorners = [.layerMinXMaxYCorner,
.layerMaxXMaxYCorner]
cell.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right:
.greatestFiniteMagnitude)
cell.directionalLayoutMargins = .zero
}
let label = UITextView()
label.frame = CGRect(x: 0, y: 0, width: cell.frame.width * 0.45, height:
cell.frame.height)
label.text = watchListStocks[indexPath.row].listName
label.textColor = .stockOrbitTeal
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 18, weight: UIFont.Weight.medium)
label.backgroundColor = .systemGray5
label.delegate = self
label.tag = indexPath.row
cell.addSubview(label)
cell.backgroundColor = .systemGray5
cell.layer.cornerRadius = 8
return cell
}
When I scroll, all cells are hidden. I see that they are created in cellForRowAt, however, they do not appear on my screen. Why are the cells being hidden? I have searched all over stackoverflow.
You shouldn't add subviews inside cellForRowAt. When you call dequeueReusableCell, at first it'll create new cells, but when you start scrolling it'll start returning cells that were dismissed earlier, means they already have UITextView subview, and you're adding one more on top of that.
cell returned by dequeueReusableCell doesn't have to have final size already, that's why you can't use cell.frame.width to calculate your subview size, I think that's may be the reason you can't see it.
What you need to do: create a UITableView subclass, something like this:
class MyCell: UITableViewCell {
let label = UITextView()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupCell()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupCell()
}
func setupCell() {
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 18, weight: UIFont.Weight.medium)
label.backgroundColor = .systemGray5
contentView.addSubview(label)
}
override func layoutSubviews() {
super.layoutSubviews()
label.frame = CGRect(x: 0, y: 0, width: contentView.frame.width * 0.45, height: contentView.frame.height)
}
}
Here you're adding a subview during initialisation only once and update label frame each time cell size gets changed. Don't forget to add this class to your cell in the storyboard and let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath as IndexPath) as! MyCell, so you can set delegate to text field, etc.
If this won't help, check out View Hierarchy to see what's actually going on there
So after many hours, I figured it out...
I had called this function in viewDidLoad()
watchListTable.roundCorners(corners: .allCorners, radius: 8)
Which made my table hidden after I scrolled. I removed this line of code, and the table is now completely visible when scrolling.
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.
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 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 have a UIButton in a uitableviewcell associated to a target:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! ProCell
cell.btn.tag = indexPath.row
cell.btn.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
This is the buttonClicked function:
func buttonClicked(sender:UIButton) {
let boton = sender as UIButton
let index = boton.tag
let buttonPosition: CGPoint = boton.convertPoint(CGPointZero, toView: self.tableView)
var indexPath: NSIndexPath = self.tableView.indexPathForRowAtPoint(buttonPosition)!
let cell = self.tableView.cellForRowAtIndexPath(indexPath) as! ProductoCell
cell.btn.setImage(UIImage (named: "rotacion-Null"), forState: UIControlState.Normal)
let indicador = UIActivityIndicatorView()
indicador.frame = CGRect(x: 0, y: 0, width: 25, height: 25)
indicador.color = UIColor(red: 153.0/255.0, green: 0.0, blue: 0.0, alpha: 1.0)
indicador.startAnimating()
cell.btn.addSubview(indicador)
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
let datosEd = ed.search(product)
dispatch_async(dispatch_get_main_queue(), {
//update UI in main thread once the loading is completed.
indicador.stopAnimating()
indicador.hidesWhenStopped = true
let label2 = UILabel(frame: CGRect(x: 15 , y: -5, width: 16, height: 16))
label2.textAlignment = NSTextAlignment.Center
label2.font = UIFont.boldSystemFontOfSize(13.0)
label2.backgroundColor = UIColor (red: 0.85, green: 0.20, blue: 0.33, alpha: 1.0)
label2.textColor = UIColor.whiteColor()
label2.layer.masksToBounds = true
label2.layer.cornerRadius = 8
let rowData = datosEd[0] as! NSDictionary
if rowData["art"] as! String == "No Results" {
label2.text = "0"
cell.contentView.addSubview(label2)
cell.btn.setImage(UIImage (named: "ed-25G"), forState: UIControlState.Normal)
} else {
label2.text = String(datosEd.count)
cell.btn.addSubview(label2)
cell.btn.setImage(UIImage (named: "ed-25R"), forState: UIControlState.Normal)
}
});
})
}
The problem is when I scroll down and scroll up back again, the subview(label2) is repeated in some cells.
Reading some responses think it has to do with the reuse of the cells, but I do not how to make the subviews are not repeated.
Some help, please... :-)