I have a list of category add I created buttons for each category in a scroll view
and a last button is ALL button for all products. But some how it didn't have any action I added.
this is my code
First I make a function to create buttons to add to view
func catButtonView(buttonSize:CGSize) -> UIView {
let buttonView = UIView()
buttonView.backgroundColor = UIColor(colorLiteralRed: 1, green: 1, blue: 1, alpha: 0)
buttonView.frame.origin = CGPoint(x: 0,y: 0)
let padding = CGSize(width:0, height:0)
buttonView.frame.size.width = (buttonSize.width + padding.width) * CGFloat(categories.count)
buttonView.frame.size.height = (buttonSize.height + 2.0 * padding.height )
//add buttons to the view
var buttonPosition = CGPoint(x:padding.width * 0.5, y:padding.height)
let buttonIncrement = buttonSize.width + padding.width
let hueIncrement = 1.0 / CGFloat(categories.count)
var newHue = hueIncrement
for i in 0...(categories.count) {
let button = UIButton.init(type: .custom) as UIButton
button.frame.size = buttonSize
button.frame.origin = buttonPosition
button.setBackgroundImage(R.image.button(), for: .normal)
button.setBackgroundImage(R.image.button_selected(), for: .selected)
if(i==categories.count) {
button.setTitle("ALL", for: .normal)
} else {
button.setTitle(categories[i].name, for: .normal)
}
button.setTitleColor(UIColor.white, for: .normal)
buttonPosition.x = buttonPosition.x + buttonIncrement
newHue = newHue + hueIncrement
button.tag = i+1
button.addTarget(self, action: #selector(catButtonPressed(sender:)), for: .touchUpInside)
buttonView.addSubview(button)
}
return buttonView
}
this is action func
func catButtonPressed(sender:UIButton){
print(sender.tag)
if(self.selectedCat != sender.tag-1) {
let lastBtn = catScrollView.viewWithTag(selectedCat+1) as? UIButton
lastBtn?.setBackgroundImage(R.image.button(), for: .normal)
self.selectedCat = sender.tag-1
self.itemsCollection.reloadData()
sender.setBackgroundImage(R.image.button_selected(), for: .normal)
}
}
then add to scroll view
let catScrollingView = catButtonView(buttonSize: CGSize(width: 200.0, height:50.0))
catScrollView.contentSize = catScrollingView.frame.size
catScrollView.subviews.forEach({ $0.removeFromSuperview() })
catScrollView.addSubview(catScrollingView)
catScrollView.showsHorizontalScrollIndicator = true
catScrollView.indicatorStyle = .default
self.itemsCollection.reloadData()
Anyone know what I missed?
It is because the if statement in your catButtonPressed function is false with the last button's tag, which makes the code inside never be executed.
Let's say you have 5 categories so your categories.count = 5. So your self.selectedCat ranges from 0 to 4. In your for i in 0...(categories.count) the last button's tag is button.tag = 5
Now in your catButtonPressed function. If the last button is the last category, then your self.selectedCat will be 4 and sender.tag will be 5
func catButtonPressed(sender:UIButton){
print(sender.tag)
if(4 != 5-1) {
// Any code in here will never be executed because 4 != 4 is false
}
}
Related
There is a UIImage inside the MainViewController as seen in the picture. There is also a button in TabBarViewController. When I press the button, I want the impulse animation I wrote for the UIView to start and stop.When i click to play button animation is not started. How can I do this?
Thanks.
enter image description here
Here is my code;
class MainViewObject: UIView {
//Center Image View Container
lazy var centerContainerView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.layer.cornerRadius = 113
view.backgroundColor = Colors.lightOrangeColor
return view
}()
}
class TabbarViewController: UITabBarController {
var object: MainViewObject!
//Create Play Button
let middleButton: UIButton = {
let btn = UIButton(frame: CGRect(x: (UIScreen.main.bounds.width / 2) - 32, y: -8, width: 65, height: 65))
btn.setImage(UIImage(named: "play"), for: UIControl.State.normal)
btn.layer.shadowColor = UIColor.black.cgColor
btn.layer.shadowOpacity = 0.1
btn.layer.shadowOffset = CGSize(width: 4, height: 4)
btn.backgroundColor = Colors.mainColor
btn.layer.cornerRadius = 32
btn.tintColor = UIColor.clear
btn .addTarget(self, action:#selector(menuButtonAction), for: .touchUpInside
return btn
}()
//Play Pause Button Function
#objc func menuButtonAction(sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
middleButton.setImage(UIImage(named: "pause"), for: UIControl.State.normal)
playRadio()
pulseAnimationStart()
}else{
middleButton.setImage(UIImage(named: "play"), for: UIControl.State.normal)
player!.pause()
pulseAnimationStop()
}
}
}
extension TabbarViewController {
//Main Page Main Image Pulse Animation Start
func pulseAnimationStart() {
let fadingAnimation = CABasicAnimation(keyPath: "opacity")
fadingAnimation.fromValue = 1
fadingAnimation.toValue = 0
let expandingAnimation = CABasicAnimation(keyPath: "transform.scale")
expandingAnimation.fromValue = 1
expandingAnimation.toValue = 1.1
let animationGroup = CAAnimationGroup()
animationGroup.animations = [expandingAnimation,
fadingAnimation]
animationGroup.duration = 1.5
animationGroup.repeatCount = .infinity
self.object.centerContainerView.layer.add(animationGroup, forKey: "pulse")
}
//Main Page Main Image Pulse Animation Stop
func pulseAnimationStop() {
UIView.animate(withDuration: 0.0) {
self.object.centerContainerView.layer.removeAllAnimations()
}
}
}
I have create 2 buttons using loop. Also I have addTarget for them in same loop. But target for button at index 0 is never called, while it is called everytime for button at index 1. Here is my code
let buttonTitles = ["GIFs","Stickers"]
let enumberatedTitles = buttonTitles.enumerated()
var originX: CGFloat = 2.5
var buttonWidth = 100
self.containerView.frame.size.width = CGFloat(buttonTitles.count) * buttonWidth + 5
self.containerView.frame.size.height = 50
self.containerView.center.x = self.frame.width/2
self.containerView.center.y = self.frame.height/2
for(index,item) in enumberatedTitles {
var button = UIButton()
button.setTitle(item, for: .normal)
button.setTitleColor(.white, for: .normal)
button.backgroundColor = .clear
button.frame.origin.x = originX
button.frame.origin.y = 2.5
button.frame.size.width = buttonWidth
button.frame.size.height = 45
button.tag = index
button.accessibilityHint = item
button.addTarget(self, action: #selector(buttonPressed(sender:)), for: .touchUpInside)
self.containerView.addSubview(button)
originX += longestLabelWidth
}
Target for button
#objc private func buttonPressed(sender: UIButton) {
if let touchedButton = self.containerView.subviews.first(where: {
$0.tag == sender.tag
}) {
self.selectedView.frame = touchedButton.frame
}
}
I'm creating voice collection app separated 4 genres(I control genres by using switch statement).You can choose one in four genres in segmentedcontroll and change buttons shown above segmentedcontroll. And I'm creating Buttons by using double for statement.
When changing genres and updating Button I coded like
loadView()
viewDidLoad()
to update buttons.But that update banner ads(disappear and appear again)
as well.How can I stop updating banner ads?.Sorry for my poor English and messy code.Thank you.
I used addsubView but which didn't work.
//this is a part of whole code
import UIKit
import AVFoundation
import GoogleMobileAds
class ViewController: UIViewController{
var spaceForiPhoneX = 0
var fontOfText = 9
var adView:UIWindow! = UIWindow()
var admobView:GADBannerView!
var window:UIWindow!
// true:テスト
let AdMobTest:Bool = true
var player = AVAudioPlayer()
var buttonArray:[UIButton]!
var currentArray:[String] = []
var first = true
override var prefersStatusBarHidden: Bool{
return true
}
lazy var buttonSegmentedControl: UISegmentedControl = {
let sc = UISegmentedControl(items: ["outou","outou2","bougen","meigen"])
sc.translatesAutoresizingMaskIntoConstraints = false
sc.tintColor = UIColor.white
sc.selectedSegmentIndex = 0
sc.addTarget(self, action: #selector(handleButtonsChange), for: .valueChanged)
return sc
}()
#objc func handlebuttonsChange(){
switch buttonSegmentedControl.selectedSegmentIndex {
case 0:
currentArray = outou
case 1:
currentArray = outou2
case 2:
currentArray = bougen
case 3:
currentArray = meigen
default:
print("not selected")
}
loadView()
viewDidLoad()
}
override func viewDidLoad() {
super.viewDidLoad()
if(first) {
currentArray = reloadViewController.outou
first = false
print("Google Mobile Ads SDK version: \(GADRequest.sdkVersion())")
var admobView = GADBannerView()
admobView = GADBannerView(adSize:kGADAdSizeBanner)
// iPhone X のポートレート決め打ちです
admobView.frame.origin = CGPoint(x:0, y:self.view.frame.size.height - admobView.frame.height + CGFloat(spaceForiPhoneX))
admobView.frame.size = CGSize(width: self.view.frame.width, height:admobView.frame.height)
admobView.adUnitID = TEST_ID
admobView.rootViewController = self
admobView.load(GADRequest())
navigationItem.titleView?.addSubview(admobView)
}
view.backgroundColor = UIColor(r: 61, g: 91, b: 151)
let numberOfrows = 6
let numberOfLines = 3
var count = 0
var buttonArray:[UIButton] = []
let sizeOfButton = view.frame.height / 10
let widthOfSpace = ((view.frame.width - sizeOfButton * 4) / 5 )
forloop : for row in 0 ... numberOfrows {
for line in 0 ... numberOfLines {
let button = UIButton(type: .custom)
button.backgroundColor = UIColor(r: 1, g: 101, b: 161)
button.setTitleColor(UIColor.white, for: .normal)
button.titleLabel?.numberOfLines = 0
button.setTitle(currentArray[row * 4 + line], for: .normal)
button.frame = CGRect(x: (widthOfSpace + sizeOfButton) * CGFloat(line) + widthOfSpace, y: view.frame.height / 9.3 * CGFloat(row) + 50, width: sizeOfButton ,height: sizeOfButton )
button.layer.cornerRadius = 10
button.layer.borderColor = UIColor.white.cgColor
button.layer.borderWidth = 1
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: CGFloat(fontOfText))
button.tag = row * 4 + line
button.addTarget(self, action: #selector(buttonPushed), for:.touchUpInside)
button.showsTouchWhenHighlighted = true
buttonArray.append(button)
count += 1
if (count == currentArray.count) {break forloop}
}
}
for button in buttonArray{
view.addSubview(button)
}
view.addSubview(buttonSegmentedControl)
setupbuttonSegmentedControl()
}
#objc func buttonPushed(button : UIButton){
let audioPath = Bundle.main.path(forResource: currentArray[button.tag], ofType: "mp3")
do {
try player = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath!))
player.play()
}catch{
print(error)
}
}
func setupbuttonSegmentedControl(){
buttonSegmentedControl.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
buttonSegmentedControl.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -90).isActive = true
buttonSegmentedControl.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -24).isActive = true
buttonSegmentedControl.heightAnchor.constraint(equalToConstant: 60).isActive = true
}
You should never call loadView and viewDidLoad by yourself. This is even mentioned in the documentation.
Extract the button update part from viewDidLoad to a separate method and call that method instead.
For example:
Declare an instance variable to store the buttons:
private var buttons: [UIButton] = []
And extract the update code into a method:
private func updateButtons() {
for buttons in buttons {
button.removeFromSuperview()
}
let numberOfrows = 6
let numberOfLines = 3
var count = 0
buttons = []
let sizeOfButton = view.frame.height / 10
let widthOfSpace = ((view.frame.width - sizeOfButton * 4) / 5 )
forloop : for row in 0 ... numberOfrows {
for line in 0 ... numberOfLines {
let button = UIButton(type: .custom)
button.backgroundColor = UIColor(r: 1, g: 101, b: 161)
button.setTitleColor(UIColor.white, for: .normal)
button.titleLabel?.numberOfLines = 0
button.setTitle(currentArray[row * 4 + line], for: .normal)
button.frame = CGRect(x: (widthOfSpace + sizeOfButton) * CGFloat(line) + widthOfSpace, y: view.frame.height / 9.3 * CGFloat(row) + 50, width: sizeOfButton ,height: sizeOfButton )
button.layer.cornerRadius = 10
button.layer.borderColor = UIColor.white.cgColor
button.layer.borderWidth = 1
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: CGFloat(fontOfText))
button.tag = row * 4 + line
button.addTarget(self, action: #selector(buttonPushed), for:.touchUpInside)
button.showsTouchWhenHighlighted = true
buttons.append(button)
count += 1
if (count == currentArray.count) {break forloop}
}
}
for button in buttons {
view.addSubview(button)
}
}
Call this method from both viewDidLoad and from handlebuttonsChange.
By the way, note that the code could be significantly simplified and ideally you should use UICollectionView instead.
I have the following buttons which are adding dynamically based on some condition. Now i need to change all added buttons behaviour as radio buttons. so that I can do some actions based on the selection..
var posX = 0
var posY = 0
if trim.contains("0"){
print("contaim 0")
let button1 = UIButton(frame: CGRect(x: posX, y: posY, width: 60, height: 20))
button1.setTitleColor(UIColor.blackColor(), forState: .Normal)
button1.setTitle("No", forState: .Normal)
button1.setImage(UIImage(named: "checkbox untick.png")!, forState: .Normal)
button1.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
myStackview.addSubview(button1)
posX = 60
}
if trim.contains("1") {
print("contaim 1")
let button2 = UIButton(frame: CGRect(x: posX, y: posY, width: 60, height: 20))
button2.setTitleColor(UIColor.blackColor(), forState: .Normal)
button2.setTitle("Less", forState: .Normal)
button2.setImage(UIImage(named: "checkbox untick.png")!, forState: .Normal)
button2.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
myStackview.addSubview(button2)
posX = posX + 60
}
if trim.contains("2"){
print("contaim 2")
let button3 = UIButton(frame: CGRect(x: posX, y: posY, width: 60, height: 20))
button3.setTitleColor(UIColor.blackColor(), forState: .Normal)
button3.setTitle("Half", forState: .Normal)
button3.setImage(UIImage(named: "checkbox untick.png")!, forState: .Normal)
button3.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
myStackview.addSubview(button3)
posX = posX + 60
}
I have set the buttonAction methods as below buts its not working
func buttonAction(sender: UIButton!) {
print("Button tapped")
sender.setImage(UIImage(named: "checkboxredtick.png")!, forState: .Normal)
}
let buttons = [UIButton]()
// create button1
let button1 = UIButton(frame: CGRect(x: posX, y: posY, width: 60, height: 20))
button1.setTitleColor(UIColor.blackColor(), forState: .Normal)
button1.setTitle("No", forState: .Normal)
button1.setImage(UIImage(named: "checkbox untick.png")!, forState: .Normal)
// if the selected button cannot be reclick again, you can use .Disabled state
button1.setImage(UIImage(named: "checkboxredtick.png")!, forState: .Selected)
button1.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
myStackview.addSubview(button1)
buttons.append(button1)
// create other buttons and add into buttons ...
func buttonAction(sender: UIButton!){
for button in buttons {
button.selected = false
}
sender.selected = true
// you may need to know which button to trigger some action
// let buttonIndex = buttons.indexOf(sender)
}
In case anyone finds this useful. Here is an example of how I use DLRadioButton library (https://github.com/DavydLiu/DLRadioButton) to create RadioButtons dynamically.
You can check a complete small project to show a working code in here https://github.com/omhack/DynamicRadioButtons
import UIKit
import DLRadioButton
//Delegate to manage the Polls
protocol QuestionsDialogDelegate : class{
func questionsAnswered(polls: [Poll])
}
class QuestionsDialog: UIViewController {
#IBOutlet weak var stackView: UIStackView!
#IBOutlet var rootView: UIView!
#IBOutlet weak var nestedView: UIView!
weak var delegate: QuestionsDialogDelegate?
var questions : [Question]!
var polls = [Poll]()
var serviceType : Int = 0
var indexView : Int = 0
override func viewDidLoad() {
super.viewDidLoad()
//setting the stack view properties
stackView.alignment = UIStackViewAlignment.leading
stackView.axis = .vertical
}
//this is where the heavy logic, to create the dynamic radio buttons takes place
func showQuestions(){
if(questions.count <= 1){
rootView.frame.size.height = 200
nestedView.frame.size.height = 200
}else{
rootView.frame.size.height = 400
nestedView.frame.size.height = 400
}
for question in questions{
var otherButtons : [DLRadioButton] = []
let frame1 = CGRect(x: self.view.frame.size.width / 2 - 131, y: 350, width: 262, height: 17);
//we create a base radio button to use it as an anchor view
let firstRadioButton = createRadioButton(frame: frame1, title: "", color: UIColor.purple);
let label = UILabel()
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 17.0)
label.textColor = UIColor.darkGray.withAlphaComponent(0.85)
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.25
label.frame = CGRect(x: 0, y: 0, width: 200, height: 30)
label.text = question.question
self.stackView.insertArrangedSubview(label, at: self.indexView)
self.indexView += 1
let poll = Poll()
poll.idQuestion = question.idQuestion
var i = 0;
for answer in question.answers{
let frame = CGRect(x: self.view.frame.size.width / 2 - 131, y: 380 + 30 * CGFloat(i), width: 300, height: 17);
let radioButton = createRadioButton(frame: frame, title: answer.answer! + " ", color: UIColor.purple)
radioButton.tag = answer.idAnswer
radioButton.params["poll"] = poll
otherButtons.append(radioButton)
self.stackView.insertArrangedSubview(radioButton, at: self.indexView)
i += 1;
self.indexView += 1
}
firstRadioButton.otherButtons = otherButtons
firstRadioButton.isHidden = true
firstRadioButton.otherButtons[1].isSelected = true
}
}
//Method to create a custom button
private func createRadioButton(frame : CGRect, title : String, color : UIColor) -> MyDLUIButton {
let radioButton = MyDLUIButton(frame: frame);
radioButton.titleLabel?.translatesAutoresizingMaskIntoConstraints = false
radioButton.titleLabel!.font = UIFont.systemFont(ofSize: 14);
radioButton.setTitle(title, for: []);
radioButton.setTitleColor(UIColor.darkGray, for: []);
radioButton.iconColor = color;
radioButton.indicatorColor = color;
radioButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left;
radioButton.addTarget(self, action: #selector(QuestionsDialog.selectedAnswer(_:)), for: UIControlEvents.touchUpInside)
self.view.addSubview(radioButton);
return radioButton;
}
#objc func selectedAnswer(_ sender: MyDLUIButton){
let poll = sender.params["poll"] as? Poll
poll?.idAnswer = sender.tag
if let row = self.polls.index(where: {$0.idQuestion == poll?.idQuestion}) {
self.polls[row] = poll!
}else{
self.polls.append(poll!)
}
print("polls size: \(self.polls.count)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewDidDisappear(_ animated: Bool) {
if(self.polls.count < self.questions.count){
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "questionsDialogDismissed"), object: nil)
}
}
#IBAction func requestService(_ sender: UIButton) {
delegate?.questionsAnswered(polls: self.polls)
}
}
class MyDLUIButton: DLRadioButton{
var params: Dictionary<String, Any>
override init(frame: CGRect) {
self.params = [:]
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
self.params = [:]
super.init(coder: aDecoder)
}
}
I would create a tag for every UIButton, then add your UIButton to be send to your ButtonAction:
button.tag = 0
button.addTarget(object, action: #selector(YourViewController.buttonAction(_:)),
forControlEvents: .TouchUpInside)
func buttonAction(sender: UIButton!) {
let selectedButton = sender as! UIButton
print(selectedButton.tag) // here stands the correct button which is pressed
}
You could also create an Array containing all Buttons, for example:
let myButtons = [UIButton]()
let button1 = UIButton()...
button1.tag = 0
myButtons.add(button1)
And now change it like this way:
myButtons[0].setImage(.....)
Where 0 is your first button (so with tag 0) // you should set your tags in the same order in which you append it to your myButtons Array.
This is my code
var button = [UIButton?](count:3, repeatedValue: UIButton())
for i in 0...2{
button[i]!.tag = i
button[i]!.frame = CGRectMake(CGFloat(i) *(collectionViewLove?.frame.width)!/3,0,(collectionViewLove?.frame.width)!/3, 30)
button[i]!.setTitle(titleForButtonsOneSelected[i], forState: .Normal)
button[i]!.titleLabel?.adjustsFontSizeToFitWidth = true
button[i]!.layer.borderWidth = 1.0
button[i]!.layer.borderColor = UIColor.blueColor().CGColor
button[i]!.backgroundColor = UIColor.clearColor()
button[i]!.setTitleColor(UIColor.blackColor(), forState: .Normal)
view.addSubview(button[i]!)
}
The problem is only the last button added to the view is getting shown. How do I show all the button objects in the view?
EDIT:
The frame values for UIButton I am getting
(0.0, 0.0, 106.666666666667, 30.0)
(106.666666666667, 0.0, 106.666666666667, 30.0)
(213.333333333333, 0.0, 106.666666666667, 30.0)
let buttons = Array(0...2).map { number -> UIButton in
let button = UIButton(frame: CGRectMake(CGFloat(number) * collectionViewLove!.frame.width / 3, 0, collectionViewLove!.frame.width / 3, 30))
button.tag = number
button.setTitle(titleForButtonsOneSelected[number], forState: .Normal)
buttontitleLabel?.adjustsFontSizeToFitWidth = true
button.layer.borderWidth = 1.0
button.layer.borderColor = UIColor.blueColor().CGColor
button.backgroundColor = UIColor.clearColor()
button.setTitleColor(UIColor.blackColor(), forState: .Normal)
view.addSubview(button)
return button
}
This way you have 3 different buttons in buttons. You can also customize the buttons right there as well.
Edit:
let buttons = Array(0...2).forEach {
let button = UIButton(frame: CGRectMake(CGFloat($0) * collectionViewLove!.frame.width / 3, 0, collectionViewLove!.frame.width / 3, 30))
button.tag = $0
button.setTitle(titleForButtonsOneSelected[$0], forState: .Normal)
buttontitleLabel?.adjustsFontSizeToFitWidth = true
button.layer.borderWidth = 1.0
button.layer.borderColor = UIColor.blueColor().CGColor
button.backgroundColor = UIColor.clearColor()
button.setTitleColor(UIColor.blackColor(), forState: .Normal)
view.addSubview(button)
}
It looks like button[i]!.frame = CGRectMake(CGFloat(i) *(collectionViewLove?.frame.width)!/3,0,(collectionViewLove?.frame.width)!/3, 30) is producing the same frame each time, so your buttons will be superimposed on each other. You need to have something dynamic in your call to have them be in different spots and visible.