Button Not Firing Event Inside ScrollView - ios

UIButtons inside scrollview are not firing event. I tried setting exclusiveTouch delaysTouchesEvent, but nothing helped.
class TestViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
var categoryArr = ["Jack","Mark","Down","Bill","Steve"]
var buttonColors = [UIColor.greenColor(), UIColor.blueColor(), UIColor.blackColor(), UIColor.cyanColor(), UIColor.magentaColor()]
override func viewDidLoad() {
super.viewDidLoad()
let scrollingView = colorButtonsView(CGSizeMake(150,scrollView.frame.size.height), buttonCount: 5)
scrollView.contentSize = scrollingView.frame.size
scrollView.addSubview(scrollingView)
scrollView.showsVerticalScrollIndicator = false
scrollView.delegate = self
scrollView.pagingEnabled = true
scrollView.indicatorStyle = .Default
scrollView.canCancelContentTouches = false
scrollView.delaysContentTouches = false
scrollView.exclusiveTouch = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func colorButtonsView(buttonSize:CGSize, buttonCount:Int) -> UIView {
let buttonView = UIView()
buttonView.frame.origin = CGPointMake(0,0)
let padding = CGSizeMake(10, 10)
buttonView.frame.size.width = (buttonSize.width + padding.width) * CGFloat(buttonCount)
var buttonPosition = CGPointMake(padding.width * 0.5, padding.height)
let buttonIncrement = buttonSize.width + padding.width
for i in 0...(buttonCount - 1) {
var button = UIButton.buttonWithType(.Custom) as! UIButton
button.frame.size = buttonSize
button.frame.origin = buttonPosition
buttonPosition.x = buttonPosition.x + buttonIncrement
button.setTitle(categoryArr[i], forState: UIControlState.Normal)
button.addTarget(self, action: "showTheNextButton:", forControlEvents: UIControlEvents.TouchUpInside)
button.backgroundColor = buttonColors[i]
buttonView.addSubview(button)
}
return buttonView
}
func showTheNextButton(sender:UIButton){
print("ok show the next button")
}
}
extension TestViewController:UIScrollViewDelegate{
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let index = round(scrollView.contentOffset.x / scrollView.frame.size.width)
print(index)
}
}

A UIButton will not accept touches if it lies outside the bounds of one of its superviews. Make sure all your views are the size and position you expect them to be

Please make the following changes:
self.scrollView.canCancelContentTouches = true
self.scrollView.delaysContentTouches = true
In your for-loop, move your let buttonView = UIView() to:
#IBOutlet weak var scrollView: UIScrollView!
var categoryArr = ["Jack","Mark","Down","Bill","Steve"]
var buttonColors = [UIColor.greenColor(), UIColor.blueColor(), UIColor.blackColor(), UIColor.cyanColor(), UIColor.magentaColor()]
let buttonView = UIView()
Then subsequently, change the following, again, in your for-loop:
Change this line: buttonView.frame.origin = CGPointMake(0,0) to
self.buttonView.frame = self.scrollView.bounds
self.buttonView.userInteractionEnabled = true
Addendum:
Comment this out: //self.scrollView.exclusiveTouch = true
I took the liberty of testing it; touches should get registered on the buttons and scrolling should also work horizontally. Enjoy.

Related

How do implement UIScrollView and UIPageControl Programmatically in Swift4?

Recently I want to implement the UI of Image and text slide show, because of my personal reasons: App pages are implemented by program code. I spent some time researching the usage of UIScrollView and UIPageControl, and found this link(How to create a Scroll View with a page control using swift?) is very informative, but the code is in My environment is not working, the SubView of UIScrollView has not been displayed correctly, and there is a problem with sliding to switch pages. I spent a lot of time searching for the answers to the questions, and I didn't find any valid information.
update my solution:
After some practice, the problem is solved, I will post the notes and solutions.
Just remember:
1、Your UIScrollView must have left (or leading) / top / width / height values.
2、The content elements of your UIScrollView need define the bounds of the contentSize-but they do so with the bottom & right (trailing) constraints.
3、The middle SubView of each UIScrollView requires some left (or leading) and right (trailing) constraints. See the code example for details.
class NTDummyVC: UIViewController, UIScrollViewDelegate {
let SCROLLVIEW_HIGHT:CGFloat = 500
let PAGECONTROL_WIDTH:CGFloat = 200
let PAGECONTROL_HIGHT:CGFloat = 50
var scrollView = UIScrollView()
var pageControl = UIPageControl()
var contentViewArray: NSMutableArray = NSMutableArray()
var imageArray: NSArray = ["ImageName one",
"ImageName two",
"ImageName three"]
var titleArray: NSArray = [NSLocalizedString("Title one", comment: ""),
NSLocalizedString("Title two", comment: ""),
NSLocalizedString("Title three", comment: "")]
var subTitleArray: NSArray = [NSLocalizedString("SubTitle one", comment: ""),
NSLocalizedString("SubTitle two", comment: ""),
NSLocalizedString("SubTitle three", comment: "")]
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
initScrollView()
initPageControl()
loadScrollView()
//After loading all SubViews, update the contentSize of UIScrollView according to the number of Subviews.
let scrollViewWidth = scrollView.frame.size.width * CGFloat(getPageCount())
self.scrollView.contentSize = CGSize(width: scrollViewWidth, height: scrollView.frame.size.height)
}
func getTopbarHeight() -> CGFloat {
let statusBarHeight = UIApplication.shared.statusBarFrame.height
let navigationBarHeight = navigationController?.navigationBar.frame.height ?? 0.0
return statusBarHeight + navigationBarHeight
}
func getPageCount() -> Int {
var pageCount = 0
pageCount = imageArray.count
if titleArray.count < pageCount {
pageCount = titleArray.count
}
if subTitleArray.count < pageCount {
pageCount = subTitleArray.count
}
return pageCount
}
func initScrollView() {
self.scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: SCROLLVIEW_HIGHT))
self.scrollView.delegate = self
self.scrollView.bounces = false
self.scrollView.isPagingEnabled = true
self.scrollView.showsVerticalScrollIndicator = false
self.scrollView.showsHorizontalScrollIndicator = false
self.view.addSubview(self.scrollView)
//Constraints for ScrollView, by snapkit tool.
self.scrollView.snp.makeConstraints { (make) in
make.width.equalToSuperview()
make.height.equalTo(SCROLLVIEW_HIGHT)
make.top.equalToSuperview().offset(getTopbarHeight())
make.leading.equalToSuperview()
}
}
func initPageControl() {
self.pageControl.numberOfPages = getPageCount()
self.pageControl.currentPage = 0
self.pageControl.tintColor = UIColor.gray
self.pageControl.pageIndicatorTintColor = UIColor.gray
self.pageControl.currentPageIndicatorTintColor = UIColor.green
self.view.addSubview(pageControl)
//Constraint displayed in the center, by snapkit tool.
self.pageControl.snp.makeConstraints { (make) in
make.width.equalTo(PAGECONTROL_WIDTH)
make.height.equalTo(PAGECONTROL_HIGHT)
make.top.equalTo(self.scrollView.snp.bottom).offset(10)
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
make.centerX.equalToSuperview()
}
pageControl.addTarget(self, action: #selector(self.changePage(sender:)), for: UIControlEvents.valueChanged)
}
func loadScrollView() {
let pageCount = getPageCount()
for index in 0...(pageCount - 1) {
var frame = CGRect.zero
frame.origin.x = self.scrollView.frame.size.width * CGFloat(index)
frame.origin.y = 0
frame.size = self.scrollView.frame.size
let contentView = UIView(frame: frame)
contentView.backgroundColor = .white
self.scrollView.addSubview(contentView)
//Constraints for SubView, by snapkit tool.
//Do’t add extra constraints such as top, bottom, width, height, etc., which will cause abnormal display.
contentView.snp.makeConstraints { (make) in
make.width.equalTo(UIUtils.screenWidth())
make.height.equalTo(self.scrollView.snp.height)
if index >= 1 {
let view:UIView = contentViewArray.object(at: index - 1) as! UIView
make.leading.equalTo(view.snp.trailing)
} else {
make.leading.equalTo(0)
}
if index == (pageCount - 1) {
make.trailing.equalTo(0)
}
}
let imageView = UIImageView(image: UIImage(named: imageArray[index] as! String))
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = UIViewContentMode.scaleAspectFit
contentView.addSubview(imageView)
imageView.snp.makeConstraints { (make) in
make.centerX.equalToSuperview()
}
let titleLabel = UILabel()
titleLabel.font = UIFont.boldSystemFont(ofSize: 18)
titleLabel.text = titleArray[index] as? String
titleLabel.textColor = .black
titleLabel.numberOfLines = 0
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(titleLabel)
titleLabel.snp.makeConstraints { (make) in
make.top.equalTo(imageView.snp.bottom).offset(30)
make.leading.equalToSuperview().offset(30)
make.trailing.equalToSuperview().offset(-30)
}
let subTitleLabel = UILabel()
subTitleLabel.font = UIFont.boldSystemFont(ofSize: 12)
subTitleLabel.text = subTitleArray[index] as? String
subTitleLabel.textColor = UIUtils.color(2)
subTitleLabel.numberOfLines = 0
subTitleLabel.lineBreakMode = .byWordWrapping
subTitleLabel.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(subTitleLabel)
subTitleLabel.snp.makeConstraints { (make) in
make.top.equalTo(titleLabel.snp.bottom).offset(5)
make.leading.equalToSuperview().offset(30)
make.trailing.equalToSuperview().offset(-30)
}
if (contentViewArray.contains(contentView)) {
contentViewArray.replaceObject(at: contentViewArray.index(of: contentView), with: contentView)
} else {
contentViewArray.insert(contentView, at: index)
}
}
}
// MARK : To Change while clicking on page control
#objc func changePage(sender: AnyObject) -> () {
let x = CGFloat(pageControl.currentPage) * scrollView.frame.size.width
scrollView.setContentOffset(CGPoint(x:x, y:0), animated: true)
}
// MARK : When UIScrollView slides over, update PageControl
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = round(scrollView.contentOffset.x / scrollView.frame.size.width)
pageControl.currentPage = Int(pageNumber)
}
}
Hope to help people who encounter the same problem.

How to achieve dynamic scrollable buttons menu?

I am already created dynamic buttons in scroll view but i need to acheive like this way.
I don't want to change the view controller when I click the buttons only get the button titles on same view controller.I have tried following way to creating buttons in scrollview.
class ViewController: UIViewController {
#IBOutlet weak var productScrollView: UIScrollView!
var buttonValues = ["Equity","Commodity","Derivatives","Market","Products","Values"]
override func viewDidLoad() {
super.viewDidLoad()
let scrollingView = colorButtonsView(buttonSize: CGSize(width:100.0,height:30.0), buttonCount: buttonValues.count)
productScrollView.contentSize = scrollingView.frame.size
productScrollView.addSubview(scrollingView)
productScrollView.showsHorizontalScrollIndicator = false
productScrollView.indicatorStyle = .default
productScrollView.setContentOffset(.zero, animated: false)
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func colorButtonsView(buttonSize:CGSize, buttonCount:Int) -> UIView {
//creates color buttons in a UIView
let buttonView = UIView()
buttonView.backgroundColor = UIColor.white
buttonView.frame.origin = CGPoint(x:0,y:0)
let padding = CGSize(width:10,height:10)
buttonView.frame.size.width = (buttonSize.width + padding.width) * CGFloat(buttonCount)
buttonView.frame.size.height = (buttonSize.height + 2.0 * padding.height)
var buttonPosition = CGPoint(x:padding.width * 0.5,y: padding.height)
let buttonIncrement = buttonSize.width + padding.width
for i in 0...(buttonCount - 1) {
let button = UIButton(type: .custom) as UIButton
button.frame.size = buttonSize
button.frame.origin = buttonPosition
buttonPosition.x = buttonPosition.x + buttonIncrement
button.setTitle(buttonValues[i], for: .normal)
button.setTitleColor(UIColor.black, for: .normal)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.black.cgColor
button.addTarget(self, action: #selector(colorButtonPressed(sender:)), for: .touchUpInside)
buttonView.addSubview(button)
}
return buttonView
}
#objc func colorButtonPressed(sender:UIButton!){
print(sender.title(for: .normal)!)
sender.setTitleColor(UIColor.blue, for: .normal)
}}
Finaly I achieve in this way
import UIKit
protocol ButtonProtocol{
func selectedButton(withTag : Int)
}
class ButtonsView: UIView {
private var scrollView: UIScrollView?
var buttonProtocolDelegate : ButtonProtocol?
var movingView : UIView?
var buttonWidths = [CGFloat]()
#IBInspectable
var wordsArray: [String] = [String]() {
didSet {
createButtons()
}
}
var padding: CGFloat = 10
var currentWidth: CGFloat = 0
private func createButtons() {
scrollView?.removeFromSuperview()
scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width+80, height: self.frame.size.height))
self.addSubview(scrollView!)
scrollView!.backgroundColor = UIColor.white
scrollView?.showsHorizontalScrollIndicator = false
scrollView?.showsVerticalScrollIndicator = false
self.calculateButtonWidths()
let totalWidthOfButtons = buttonWidths.reduce(10.0,+)
let isBigButton = buttonWidths.contains(where: {$0 > (scrollView?.frame.size.width)!/2})
for i in 0..<wordsArray.count {
let text = wordsArray[i]
var button = UIButton()
if totalWidthOfButtons >= self.frame.size.width || isBigButton {
button = UIButton(frame: CGRect(x:currentWidth, y: 0.0, width: buttonWidths[i], height: self.frame.size.height))
}else{
button = UIButton(frame: CGRect(x:currentWidth, y: 0.0, width: self.frame.size.width/CGFloat(self.buttonWidths.count), height: self.frame.size.height))
buttonWidths[i] = self.frame.size.width/CGFloat(self.buttonWidths.count)
}
button.tag = i
button.setTitle(text, for: .normal)
button.setTitleColor(UIColor.black, for: .normal)
let buttonWidth = button.frame.size.width
currentWidth = currentWidth + buttonWidth + (i == wordsArray.count - 1 ? 0 : padding)
scrollView!.addSubview(button)
button.addTarget(self, action: #selector(pressed(sender:)), for: .touchUpInside)
}
scrollView!.contentSize = CGSize(width:currentWidth,height:scrollView!.frame.size.height)
self.addMovingView()
}
func addMovingView(){
movingView = UIView.init(frame: CGRect.init(x: 0, y: (scrollView?.frame.size.height)! - 2, width: buttonWidths[0], height: 2))
movingView?.backgroundColor = UIColor.blue
scrollView?.addSubview(movingView!)
}
#objc func pressed(sender : UIButton){
self.buttonProtocolDelegate!.selectedButton(withTag : sender.tag)
self.moveButtonToCenterIfPossible(sender : sender)
}
func animageMovingView(sender : UIButton){
UIView.animate(withDuration: 0.20, delay: 0, options: [UIViewAnimationOptions.curveEaseInOut], animations: {
//Set x position what ever you want, in our case, it will be the beginning of the button
() -> Void in
self.movingView?.frame = CGRect(x: sender.frame.origin.x, y: (self.movingView?.frame.origin.y)! , width: sender.frame.size.width, height: 2)
self.superview?.layoutIfNeeded()
}, completion: { (finished) -> Void in
// ....
})
}
func moveButtonToCenterIfPossible(sender : UIButton){
self.scrollView?.scrollToView(button: sender, animated: true)
// print(sender.frame)
self.animageMovingView(sender : sender)
}
func calculateButtonWidths(){
for i in 0..<wordsArray.count {
let text = wordsArray[i]
let button = UIButton(frame: CGRect(x:0, y: 0.0, width: 100, height: 50))
button.tag = i
button.setTitle(text, for: .normal)
button.sizeToFit()
button.contentEdgeInsets = UIEdgeInsets.init(top: 5, left: padding, bottom: 5, right: padding)
button.sizeToFit()
let buttonWidth = button.frame.size.width
buttonWidths.append(buttonWidth)
}
}
}
extension UIScrollView {
func scrollToView(button:UIButton, animated: Bool) {
if let origin = button.superview {
// let buttonStart = button.frame.origin
let buttonCenterPoint = button.center
var scrollOffset = (origin as? UIScrollView)?.contentOffset
let offset = scrollOffset
let deviceBounds = (origin.superview?.frame.size.width)!/2
// print(buttonStart, deviceBounds, scrollOffset ?? "0.0")
let differenceLeft = buttonCenterPoint.x - (scrollOffset?.x)!
let differenceRight = ((origin as? UIScrollView)?.contentSize.width)! - (contentOffset.x + deviceBounds*2)
if buttonCenterPoint.x > deviceBounds {
// scroll left & right
if differenceLeft > deviceBounds && differenceRight < deviceBounds && differenceRight < button.frame.size.width {
//handle last button
scrollOffset?.x = (offset?.x)! + differenceRight
}else{
//for all others in the middle
scrollOffset?.x = (offset?.x)! + differenceLeft - deviceBounds
}
self.setContentOffset(CGPoint.init(x: (scrollOffset?.x)! , y: 0), animated: true)
// scroll right
}else {
// left most buttons
self.setContentOffset(CGPoint.init(x: 0 , y: 0), animated: true)
}
}
}
}
and your view controller
#IBOutlet weak var buttonsView: ButtonsView!
override func viewDidLoad() {
super.viewDidLoad()
buttonsView.buttonProtocolDelegate = self
buttonsView.wordsArray = ["Offers", "Burgers", "Shakes", "Biryani","Snacks", "Lucknow Biryani","Elepaha","dfasjjlfajd","dafjljafl","546464464"]
} extension ViewController {
func selectedButton(withTag : Int) {
print(buttonsView.wordsArray[withTag])
}}

Add a subview(ShareView) but nothing happens when touching a button on it

Add a subview(ShareView) but nothing happens when touching a button(coverBtn) on it if I shareVC.addsubView(self) in func showShareView ()
But If superView.addSubview(coverBtn) and superView.addSubview(sharePanel) separately, everything will be fine.
import UIKit
class ShareView: UIView {
weak var shareVC: UINavigationController?
// UI
private lazy var coverView: UIView! = {
let coverView = UIView(frame: UIScreen.mainScreen().bounds)
return coverView
}()
// transluscent cover
private lazy var coverBtn: UIButton! = {
let bounds = UIScreen.mainScreen().bounds
let frame = CGRectMake(0, 0, bounds.width, bounds.height)
let coverBtn = UIButton(frame: frame)
print ("UIScreen.mainScreen().bounds = \(UIScreen.mainScreen().bounds)")
coverBtn.alpha = 0.2
coverBtn.backgroundColor = UIColor.blackColor()
coverBtn.addTarget(self, action: #selector(ShareView.pressCoverBtn), forControlEvents: .TouchUpInside)
return coverBtn
}()
let panelHeight: CGFloat = 215
// share panel
private lazy var sharePanel: UIView! = {
// panel size
let bounds = UIScreen.mainScreen().bounds
let h = 215
let frame = CGRectMake(0, bounds.height, bounds.width, self.panelHeight)
let sharePanel: UIView = UIView(frame: frame)
sharePanel.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1.0)
// label
let labelHeight: CGFloat = 30
let labelWidth: CGFloat = 100
let labelY: CGFloat = 20
let labelFrame = CGRectMake(sharePanel.frame.width/2-labelWidth/2, labelY, labelWidth, labelHeight)
let label = UILabel(frame: labelFrame)
label.text = "分享到"
label.textAlignment = .Center
label.backgroundColor = UIColor.whiteColor()
sharePanel.addSubview(label)
// share buttons
let marginW: CGFloat = 80
let btnInv: CGFloat = 20
let btnCnt: CGFloat = 3
let btnsY = label.frame.maxY + 15
let btnA = (sharePanel.frame.width - 2*marginW - (btnCnt-1)*btnInv)/btnCnt
let wcFrame = CGRectMake(marginW, btnsY, btnA, btnA)
let pyqFrame = CGRectMake(wcFrame.maxX+btnInv, btnsY, btnA, btnA)
let wbFrame = CGRectMake(pyqFrame.maxX+btnInv, btnsY, btnA, btnA)
let wcBtn = UIButton(frame: wcFrame)
let pyqBtn = UIButton(frame: pyqFrame)
let wbBtn = UIButton(frame: wbFrame)
wcBtn.setImage(UIImage(named: "share_wx"), forState: .Normal)
pyqBtn.setImage(UIImage(named: "share_pyq"), forState: .Normal)
wbBtn.setImage(UIImage(named: "share_wb"), forState: .Normal)
sharePanel.addSubview(wcBtn)
sharePanel.addSubview(pyqBtn)
sharePanel.addSubview(wbBtn)
// cancel button
let ccW = sharePanel.frame.width/2
let ccH: CGFloat = 50
let ccFrame = CGRectMake(sharePanel.frame.width/2-ccW/2, wcBtn.frame.maxY+10, ccW, ccH)
let cancelBtn: UIButton = UIButton(frame: ccFrame)
cancelBtn.setBackgroundImage(UIImage(named: "kkk"), forState: .Normal)
cancelBtn.setTitle("取消", forState: .Normal)
cancelBtn.setTitleColor(UIColor.blackColor(), forState: .Normal)
cancelBtn.addTarget(self, action: #selector(ShareView.pressCoverBtn), forControlEvents: UIControlEvents.TouchUpInside)
sharePanel.addSubview(cancelBtn)
return sharePanel
}()
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/
// override init(){
// super.init()
// }
override init(frame: CGRect) {
super.init(frame: frame)
self.addCustomView(self)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addCustomView (superView: UIView) {
superView.addSubview(coverBtn)
superView.addSubview(sharePanel)
}
#objc func pressCoverBtn() {
print("press cover btn\n")
hideShareView()
}
func showShareView () {
self.addCustomView((shareVC?.view)!)
UIView.animateWithDuration(0.4, animations: {
() -> Void in
self.sharePanel.frame = CGRectMake(0, UIScreen.mainScreen().bounds.height - self.panelHeight, self.sharePanel.frame.width, self.panelHeight)
})
}
func hideShareView() {
coverBtn.removeFromSuperview()
UIView.animateWithDuration(0.4, animations: {
() -> Void in
self.sharePanel.frame = CGRectMake(0, UIScreen.mainScreen().bounds.height, self.sharePanel.frame.width, self.panelHeight)
}) { (finish)-> Void in
self.removeFromSuperview()
}
}
}
you can check the 'Debug View Hierarchy' to focus on layers so that you can see if there is a view over the button blocking it
'Debug view Hierarchy' will give you 3d view of every layer
it is situated in bottom bar
Also, you are adding both the views to the superview, try to add 'coverBtn' button to the 'sharePanel' view and then add the view to the super view, this will create button layer above the 'sharePanel' view

Swift: Buttons not working inside UIScrollView

I have a ScrollView. You can scroll but the buttons don't allow you to press them(when you press them they don't do anything). Can you help fix this? Here is my current code:
PS: I'm checking this regularly so if you have a question I'll answer.
class ViewController: UIViewController {
#IBOutlet weak var categoryScrollView: UIScrollView!
var categoryArr = ["Button1","Button2","Button3","Button4","Button5", "Button 6", "Button 7", "Button 8", "Button 9", "Button 10", "Button 11", "Button 12"]
var buttonColors = [UIColor.greenColor(), UIColor.blueColor(), UIColor.blackColor(), UIColor.cyanColor(), UIColor.magentaColor(), UIColor.greenColor(), UIColor.blueColor(), UIColor.blackColor(), UIColor.cyanColor(), UIColor.magentaColor(), UIColor.blackColor(), UIColor.brownColor()]
var buttonImages = [UIImage(named: "One"), UIImage(named: "Two"), UIImage(named: "Three"), UIImage(named: "PlayButtonImage"), UIImage(named: "Triangle"), UIImage(named: "PlayButtonImage"), UIImage(named: "Triangle"), UIImage(named: "PlayButtonImage"), UIImage(named: "Triangle"), UIImage(named: "PlayButtonImage"), UIImage(named: "Triangle"), UIImage(named: "PlayButtonImage")]
let kPadding:CGFloat = 20
override func viewDidLoad() {
super.viewDidLoad()
let buttonSize = CGSizeMake(categoryScrollView.bounds.size.width/2, categoryScrollView.bounds.size.height/2)//hal
let scrollingView = ImageButtonsView(buttonSize, buttonCount: 12)
categoryScrollView.contentSize = scrollingView.frame.size
categoryScrollView.addSubview(scrollingView)
categoryScrollView.showsVerticalScrollIndicator = false
categoryScrollView.delegate = self
categoryScrollView.pagingEnabled = true
categoryScrollView.indicatorStyle = .Default
categoryScrollView.contentOffset = CGPointMake(0, 0)
categoryScrollView.delaysContentTouches = false
categoryScrollView.userInteractionEnabled = true;
categoryScrollView.exclusiveTouch = true;
categoryScrollView.canCancelContentTouches = true;
//categoryScrollView.clipsToBounds = true
}
func ImageButtonsView(buttonSize:CGSize, buttonCount:Int) -> UIView {
let buttonView = UIView()
buttonView.frame.origin = CGPointMake(50,142)
let padding = CGSizeMake(kPadding, kPadding)
buttonView.frame.size.width = (buttonSize.width + padding.width) * CGFloat(buttonCount)
var buttonPosition = CGPointMake(0, padding.height)
let buttonIncrement = buttonSize.width + padding.width
for i in 0...(buttonCount - 1) {
let button = UIButton(type: .Custom)
buttonView.userInteractionEnabled = true
button.frame.size = buttonSize
button.frame.origin = buttonPosition
buttonPosition.x = buttonPosition.x + buttonIncrement
button.setTitle(categoryArr[i], forState: UIControlState.Normal)
let buttonImagesOne = buttonImages[i]
button.setImage(buttonImagesOne, forState: .Normal)
button.layer.cornerRadius = 30
button.addTarget(self, action: "pressed:", forControlEvents: UIControlEvents.TouchUpInside)
buttonView.addSubview(button)
}
//buttonView.backgroundColor = UIColor.redColor()
categoryScrollView.bringSubviewToFront(buttonView)
return buttonView
}
}
extension ViewController:UIScrollViewDelegate{
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let index = round(scrollView.contentOffset.x / scrollView.frame.size.width)
print(index)
}
func pressed(/*sender: UIButton!*/) {
let vc = UIViewController(nibName: "GridViewController", bundle: nil)
self.presentViewController(vc, animated: true, completion:nil)
//viewController.hidden = true
}
}
Originally here, I thought the line
button.addTarget(self, action: "pressed:", forControlEvents: UIControlEvents.TouchUpInside)
should have said "pressed" without a ":". But that turned out to be a misunderstanding on my part, sorry. It should be "pressed:".
Instead, this may be related to Protocol extension and addTarget is crashing with NSInvalidArgumentException which is also very confusing.
It turned out my scrollview's layout was set to "Autoresizing Mask" instead of "Inferred (Constraints)". Although my layout looked good, my buttons were actually outside the bounds of the scrollview and therefore couldn't be clicked!
Have you tried adding a UITapGestureRecognizer to your button? You could try something like this:
let myTap = UITapGestureRecognizer(target: self, action: Selector("handleButtonTap:"))
myTap.delegate = self
//**Make your class inherit from UIGestureRecognizerDelegate otherwise an error will be thrown**
myButton.addGestureRecognizer(myTap)
Then write a function (the name of the function should be what you put in the action field above. So in this case the function would be called handleButtonTap. Here is the code:
func handleButtonTap() {
// Handle what happens when the button is tapped.
}
I hope I was able to help :).
This is my approach (Swift 2 / xCode 7.2.1):
I have 2 View Controllers:
“VC1” with the scrollview
Here I create the different views (instances of “VC2”) and add them to the scrollview:
scrollView.addSubview(pageStep.view)
addChildViewController(pageStep)
which I call page1, page2, page3 …
Then you can access the "page1.btn1" and do something like this
page1.nextBtn.addTarget(self, action: "nextPage:", forControlEvents: .TouchUpInside)
func nextPage(sender: UIButton!) {
let xPosition = (pageFraction + 1) * scrollSize
scrollView.setContentOffset(CGPoint(x: xPosition, y: 0), animated: true)
}
“VC2” With the outlets (each page) (UIImage, Buttons etc.)
I hope it helps !

Swift: How to use buttons in Scroll View

I have created a scroll view with "buttons". But the "buttons" actually don't do anything at the moment. So, I would like to know, how I can make the "buttons" usable. So when I press them they lead me to a different view controller. All the buttons will lead me to the same view controller just with different data (depending on what I want that button to represent) inside the view controller. Here's my code so far:
#IBOutlet weak var categoryScrollView: UIScrollView!
var categoryArr = ["Button1","Button2","Button3","Button4","Button5", "Button 6", "Button 7", "Button 8", "Button 9", "Button 10", "Button 11", "Button 12"]
var buttonColors = [UIColor.greenColor(), UIColor.blueColor(), UIColor.blackColor(), UIColor.cyanColor(), UIColor.magentaColor(), UIColor.greenColor(), UIColor.blueColor(), UIColor.blackColor(), UIColor.cyanColor(), UIColor.magentaColor(), UIColor.blackColor(), UIColor.brownColor()]
let kPadding:CGFloat = 20
override func viewDidLoad() {
super.viewDidLoad()
let buttonSize = CGSizeMake(categoryScrollView.bounds.size.width/2, categoryScrollView.bounds.size.height/2)//hal
let scrollingView = colorButtonsView(buttonSize, buttonCount: 12)
categoryScrollView.contentSize = scrollingView.frame.size
categoryScrollView.addSubview(scrollingView)
categoryScrollView.showsVerticalScrollIndicator = false
categoryScrollView.delegate = self
categoryScrollView.pagingEnabled = true
categoryScrollView.indicatorStyle = .Default
categoryScrollView.contentOffset = CGPointMake(0, 0)
}
func colorButtonsView(buttonSize:CGSize, buttonCount:Int) -> UIView {
let buttonView = UIView()
buttonView.frame.origin = CGPointMake(50,300)
let padding = CGSizeMake(kPadding, kPadding)
buttonView.frame.size.width = (buttonSize.width + padding.width) * CGFloat(buttonCount)
var buttonPosition = CGPointMake(0, padding.height)
let buttonIncrement = buttonSize.width + padding.width
for i in 0...(buttonCount - 1) {
let button = UIButton(type: .Custom)
button.frame.size = buttonSize
button.frame.origin = buttonPosition
buttonPosition.x = buttonPosition.x + buttonIncrement
button.setTitle(categoryArr[i], forState: UIControlState.Normal)
button.backgroundColor = buttonColors[i]
buttonView.addSubview(button)
}
buttonView.backgroundColor = UIColor.redColor()
return buttonView
}
}
extension ViewController:UIScrollViewDelegate{
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let index = round(scrollView.contentOffset.x / scrollView.frame.size.width)
print(index)
}
}
When you create your button you have to specify a target in order to have an action with it (add this in your for loop) :
button.addTarget(self, action: "myaction:", forControlEvents: .TouchUpInside)
then create the corresponding method
func myaction(sender: UIButton!) {
// navigation code here.
}
Please note that you don't have to create several method in order to have different actions for each button, all you have to do is something like this :
button.tag = i
and then in your action method :
switch sender.tag {
case 0 :
//do some stuff
case 1 :
//do some stuff
}
You have to add targets to button to fire some action methods. Like in your loop when you create UIButton, add
button.addTarget(self, action: "pressed:", forControlEvents: .TouchUpInside)
and implement one method like:
func pressed(sender: UIButton!) {
// navigation code here.
}

Resources