show badge on bar button item with action - ios

I have a bar button item on my view controller which is showing a popover view, and I have an extension to show badges on any button,
I tried to show the badges on the icon but it shows me another view, and I want to show the badges on my bar button item,
I tried this code
func addBadge(itemvalue: String) {
let bagButton = BadgeButton()
bagButton.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
bagButton.tintColor = UIColor.darkGray
bagButton.setImage(UIImage(named: "comment")?.withRenderingMode(.alwaysTemplate), for: .normal)
bagButton.badgeEdgeInsets = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 15)
bagButton.badge = itemvalue
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: bagButton)
}
my popover button code
#IBAction func showPopoverButtonAction(_ sender: Any) {
//get the button frame
/* 1 */
let button = sender as? UIButton
let buttonFrame = button?.frame ?? CGRect.init(x: -20, y: -320, width: 200, height: 400)
/* 2 */
//Configure the presentation controller
guard let popoverContentController = self.storyboard?.instantiateViewController(withIdentifier: "PopOverViewController") as? PopOverViewController else { return }
popoverContentController.modalPresentationStyle = .popover
popoverContentController.dpostID = self.postIdm
popoverContentController.dpostTitle = self.postTitlem
popoverContentController.duserPhone = self.muserPhone
popoverContentController.delegate = self
/* 3 */
if let popoverPresentationController = popoverContentController.popoverPresentationController {
popoverPresentationController.permittedArrowDirections = .up
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = buttonFrame
popoverPresentationController.delegate = self
// if let popoverController = popoverContentController {
//
// }
present(popoverContentController, animated: true, completion: nil)
}
}
currently it is showing like this!
enter image description here
but I want the badges to be on my bar button not new button!
to clarify: the new bar button with badge is generated by the code in the question, and the comment button is mybutton which I want to show the badges on.
popover button is the button that I want to show the badges on instead of the generated button from the code

Related

Assign tags for dynamic UIButtons

I found this example of a dynamic view of UIButtons at: http://helpmecodeswift.com/advanced-functions/generating-uibuttons-loop
I inserted this code into my app but unfortunately I can't find a way to set a tag for each buttons.
My target is to know which button is tapped, count the amount of clicks for each button and save this information into my DB.
override func viewDidLoad() {
super.viewDidLoad()
var arrayOfVillains = ["santa", "bugs", "superman", "batman"]
var buttonY: CGFloat = 20
for villain in arrayOfVillains {
let villainButton = UIButton(frame: CGRect(x: 50, y: buttonY, width: 250, height: 30))
buttonY = buttonY + 50 // we are going to space these UIButtons 50px apart
villainButton.layer.cornerRadius = 10 // get some fancy pantsy rounding
villainButton.backgroundColor = UIColor.darkGrayColor()
villainButton.setTitle("Button for Villain: \(villain)", forState: UIControlState.Normal) // We are going to use the item name as the Button Title here.
villainButton.titleLabel?.text = "\(villain)"
villainButton.addTarget(self, action: "villainButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(villainButton) // myView in this case is the view you want these buttons added
}
}
func villainButtonPressed(sender:UIButton!) {
if sender.titleLabel?.text != nil {
println("You have chosen Villain: \(sender.titleLabel?.text)")
} else {
println("Nowhere to go :/")
}
}
}
So how it is possible to set and get the tag for/from each button in code (in this example)?
Thank you in advance!
You can use enumerated array to access indexes of the current item in iteration and use that as a tag:
override func viewDidLoad() {
super.viewDidLoad()
var arrayOfVillains = ["santa", "bugs", "superman", "batman"]
var buttonY: CGFloat = 20
for (index, villain) in arrayOfVillains.enumerated() {
let villainButton = UIButton(frame: CGRect(x: 50, y: buttonY, width: 250, height: 30))
buttonY = buttonY + 50 // we are going to space these UIButtons 50px apart
// set the tag to current index
villainButton.tag = index
villainButton.layer.cornerRadius = 10 // get some fancy pantsy rounding
villainButton.backgroundColor = UIColor.darkGrayColor()
villainButton.setTitle("Button for Villain: \(villain)", forState: UIControlState.Normal) // We are going to use the item name as the Button Title here.
villainButton.titleLabel?.text = "\(villain)"
villainButton.addTarget(self, action: "villainButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(villainButton) // myView in this case is the view you want these buttons added
}
}
}
#objc func villainButtonPressed(sender:UIButton!) {
// tag of pressed button
print(">>> you pressed button with tag: \(sender.tag)")
if sender.titleLabel?.text != nil {
println("You have chosen Villain: \(sender.titleLabel?.text)")
} else {
println("Nowhere to go :/")
}
}
You should use an integer-based for loop for this.
for i in 0 ..< arrayOfVillains.count {
let villain = arrayOfVillains[i]
let villainButton = UIButton(frame: CGRect(x: 50, y: buttonY, width: 250, height: 30))
villainButton.tag = i
}
You can do as follows,
var buttonTag = 1
for villain in arrayOfVillains {
let villainButton = UIButton(frame: CGRect(x: 50, y: buttonY, width: 250, height: 30))
villainButton.tag = buttonTag
buttonTag += 1
}

Swift: how to make search bar animate when focused? Used to work?

Ok, I feel as though a few versions of Xcode ago this was the default, and I have it working in a past project, just do not know why I cant get this search bar animation to happen with this search bar now in Xcode 9.
What I want to happen is when the search bar ISNT focused, the placeholder text is centered:
Then when its tapped and becomes first responder, the text is left aligned (the transition between the two seems to animate automatically):
I swear search bars used to do this without any customization. How can I achieve this? Right now in my tableview custom header I set up my search bar programmatically like this:
searchBar.placeholder = "Find an Episode."
searchBar.backgroundColor = UIColor.clear
searchBar.searchBarStyle = .minimal
searchBar.layer.shadowOpacity = 0.0
searchBar.barTintColor = thirdColorStr
searchBar.tintColor = thirdColorStr
searchBar.frame = CGRect(x: 0, y: 0, width: self.bounds.width, height: screenSize.height * (40/screenSize.height))
self.addSubview(searchBar)
// searchBar.center = CGPoint(x: self.bounds.width/2, y: (searchBar.bounds.height/2))
searchBar.center = CGPoint(x: self.bounds.width/2, y: (searchBar.bounds.height)*0.8)
searchBar.delegate = listVC
for subView in searchBar.subviews {
for subViewOne in subView.subviews {
if let textField = subViewOne as? UITextField {
subViewOne.backgroundColor = secondColorStr
//print("HEREE:", textField.bounds.width/screenSize.width)
//use the code below if you want to change the color of placeholder
if let t = textField.value(forKey: "placeholderLabel") as? UILabel
{
t.textColor = thirdColorStr
t.font = iphoneFontThin
t.tintColor = thirdColorStr
t.backgroundColor = UIColor.clear
}
// if let clearButton = textField.value(forKey: "_clearButton") as? UIButton {
// // Create a template copy of the original button image
// let img = UIImage(named: "clear")
// clearButton.setImage(img, for: .normal)
//
// // Finally, set the image color
// //clearButton.tintColor = .red
// }
if let t = searchBar.value(forKey: "searchField") as? UITextField
{
t.textColor = barColorStr
t.font = iphoneFontThin
t.backgroundColor = secondColorStr
Then
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
self.searchBar.showsCancelButton = true
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
//searchBar.showsCancelButton = true
resetCategory(newCat: overallCategory)
searchBar.text = ""
searchBar.resignFirstResponder() //kills keyboard
}
I cant find any differences between the code that produces and animation and the one above that does not.

Is it possible to pass a gesture from the current view controller to popover viewcontroller

In my presented ViewController i have a button where on the long press I present a ViewController with modalPresentationStyle popover. The thing is I would like to pass the same touch gesture to the popover so that I don't have to make another touch event to make things work. Is it possible in my current situation or do u suggest work around?
interactionViewController?.delegate = self
interactionViewController?.indexpathRow = indexPathRow
interactionViewController?.modalPresentationStyle = .popover
interactionViewController?.popoverPresentationController?.backgroundColor = .clear
interactionViewController?.preferredContentSize = CGSize(width: 320, height: 220)
interactionViewController?.view.layer.cornerRadius = 25
let popoverMenuViewController = interactionViewController?.popoverPresentationController
popoverMenuViewController?.permittedArrowDirections = UIPopoverArrowDirection.init(rawValue: 0)
popoverMenuViewController?.sourceView = sender as? UIView
popoverMenuViewController?.popoverBackgroundViewClass = PopupControllerBackgroundView.self
popoverMenuViewController?.sourceRect = CGRect(x: 0,y:0,width: 1,height: 1)
popoverMenuViewController?.delegate = self
self.present(self.interactionViewController!, animated: false, completion: { [weak self] in
self?.interactionViewController?.view.superview?.layer.cornerRadius = 40
self?.interactionViewController?.view.superview?.backgroundColor = .clear
})

removeFromSuperview() not always working

I declare a UIView variable called var progressBar : UIView?
and I show it or hide the view with this function
func showProgressBar(showBar: Bool){
if showBar{
let viewHeight = view.frame.size.height
progressBar = Bundle.main.loadNibNamed("progressBar", owner: nil, options: nil)?.first as? UIView
progressBar?.frame = CGRect(x: 0, y: viewHeight - 80 , width: self.view.frame.width, height: 80)
if let bar = progressBar{
self.view.addSubview(bar)
}
}else{
DispatchQueue.main.async() {
self.progressBar?.removeFromSuperview()
}
}
Sometimes when I navigate a bit between the views I am not able to hide the progress bar, even when self.progressBar?.removeFromSuperview() is executed. It looks to me like if the view has lost the reference to the old progress bar... Do you have an idea about the problem and how I could fix it?
If you're calling showProgressBar twice, it's not validated that there's not a bar already, so you could be adding a second one and losing a reference to the first one. Thus, when you remove it, it just removes the second one and doesn't work.
If you only want to show and hide your progressBar why don't you use self.progressBar.hidden = true/false? By doing so, you can just create your progressBar once and removeFromSuperview once you don't use it anymore.
func showProgressBar(showBar: Bool){
if showBar {
// Check this first
if progressBar == nil {
let viewHeight = view.frame.size.height
progressBar = Bundle.main.loadNibNamed("progressBar", owner: nil, options: nil)?.first as? UIView
progressBar?.frame = CGRect(x: 0, y: viewHeight - 80 , width: self.view.frame.width, height: 80)
if let bar = progressBar {
self.view.addSubview(bar)
}
}
} else {
DispatchQueue.main.async() {
self.progressBar?.removeFromSuperview()
}
}
}

ViewController won't reload properly on first Simulator launch

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.

Resources