I am using Xib view as a common view in header as shown in image
When user move to next view controller and came back to previous screen it moves out side of screen as shown in image
I have auto layout the view and given 10 points margin from right side to arrow image. I am not sure why it is moving to right side.
Following is the code:
func setHeader(headerView : UIView, vc : UIViewController)
{
vc1 = vc
customView.removeFromSuperview()
customView = UINib(nibName:"ViewHeader",bundle:.main).instantiate(withOwner: nil, options: nil).first as! HeaderView
customView.btnNotification.setTitle("", for: .normal)
customView.btnReward.setTitle("", for: .normal)
customView.btnSideMenu.setTitle("", for: .normal)
customView.viewUnread.layer.cornerRadius = customView.viewUnread.frame.size.width/2
customView.viewUnread.clipsToBounds = true
customView.btnSideMenu.addTarget(self, action: #selector(Commons.openDrawer(_:)), for: .touchUpInside)
customView.lblPoints.text = String(Constants.CUSTOMERPOINTS)
customView.btnReward.addTarget(self, action: #selector(Commons.openReward(_:)), for: .touchUpInside)
customView.btnNotification.addTarget(self, action: #selector(Commons.openNotification(_:)), for: .touchUpInside)
var w = String(format: "%f", Commons.screenWidth)
var h = String(format: "%f", Commons.screenHeight)
print("screenSize ye ha --> height: " + w + " - Width:" + h)
if(Commons.screenHeight > 400 && Commons.screenHeight <= 750 )
{
customView.frame.size.height = 80.0
}
else if(Commons.screenHeight > 750 && Commons.screenHeight <= 850 )
{
// customView.ic_centerMargin.constant = -20
customView.frame.size.height = 80.0
}
else if(Commons.screenHeight > 850 && Commons.screenHeight <= 900 )
{
customView.frame.size.height = 80.0
}
else if (Commons.screenHeight > 900)
{
customView.frame.size.height = 80.0
}
let group = DispatchGroup()
group.enter()
Commons.getPoints()
{ [self] json, error in
// will be called at either completion or at an error.
// will be called at either completion or at an error.
DispatchQueue.main.async { [self] in
customView.lblPoints.text = String(Constants.CUSTOMERPOINTS)
}
group.leave()
}
group.wait()
headerView.addSubview(customView)
// customView.center = vc1.view.center;
}
Thanks in advance
Related
I have weird problem. I have a basic tap gesture recognizer added to my subview, but it works only when it likes to. Sometimes it works on second click, sometimes on the third or even more clicks. But when I added print("whatever") to the function, which is called by the gesture recognizer, it always works on the first time I click the subview.
How do I fix this?
On these two examples occur the same problem:
SubView:
let getGiftGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.getGift))
self.continueButton.addGestureRecognizer(getGiftGestureRecognizer)
DispatchQueue.main.async {
self.coverAnyUIElement(element: self.successView)
let gift = SCNNode()
gift.geometry = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0)
//nahodne vygenerovat geometry, nebo barvu
let ownedGeometries = UserDefaults.standard.array(forKey: "ownedGeometries")
let ownedColors = UserDefaults.standard.array(forKey: "ownedColors")
let notOwnedGeometriesCount = geometriesCount - ownedGeometries!.count
let notOwnedColorsCount = colorsCount - ownedColors!.count
if notOwnedGeometriesCount == 0{
//mam vsechny geometrie
//vygeneruju barvu
}else if notOwnedColorsCount == 0{
//mam vsechny barvy
//vygeneruju geometrii
}else if(notOwnedGeometriesCount == 0 && notOwnedColorsCount == 0){
//mam uplne vsechno
}else{
//vygeneruj cokoliv
let random = Int.random(in: 0...10)
if random <= 3{
//vygeneruj geometrii
}else{
//vygeneruj barvu
}
}
print(self.generateColor())
print(self.generateGeometry())
self.chest.opacity = 1
self.chest.position.y = -1.8
self.world.addChildNode(self.chest)
let viko = self.chest.childNode(withName: "viko", recursively: false)
self.chest.addChildNode(gift)
print("VLAKNO1: \(Thread.isMainThread)")
viko?.runAction(SCNAction.rotateBy(x: 0, y: 0, z: -90/(180/CGFloat.pi), duration: 1),completionHandler: {
print("VLAKNO2: \(Thread.isMainThread)")
let pohyb = SCNAction.move(by: SCNVector3(0,4,0), duration: 1)
gift.runAction(pohyb,completionHandler: {
print("VLAKNO3: \(Thread.isMainThread)")
self.showConfirmGiftButton()
})
})
}
}
Button:
confirmGiftButton.addTarget(self, action: #selector(acceptedGift), for: .touchUpInside)
#objc func acceptedGift(){
DispatchQueue.main.async {
UIButton.animate(withDuration: 0.2, animations: {
self.confirmGiftButton.alpha = 0.9
}) { (_) in
UIButton.animate(withDuration: 0.2, animations: {
self.confirmGiftButton.alpha = 1
}) { (_) in
//print("VLAKNO1: \(Thread.isMainThread)")
self.chest.runAction(SCNAction.fadeOut(duration: 0.5),completionHandler: {
// print("Vlakno: \(Thread.isMainThread)")
self.chest.removeFromParentNode()
self.moveToMenu()
})
//print("VLAKNO2: \(Thread.isMainThread)")
self.coverAnyUIElement(element: self.confirmGiftButton)
}
}
}
}
So I removed the DispatchQueue.main.async from both methods and tried it for a few times and it seems like it was the problem, because now both the subview gesture recognizer and button target works on first click correctly.
I think that it was caused because when I clicked on the button, the Main thread was already used so it somehow skipped the methods. And worked in the second or more clicks, because in that time it was already empty.
I am having trouble with the reusable aspect of my UITableViewCell. I have different type of data going into the different cells. When the types of data are the same (example: only images) I have no problem because the new image over writes the old one. But when the types of data are the same they both are sticking around.
I'm looking for methods or tools for clearing a cell completely. I have tried many things such as dictionaries to reference the data directly and erase it but that failed because I couldn't consistently tell what data was in what reused cell (especially when scrolling a lot). Others things were
cell.contentView.subviews.removeAll()
threw error, another was
cell.contentView.removeFromSuperView()
but that just made the cell useable and nothing loaded ever.
my code is below, thanks if advance for the help (ignore the date stuff).
if dictionary?["type"]! != nil {
cell.imageView?.layer.borderColor = UIColor.black.cgColor
cell.layer.borderWidth = 1
cell.imageView?.layer.cornerRadius = 1
cell.imageView?.frame = CGRect(x: 0, y: UIScreen.main.bounds.height/2, width: 25, height: 25)
self.tableTextOverLays(i: indexPath.row, type: Int((dictionary?["type"])! as! NSNumber), cell: cell)
if (indexPath.row == tableFeedCount - 1) && lockoutFeed != true && tableFeedCount == self.allDictionary.count && imageFeedCount == imageDictionary.count {
let dictionary = self.allDictionary[indexPath.row]
let date = dictionary?["date"] as! Double
let date2 = date*100000
let date3 = pow(10,16) - date2
let date4 = String(format: "%.0f", date3)
self.setUpFeed(starting: date4, queryLimit: UInt(11))
}
}
else if (dictionary?["type_"] as! String) == "Image" {
print("image feed", indexPath.row)
cell.imageView?.layer.borderColor = UIColor.black.cgColor
cell.layer.borderWidth = 1
cell.imageView?.layer.cornerRadius = 1
cell.imageView?.frame = CGRect(x: 0, y: UIScreen.main.bounds.height/2, width: 25, height: 25)
cell.imageView?.image = imageDictionary[indexPath.row]
if indexPath.row == tableFeedCount - 1 && lockoutFeed != true && tableFeedCount == self.allDictionary.count && imageFeedCount == imageDictionary.count{
let dictionary = self.allDictionary[indexPath.row]
let date = dictionary?["date"] as! Double
let date2 = date*100000
let date3 = pow(10,16) - date2
let date4 = String(format: "%.0f", date3)
setUpFeed(starting: date4, queryLimit: UInt(11))
}
}
else if (dictionary?["type_"] as! String) == "Video" {
print("video feed", indexPath.row)
cell.imageView?.layer.borderColor = UIColor.black.cgColor
cell.layer.borderWidth = 1
let imagerView = UIImageView()
imagerView.layer.cornerRadius = 1
imagerView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
imagerView.image = videoDictionary[indexPath.row]
// let vidUIView = UIView()
// vidUIView.tag = indexPath.row
let asf = UITapGestureRecognizer(target: self, action: #selector(ProfileController.playVid2(gestureRecognizer:)))
asf.numberOfTapsRequired = 2
// imagerView.addGestureRecognizer(asf)
let adsf = UITapGestureRecognizer(target: self, action: #selector(ProfileController.playVid(gestureRecognizer:)))
adsf.numberOfTapsRequired = 1
adsf.require(toFail: asf)
// imagerView.addGestureRecognizer(adsf)
cell.contentView.addGestureRecognizer(asf)
cell.contentView.addGestureRecognizer(adsf)
cell.contentView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
cell.contentView.addSubview(imagerView)
//cell.contentView.addSubview(vidUIView)
if indexPath.row == tableFeedCount - 1 && lockoutFeed != true && tableFeedCount == self.allDictionary.count && videoFeedCount == videoDictionary.count{
let dictionary = self.allDictionary[indexPath.row]
let date = dictionary?["date"] as! Double
let date2 = date*100000
let date3 = pow(10,16) - date2
let date4 = String(format: "%.0f", date3)
setUpFeed(starting: date4, queryLimit: UInt(11))
}
}
It's unclear if that code is in a view controller or in a UITableViewCell subclass. In any case, you will want to use a UITableViewCell subclass for your cells and do cleanup tasks in prepareForReuse:
override func prepareForReuse() {
super.prepareForReuse()
imagerView.image = nil
}
This will involve removing any data from the cell that you don't want carried over into the cell when it is reused. Clearing images from image views, hiding views that won't be shown for all cell types, etc.
Another solution would be to have multiple cell classes and load the appropriate cell class based on the data type it is responsible for displaying. This will simplify some of the code above and may help to prevent reuse, but it will require a significant refactor by the looks of things.
I have a UIView within the cell of a UITableView. My cellForRowAtIndexPath rounds that view. When I open the viewcontroller and see the table, all the visible views are rounded. However, when I scroll down, the first new cell to appear does not have a rounded view. How do I fix it?
My cellForRowAtIndex looks like this:
let cell = tableView.dequeueReusableCell(withIdentifier: "RepeatingCell", for: indexPath) as! CustomTableViewCell
cell.delegate = self
tableView.contentInset = UIEdgeInsetsMake(10, 0, 0, 0)
if (indexPath as NSIndexPath).row < tableListInfo_Context.count {
let task = tableListInfo_Context[(indexPath as NSIndexPath).row
let accState = task.value(forKey: "state") as? String
//Removed assigning labels their text
let mainView = cell.mainView
mainView.isHidden = false
let circleView = cell.viewToRound
circleView?.isHidden = false
circleView?.layer.cornerRadius = (circleView?.frame.size.width)!/2
circleView?.layer.masksToBounds = true
cell.layoutMargins = UIEdgeInsetsMake(0, 1000, 0, 1000)
} else {
//My last cell hides several views to reveal a view under them
//If I comment this one line out, I get the not-rounded problem only once and it does not show up again even if I continue scrolling up / down
let mainView = cell.mainView
mainView.isHidden = true
let circleView = cell.viewToRound
circleView?.isHidden = true
}
I understand that UITableViews recycle cells and I think that's likely causing me problems. I think it's related to that last cell where I hide views.
In a list of 20 cells, sometimes a non-rounded view shows up as the first to scroll on screen, sometimes the second. As I scroll up/down, randomly a view isn't rounded! I know there's a reason/pattern, but I don't know what.
I also tried adding the rounding code to willDisplayCell:
let circleView = myCell.mainCircle
circleView?.layer.cornerRadius = (circleView?.frame.size.width)!/2
circleView?.layer.masksToBounds = true
However, that did not solve it. How inconsistent this is is very frustrating. Any help would be appreciated.
FULL CODE AS REQUESTED BY DUNCAN:
func buildCell_RepeatableCell (indexPath: IndexPath) -> CustomTableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RepeatingCell", for: indexPath) as! CustomTableViewCell
cell.delegate = self
tableToSV_Left.constant = 10
tableToSV_Right.constant = 10
tableView.contentInset = UIEdgeInsetsMake(10, 0, 0, 0)
if (indexPath as NSIndexPath).row < curLifeList_Context.count {
resetDataCell_ToDefaultLaylout(cell: cell, hideExpand: true)
let task = curLifeList_Context[(indexPath as NSIndexPath).row]
let accState = task.value(forKey: "state") as? String
cell.nameLabel!.text = task.value(forKey: "name") as? String
cell.descLabel!.text = task.value(forKey: "desc") as? String
let redTrashIcon = UIImage(named: "trash")
let maskedIcon = redTrashIcon?.maskWithColor(color: .red)
cell.row5_LeftBtnImg?.image = maskedIcon
let doneGreen = UIColor(colorLiteralRed: 83/255, green: 223/255, blue: 56/225, alpha: 0.9)
let greenCheck = UIImage(named: "check_Green")
let maskedCheck = greenCheck?.maskWithColor(color: doneGreen)
cell.row5_RightBtnImg?.image = maskedCheck
roundQtyCircle(view: cell.mainCircle)
if accState == "Selected" {
cell.circleLine.backgroundColor = doneGreen
cell.mainCircle.borderColor = doneGreen
cell.hdrCrossOutLine.isHidden = false
cell.row5_RightBtnImg.alpha = 0.5
} else {
cell.circleLine.backgroundColor = UIColor(colorLiteralRed: 211/255, green: 211/255, blue: 211/255, alpha: 0.9)
cell.mainCircle.borderColor = UIColor(colorLiteralRed: 211/255, green: 211/255, blue: 211/255, alpha: 0.9)
cell.hdrCrossOutLine.isHidden = true
cell.row5_RightBtnImg.alpha = 1.0
}
cell.dataHdr_Left!.text = doneColon_lczd
cell.dataHdr_Right!.text = lastDoneColon_lczd
cell.dataVal_Left!.text = "0"
cell.dataVal_Right!.text = "-"
if let lastCompDate = task.value(forKey: "lastCompleted") as? Date {
cell.dataVal_Left!.text = "\(task.value(forKey: "timesCompleted") as! Int)"
if NSCalendar.current.isDateInToday(lastCompDate) {
cell.dataVal_Right!.text = "Today"
cell.dataBotDtl_Right.text = ""
} else {
let secondsUntilChange = (lastCompDate.seconds(from: now)) * -1
print("Seconds ago \(secondsUntilChange)")
var timeAgo = getDateString(secondsUntilChange, resetDate: lastCompDate)
timeAgo.remove(at: timeAgo.startIndex)
cell.dataVal_Right!.text = timeAgo
}
}
cell.layoutMargins = UIEdgeInsetsMake(0, 1000, 0, 1000)
} else {
buildAddNew_ForRepeatableCell(cell: cell)
}
return cell
}
func resetDataCell_ToDefaultLaylout (cell: CustomTableViewCell, hideExpand: Bool) {
cell.addnewBtn.isHidden = true
cell.nameLabel.isHidden = false
cell.dataHdr_Left.isHidden = false
cell.dataHdr_Right.isHidden = false
cell.dataTopDtl_Right.isHidden = false
cell.dataBotDtl_Right.isHidden = false
cell.mainBox.isHidden = false
}
func buildAddNew_ForRepeatableCell (cell: CustomTableViewCell) {
cell.addnewBtn.isHidden = false
cell.descLabel.text = addNew_lczd //For editor
cell.mainBox.isHidden = true
cell.layoutMargins = UIEdgeInsetsMake(0, 1000, 0, 1000)
cell.container.layoutIfNeeded()
}
Instead of setting layer properties of the view in cellForRowAtIndexPath, set them in your CustomTableViewCell class. You can set them in awakeFromNib Method.
In short move your below code to awakeFromNib.
let circleView = cell.viewToRound
circleView?.layer.cornerRadius = (circleView?.frame.size.width)!/2
circleView?.layer.masksToBounds = true
The sudo code could be something like this:
awakeFromNib(){
self.viewToRound?.layer.cornerRadius = (viewToRound?.frame.size.width)!/2
viewToRound?.layer.masksToBounds = true
}
#Adeel already told you the problem and the solution in his comment.
You always need to fully configure your cells in every case. Remember that when you get a recycled cell, it might be in any possible leftover state.
In your case, the key bit is:
if (indexPath as NSIndexPath).row < tableListInfo_Context.count {
//Configure cells that are not the last cell
} else {
//Configure cells the last cell
mainView.isHidden = true
}
You hide mainView in the case where you're configuring the last cell, but don't un-hide it if it's not the last cell. So, if you configure the last cell, scroll it off-screen, then scroll back towards the top of the screen, that recycled cell will get reused for an indexPath other than the last one, and it's mainView will never get un-hidden.
if (indexPath as NSIndexPath).row < tableListInfo_Context.count {
//Configure cells that are not the last cell
//-----------------------------
// This is what you are missing
mainView.isHidden = false
//-----------------------------
} else {
//Configure cells the last cell
mainView.isHidden = true
}
#VishalSonawane's answer is good, but to make that work you should use 2 different identifiers, one for all cells but the last one, and a different identifier, with a cell pre-configured with mainView hidden, for the last cell. That way you won't get a recycled last cell and try to use it for one of the other positions in your table view.
Try this, it will work.
override func awakeFromNib() {
super.awakeFromNib()
self.viewToRound?.layer.cornerRadius = (viewToRound?.frame.size.width)!/2
viewToRound?.layer.masksToBounds = true
}
override func prepareForReuse() {
super.prepareForReuse()
self.viewToRound?.layer.cornerRadius = (viewToRound?.frame.size.width)!/2
viewToRound?.layer.masksToBounds = true
}
I did following code to add UIView and UIButton as tags inside UIScrollView. Everything is working fine to append data into UIScrollView. Problem is how to remove UIView & UIButton inside UIScrollView. I did to remove but it does not disappear from UI. Please help me how to do.
Here is to create UIView & UIButton as tags
var xOffset: CGFloat = 0;
var i = 0;
for location in locationNameStrs {
let myString: NSString = location as NSString
let size: CGSize = myString.sizeWithAttributes([NSFontAttributeName: UIFont(name: "HelveticaNeue", size: 13)!])
outletView = UIView(frame: CGRectMake(xOffset, 10, size.width + 40, 40))
outletView.tag = i
outletStrs = UIButton(frame: CGRectMake(0, 5, outletView.frame.size.width, 25))
outletStrs.setTitle(location, forState: .Normal)
outletStrs.titleLabel?.textAlignment = NSTextAlignment.Center
outletStrs.backgroundColor = UIColor(red:0.00, green:0.45, blue:0.74, alpha:1.0)
outletStrs.layer.cornerRadius = 12.5
outletStrs.tag = i
outletStrs.addTarget(self, action: #selector(self.removeTags(_:)), forControlEvents: UIControlEvents.TouchUpInside)
outletStrs.titleLabel?.font = UIFont(name: "HelveticaNeue", size: 13)!
let closeImg = UIImageView (frame: CGRectMake(outletStrs.frame.size.width - 30, 0, 25, 25))
closeImg.image = UIImage(named: "close")
closeImg.contentMode = UIViewContentMode.Right
outletStrs.addSubview(closeImg)
outletView.addSubview(outletStrs)
tagScrollView.addSubview(outletView)
xOffset = xOffset + size.width + 50
i = i + 1
}
tagScrollView.contentSize = CGSizeMake(xOffset + 50, 50)
Here is to remove, but problem is those not disappear from UI
func removeTags(sender: UIButton) {
let ok = UIAlertAction(title: "OK", style: .Default) { (action:UIAlertAction!) in
if self.locationNameStrs.contains(self.locationNameStrs[sender.tag]) {
self.locationNameStrs.removeAtIndex(sender.tag)
self.outletView.removeFromSuperview()
self.outletStrs.removeFromSuperview()
self.closeImg.removeFromSuperview()
self.addButton.removeFromSuperview()
self.displayOutletTags()
}
}
}
You are not using the alert API correctly. You're leaving out the essential piece that gets it on the screen -- the View Controller itself. You need:
func removeTags(sender: UIButton) {
let alertBox = UIAlertController(title: "Removing tags", message: "I will now remove some tags.", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "OK", style: .Default) { (action:UIAlertAction!) in
guard sender.tag < self.locationNameStrs.count else {
print("Invalid tag index \(sender.tag)!")
return
}
self.locationNameStrs.removeAtIndex(sender.tag)
self.outletView.removeFromSuperview()
self.dislayOutletTags()
}
alertBox.addAction(okAction)
self.presentViewController(alertBox, animated: true, completion: nil)
}
OR
without the Alert, since it seems you don't want that:
func removeTags(sender: UIButton) {
guard sender.tag < self.locationNameStrs.count else {
print("Invalid tag index \(sender.tag)!")
return
}
self.locationNameStrs.removeAtIndex(sender.tag)
self.outletView.removeFromSuperview()
self.dislayOutletTags()
}
You should not be iterating through the scroll view to remove every view you find. This is fragile & awkward design. You're already keeping track of the view added, so remove it by name.
Your isKindOfClass() in your solution makes no sense, because by definition a view's subviews are all subclasses of UIView.
Again, your if statement makes no sense, since you're looking at an item in the array, and asking if that very array contains it.
if self.locationNameStrs.contains(self.locationNameStrs[sender.tag]) {
self.locationNameStrs.removeAtIndex(sender.tag)
for view in self.tagScrollView.subviews {
if view.isKindOfClass(UIView) {
view.removeFromSuperview()
}
}
self.displayOutletTags()
}
Above coding fixed my request.
I have a weird issue that I just found out when I re-installed and launched my project first time on Simulator
My main ViewController has a collection view that will show a list of recipes. After a recipe is added and navigated back to this screen, the list will reflect the update.
There is also a ScrollView that appears when recipe.count > 0 with subview containing buttons (to filter list by category). The scrollview reflect the update on the recipes but it won't work on the very first launch in Simulator.
I've tried reloading collectionview, fetching recipe data on viewDidAppear, viewWillAppear but no luck with the first-time launch.
How can I make sure the first app launch experience is the same with the subsequent launches? Is there any known issue with first-time launch on Simulator that I should know about?
Here is the code that creates buttons and add to ScrollView.
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
fetchRecipe()
collection.reloadData()
if recipes.count == 0 {
categoryScrollView.hidden = true
categoryScrollViewHeight.constant = 0
} else {
populateCategoryScrollView()
}
}
func populateCategoryScrollView() {
//Create category sort buttons based on fetched category.name and add to scrollview
if recipes.count > 0 {
var categories: [String] = []
for recipe in recipes {
if let value = recipe.category {
let category = value as! RecipeCategory
categories.append(category.name!)
}
}
var distinctCategories = Array(Set(categories))
var widthStack = 0
if distinctCategories.count != 0 {
for subView in categoryScrollView.subviews {
subView.removeFromSuperview()
}
for i in 0..<distinctCategories.count {
//Pilot button creation to get width
let frame1 = CGRect(x: 0, y: 6, width: 80, height: 40 )
let button = UIButton(frame: frame1)
button.setTitle("\(distinctCategories[i])", forState: .Normal)
button.sizeToFit()
let buttonWidth = Int(button.frame.size.width)
var frame2: CGRect
if i == 0 {
frame2 = CGRect(x: 10, y: 6, width: buttonWidth+20, height: 30 )
} else {
frame2 = CGRect(x: 10 + widthStack, y: 6, width: buttonWidth+20, height: 30 )
}
widthStack += buttonWidth+32
let button1 = UIButton(frame: frame2)
let attributedTitle = NSAttributedString(string: "\(distinctCategories[i])".uppercaseString, attributes: [NSKernAttributeName: 1.0, NSForegroundColorAttributeName: UIColor.blackColor()])
button1.setAttributedTitle(attributedTitle, forState: .Normal)
button1.titleLabel!.font = UIFont(name: "HelveticaNeue", size: 13.0)
button1.layer.borderWidth = 2.0
button1.layer.borderColor = UIColor.blackColor().CGColor
button1.backgroundColor = UIColor.whiteColor()
button1.addTarget(self, action: "filterByCategory:", forControlEvents: UIControlEvents.TouchUpInside)
self.categoryScrollView.addSubview(button1)
}
}
}
}
The first time you enter the application, the recipes.count is 0, so you are hiding the scroll view by the constraint categoryScrollViewHeight.constant = 0. So next time you create a new recipe, the scroll view is still with a zero height. That's why you didn't see the scroll on first time launch.