I want to make section header conditional in following code so that i can add a "+" button on one section header.Following is my method:
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let customSecHeader = UIView()
if (section == 0)
{
let titleLabel = UILabel()
let addButton = UIButton()
titleLabel.text = "\(self.section[section]) (\(self.items[section].count))"
titleLabel.font = UIFont(name: "MarkerFelt-Thin", size: 15)
titleLabel.textColor = UIColor.redColor()
titleLabel.textAlignment = .Left
titleLabel.frame = CGRectMake(5,5,140,30)
addButton.setTitle("+", forState: .Normal)
addButton.setTitleColor(UIColor.blueColor(), forState: .Normal)
addButton.frame = CGRectMake(60,5,10,10)
customSecHeader.addSubview(titleLabel)
customSecHeader.addSubview(addButton)
}
else
{
let titleLabel = UILabel()
titleLabel.text = "\(self.section[section]) (\(self.items[section].count))"
titleLabel.font = UIFont(name: "MarkerFelt-Thin", size: 15)
titleLabel.textColor = UIColor.redColor()
titleLabel.textAlignment = .Center
titleLabel.frame = CGRectMake(5,5,140,30)
customSecHeader.addSubview(titleLabel)
}
return customSecHeader
}
But this code is not working.When i tried to debug this method i found that this method was executed once with section = 1 but i have 2 section in my table.
Related
recently, I decided to quit using storyboards on my IOS app. So, am presently learning everything now with code. I was trying to place a label below navigationBar view but I got an error and I don't know how to debug it. Please view my code and share your thoughts.
class SellBaseViewController: UIViewController {
lazy var container: UIStackView = {
let stackView = UIStackView(frame: .zero)
stackView.alignment = .fill
stackView.axis = .vertical
stackView.spacing = 2
stackView.willSetConstraints()
return stackView
}()
lazy var navHeader: UIView! = {
return self.navBar()
}()
lazy var firstLabel: UILabel! = {
return self.labelOne()
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if !Authentication.shared.isAuthenticated {
showLogin()
} else {
self.setupInterface()
}
}
private func setupInterface() {
self.navigationController?.navigationBar.isHidden = true
self.embedInScrollView(content: self.container)
navHeader.willSetConstraints()
firstLabel.willSetConstraints()
self.container.addArrangedSubviews([self.navHeader!, self.firstLabel!])
DispatchQueue.main.async {
NSLayoutConstraint.activate([
self.navHeader.heightAnchor.constraint(equalToConstant: 44),
self.navHeader.widthAnchor.constraint(equalTo: self.view.widthAnchor),
self.navHeader.topAnchor.constraint(equalTo: self.container.topAnchor),
])
}
}
// MARK: NAVBAR
func navBar() -> UIView {
let navBar = UIView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: self.view.frame.width, height: 44)))
navBar.backgroundColor = UIColor.constants.darkBlue
let backIcon = UIImage(named: "ic_back")?.withRenderingMode(.alwaysTemplate)
let returnButton = UIButton(type: .custom)
returnButton.imageView?.tintColor = UIColor.white
returnButton.setImage(backIcon, for: .normal)
returnButton.image(for: .normal)
returnButton.titleLabel?.font = UIFont(name: "Hind", size: 18)
returnButton.setTitle("Sell", for: .normal)
returnButton.setTitleColor(UIColor.white, for: .normal)
returnButton.addTarget(self, action: #selector(self._return), for: .touchUpInside)
returnButton.willSetConstraints()
navBar.addSubviews([returnButton])
NSLayoutConstraint.activate([
returnButton.centerYAnchor.constraint(equalTo: navBar.centerYAnchor),
returnButton.leadingAnchor.constraint(equalTo: navBar.leadingAnchor, constant: 11),
returnButton.heightAnchor.constraint(equalToConstant: 24),
returnButton.widthAnchor.constraint(equalToConstant: 71),
])
return navBar
}
func labelOne() -> UILabel{
let label = UILabel()
label.textAlignment = .center
label.textColor = .white
label.font = UIFont(name: "Avenir-Light", size: 15.0)
label.text = "This is a Label"
self.view.addSubview(label)
return labelOne()
}
#objc func _return() {
self.backHome()
}
}
The navBar showed well, but when I added the label, the app kept crashing with this error. I don't know how to find out exactly what the error is:
Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffee6703fe8)
func labelOne() -> UILabel{
let label = UILabel()
label.textAlignment = .center
label.textColor = .white
label.font = UIFont(name: "Avenir-Light", size: 15.0)
label.text = "This is a Label"
self.view.addSubview(label)
return labelOne()
}
You did:
return labelOne()
You should do:
return label
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
}
hello I want to add two buttons on my ViewController programmatically like this
What I have done is this
func createButton(buttonTitle: String,buttonAction: Selector) -> UIButton{
let button = UIButton(type: UIButtonType.System) as UIButton
button.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.frame)/2, 48)
// button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle(buttonTitle, forState: UIControlState.Normal)
button.addTarget(self, action:buttonAction, forControlEvents: UIControlEvents.TouchUpInside)
button.setTitleColor(UIColor.whiteColor(), forState:UIControlState.Normal)
button.titleLabel?.font = UIFont(name: Variables.MONTESERRAT_REGULAR, size: 20.0)
button.backgroundColor = UIColor().blueColor() //top
button.titleEdgeInsets = UIEdgeInsetsMake(0.0,10.0, 10.0, 0.0)
return button
}
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView()
footerView.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.frame), 48)
bottomButton = createButton("PUBLISH", buttonAction: "Publish")
footerView.addSubview(bottomButton!)
return footerView
}
At the moment it only prints one button. for second button I am doing this
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView()
footerView.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.frame), 48)
bottomButton = createButton("PUBLISH", buttonAction: "Publish")
bottomButton2 = createButton("Delete", buttonAction: "Delete")
footerView.addSubview(bottomButton!)
footerView.addSubview(bottomButton2!)
return footerView
}
This code is not printing two buttons. just printing only one
I think the problem is that both buttons have the same position, so one is showing above the other.
Try this:
func createButton(buttonTitle: String,buttonAction: Selector, buttonNumber : Int) -> UIButton{
let backgroundColor = buttonNumber == 0 ? UIColor.blueColor() : UIColor.orangeColor()
let space : CGFloat = 5
let button = UIButton(type: UIButtonType.System) as UIButton
let width = (CGRectGetWidth(self.view.frame) - space)/2
let xPos = buttonNumber == 0 ? 0 : width + space
button.frame = CGRectMake(xPos, 0, width, 48)
// button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle(buttonTitle, forState: UIControlState.Normal)
button.addTarget(self, action:buttonAction, forControlEvents: UIControlEvents.TouchUpInside)
button.setTitleColor(UIColor.whiteColor(), forState:UIControlState.Normal)
// button.titleLabel?.font = UIFont(name: Variables.MONTESERRAT_REGULAR, size: 20.0)
button.backgroundColor = backgroundColor
button.titleEdgeInsets = UIEdgeInsetsMake(0.0,10.0, 10.0, 0.0)
return button
}
And then add it like so:
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView()
footerView.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.frame), 48)
bottomButton = createButton("PUBLISH", buttonAction: "Publish", buttonNumber: 0)
bottomButton2 = createButton("Delete", buttonAction: "Delete", buttonNumber: 1)
footerView.addSubview(bottomButton!)
footerView.addSubview(bottomButton2!)
return footerView
}
I have a problem when I scroll in my tableview which contains elements that can be scrolled horizontal it is mixing the values.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell : RoundWorkoutCell! = tableView.dequeueReusableCellWithIdentifier("Cell") as! RoundWorkoutCell
let tmpCell = cell
print(tmpCell)
if(cell == nil)
{
cell = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)[0] as! RoundWorkoutCell;
}
let exerviseName = RoundLabels[indexPath.row]
if(indexPath.row == 0){
for countMe in 0..<self.round_1_exercises.count {
if(countMe<1){
roundPosition1.append(5)
}else{
roundPosition1.append(115+roundPosition1[countMe-1])
}
scrollerSize = 115+roundPosition1[countMe]
}
}else if(indexPath.row == 1){
for countMe in 0..<self.round_2_exercises.count {
if(countMe<1){
roundPosition2.append(5)
}else{
roundPosition2.append(115+roundPosition2[countMe-1])
}
scrollerSize = 115+roundPosition2[countMe]
}
}else if(indexPath.row == 2){
for countMe in 0..<self.round_3_exercises.count {
if(countMe<1){
roundPosition3.append(5)
}else{
roundPosition3.append(115+roundPosition3[countMe-1])
}
scrollerSize = 115+roundPosition3[countMe]
}
}......
cell.RoundExercise_Cell_ScrollView.contentSize = CGSizeMake(CGFloat(scrollerSize),115)
cell.RoundExercise_Cell_ScrollView.showsHorizontalScrollIndicator = true
cell.RoundExercise_Cell_ScrollView.indicatorStyle = .Default
if(indexPath.row==0){
for index in 0..<self.round_1_exercises.count {
print("Round position 1 \(self.roundPosition1[index])")
var imageView : UIImageView
imageView = UIImageView(frame:CGRect(x:roundPosition1[index],y: 5, width:110, height: 110 ))
imageView.backgroundColor = UIColor.whiteColor()
cell.RoundExercise_Cell_ScrollView.addSubview(imageView)
let label1: UILabel = UILabel()
label1.frame = CGRect(x:roundPosition1[index],y: 5, width:110, height: 20 )
label1.textColor = UIColor(red:17/255.0, green: 22/255.0, blue: 40/255.0, alpha:1.0)
label1.textAlignment = NSTextAlignment.Center
label1.font = UIFont(name: "OpenSans-CondensedLight", size: 14)
label1.text = exerciseInfo.exercise_name(self.round_1_exercises[index] as! String)
cell.RoundExercise_Cell_ScrollView.addSubview(label1)
let frame1 = CGRect(x:roundPosition1[index]+10,y:25, width:90, height: 90 )
let button = UIButton(frame: frame1)
button.backgroundColor = UIColor.redColor()
button.setBackgroundImage(UIImage(named: (self.round_1_exercises[index] as? String)!) as UIImage?, forState: .Normal)
button.setTitleColor(UIColor.blackColor(), forState: .Normal)
button.setTitle(self.round_1_exercises[index] as? String, forState: .Normal)
button.setTitleColor(UIColor(red:0/255,green:0/255,blue:0/255,alpha:0.0), forState: .Normal)
button.addTarget(self, action: "buttonClick:", forControlEvents: .TouchUpInside)
cell.RoundExercise_Cell_ScrollView.addSubview(button)
let label: UILabel = UILabel()
label.frame = CGRect(x:roundPosition1[index],y: 115, width:110, height: 20 )
label.font = UIFont(name: "OpenSans", size: 14)
label.textColor = UIColor.whiteColor()
label.textAlignment = NSTextAlignment.Center
label.text = self.round_1_decoration[index] as? String
cell.RoundExercise_Cell_ScrollView.addSubview(label)
}
}else if(indexPath.row == 1){
for index in 0..<self.round_2_exercises.count {
print("Round position 2 \(self.roundPosition2[index])")
var imageView : UIImageView
imageView = UIImageView(frame:CGRect(x:roundPosition2[index],y: 5, width:110, height: 110 ))
imageView.backgroundColor = UIColor.whiteColor()
cell.RoundExercise_Cell_ScrollView.addSubview(imageView)
let label1: UILabel = UILabel()
label1.frame = CGRect(x:roundPosition2[index],y: 5, width:110, height: 20 )
label1.textColor = UIColor(red:17/255.0, green: 22/255.0, blue: 40/255.0, alpha:1.0)
label1.textAlignment = NSTextAlignment.Center
label1.font = UIFont(name: "OpenSans-CondensedLight", size: 14)
label1.text = exerciseInfo.exercise_name(self.round_2_exercises[index] as! String)
cell.RoundExercise_Cell_ScrollView.addSubview(label1)
let frame1 = CGRect(x:roundPosition2[index]+10,y:25, width:90, height: 90 )
let button = UIButton(frame: frame1)
button.backgroundColor = UIColor.redColor()
button.setBackgroundImage(UIImage(named: (self.round_2_exercises[index] as? String)!) as UIImage?, forState: .Normal)
button.setTitleColor(UIColor.blackColor(), forState: .Normal)
button.setTitle(self.round_2_exercises[index] as? String, forState: .Normal)
button.setTitleColor(UIColor(red:0/255,green:0/255,blue:0/255,alpha:0.0), forState: .Normal)
button.addTarget(self, action: "buttonClick:", forControlEvents: .TouchUpInside)
cell.RoundExercise_Cell_ScrollView.addSubview(button)
let label: UILabel = UILabel()
label.frame = CGRect(x:roundPosition2[index],y: 115, width:110, height: 20 )
label.font = UIFont(name: "OpenSans", size: 14)
label.textColor = UIColor.whiteColor()
label.textAlignment = NSTextAlignment.Center
label.text = self.round_2_decoration[index] as? String
cell.RoundExercise_Cell_ScrollView.addSubview(label)
}
}.....
cell.RoundExercise_Cell_Label.text = exerviseName
return cell as RoundWorkoutCell
}
Here is the custom cell class
class RoundWorkoutCell: UITableViewCell {
#IBOutlet var RoundExercise_Cell_Label: UILabel!
#IBOutlet var RoundExercise_Cell_ScrollView: UIScrollView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.RoundExercise_Cell_Label.text = ""
self.RoundExercise_Cell_ScrollView.contentSize = CGSizeMake(CGFloat(0),115)
}
I have placed this thread before but no one answered.I need to fix this.I have finished my whole app and this is left.I know that i have to use somehow prepareForReuse() but am not sure how,or if i could disable this reusable cells.
Thanks
The cells are reused to save on memory, this means that you need to recycle them properly to stop old data from being shown. You can do this by adding the prepareForReuse() function into your tableviewCell. In here you will need to set image outlets to be empty i.e by setting it to UIImage(). You will need to do the same with all outlets. This will ensure that old data that is not relevant will not be shown.
Example:
override func prepareForReuse() {
//myOutletName = myNilValue
super.prepareForReuse()
}
If you don't want to reuse cells, you can simply remove the call to dequeueReusableCellWithIdentifier. Try replacing these lines:
var cell : RoundWorkoutCell! = tableView.dequeueReusableCellWithIdentifier("Cell") as! RoundWorkoutCell
let tmpCell = cell
print(tmpCell)
if(cell == nil)
{
cell = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)[0] as! RoundWorkoutCell;
}
With this:
cell = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)[0] as! RoundWorkoutCell;
This approach doesn't reuse cells and will be less performant and will leak memory.
A better approach would be to construct the cells once and then reuse them, instead of rebuilding them in cellForRowAtIndexPath method. For example, if you design the cells in the NIB (as you are doing now), there's no need to add buttons and labels again by code, you can simply change the contents and hide those that are not needed.
Then, on prepareForReuse (or even at the beginning of cellForRowAtIndexPath), you reset the content of the row to the initial state.
class RoundWorkoutCell: UITableViewCell {
#IBOutlet var RoundExercise_Cell_Label: UILabel!
#IBOutlet var RoundExercise_Cell_ScrollView: UIScrollView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.RoundExercise_Cell_Label.text = ""
self.RoundExercise_Cell_ScrollView.contentSize = CGSizeMake(CGFloat(0),115)
}
override func prepareForReuse() {
//myOutletName = myNilValue
self.RoundExercise_Cell_Label.text = ""
self.RoundExercise_Cell_ScrollView.contentSize = CGSizeMake(CGFloat(0),115)
for subview in RoundExercise_Cell_ScrollView.subviews {
print(subview)
subview.removeFromSuperview()
}
super.prepareForReuse()
}
}
#Swinny89 was at right point thank you for that, but I can add more detail about prepareForReuse method. If you remove all your reusing cell data in that method, the performance will reduce. On the other hand, you can hide your variables in prepareForReuse method, and make them visible in your cell init method.
For example as the way I did:
override func prepareForReuse() {
if(commentLabels != nil) {
for item in commentLabels {
item.hidden = true
}
}
super.prepareForReuse()
}
In other method I make the visible with if check:
if(commentLabels == nil) {
// creating new labels and adding to commentLabels
} else { // it means reuse cell data and it has been hidden
// hidden = false
for item in commentLabels {
item.hidden = false
}
}
I use a for-loop to create labels and buttons inside my scrollView.
Is it possible to remove all objects indside my scrollView? (I would like to update it with new content)
for peop in personArray{
scrollView.clearContent ??????
// Name label
var label: UILabel = UILabel()
label.frame = CGRectMake(8, CGFloat(nameHeight), 183, 21)
label.backgroundColor = UIColor.whiteColor()
label.textColor = UIColor(red: 90/255.0, green: 187/255.0, blue: 206/255.0, alpha: 1.0)
label.textAlignment = NSTextAlignment.Left
label.font = UIFont (name: "HelveticaNeue-Light", size: 14)
label.text = " \(peop.getName()) - \(sex)"
self.scrollView.addSubview(label)
//Delete button
var button = UIButton.buttonWithType(UIButtonType.System) as UIButton
button.tag = playerId
button.frame = CGRectMake(199, CGFloat(nameHeight), 37, 21)
button.backgroundColor = colorWheel.colorsArray[7]
button.setTitle("Slet", forState: UIControlState.Normal)
button.addTarget(self, action: "delAction:", forControlEvents: UIControlEvents.TouchUpInside)
button.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
self.scrollView.addSubview(button)
button.titleLabel!.font = UIFont(name: "HelveticaNeue-Light", size: 14)
scrollHeight = scrollHeight + 29
nameHeight = nameHeight + 29
playerId++
}
scrollView.contentSize = CGSize(width: 20.0, height: CGFloat(nameHeight))
}
func delAction(sender: UIButton!){
personArray.removeAtIndex(sender.tag)
updatePeople()
}
Have you tried this ?
let subViews = self.scrollView.subviews
for subview in subViews{
subview.removeFromSuperview()
}
One line solution, use
scrollView.subviews.forEach({ $0.removeFromSuperview() })
UPDATED
For removing only specific kind of view, say UIButton use
scrollView.subviews.forEach ({ ($0 as? UIButton)?.removeFromSuperview() })
Removing a set of objects from differing classes can be done with tags. Set the tag when creating the set of objects.
label.tag = 99
Now, when removing the objects, use:
func removeLabels() {
let subViews = self.view.subviews
for subview in subViews {
if subview.tag == 99 {
subview.removeFromSuperview()
}
}
}
You can do this with block approach,
let views: NSArray = scroller.subviews
// 3 - remove all subviews
views.enumerateObjectsUsingBlock {
(object: AnyObject!, idx: Int, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
object.removeFromSuperview()
}