Use buttons inside subview - ios

I'm making a multiple choice quiz game, and my goal right now is to have four buttons that refresh by spinning around with new answer choices. I think that means I need a subview that animates and re-populates with new buttons--if that's incorrect or not best, please stop me here.
At any rate, I created the subview in my storyboard, put the buttons inside it (background is blue just to see it now):
I dragged that over to my ViewController to make an IBOutlet (buttonContainer) and added this code to my ViewDidLoad:
view.addSubview(buttonContainer)
let buttonTap = UITapGestureRecognizer(target:self, action: Selector("checkAnswer"))
buttonTap.numberOfTapsRequired = 1
buttonContainer.addGestureRecognizer(buttonTap)
buttonContainer.userInteractionEnabled = true
However: When I run it in the simulator, the blue background does not appear at all, but the buttons are still disabled.
Before creating the subview, both the buttons and the function (checkAnswer) they called all worked perfectly.

You don't need any of this code if you are creating everything in storyboard. Just create a new class for the containerview and connect the buttons as an outlet collection.
For example, your button container class might look something like this:
class ButtonContainerView: UIView {
#IBOutlet var answerButtons: [UIButton]!
func rotateButtons() {
for button in answerButtons {
var context = UIGraphicsGetCurrentContext()
UIView.beginAnimations(nil, context: &context)
UIView.setAnimationCurve(UIViewAnimationCurve.Linear)
UIView.setAnimationDuration(5.0)
button.transform = CGAffineTransformRotate(button.transform, CGFloat(M_PI))
UIView.commitAnimations()
}
}
}

Related

Button in tip view create by EasyTipView

I'm using EasyTipView to create a custom tip view have a button inside look like the image below. But notthing happen when I click to button inside tip view. Does anyone have use this libray and know how to fix this problem ?
My demo: github.com/minhtien1403/TestTipView
Library link: https://github.com/teodorpatras/EasyTipView
View hierarchy is fine, nothing overlay the button
As from your github demo, I notice things make button click inside not working.
First of all, in your CustomTipView when ever you change to position, you call translatesAutoresizingMaskIntoConstraints to redefine view which make the xib not working correctly anymore. Just need to remove this
fileprivate func arrange(withinSuperview superview: UIView) {
// your others code
if case .view(let contentView) = content {
contentView.translatesAutoresizingMaskIntoConstraints = false // remove this
contentView.frame = getContentRect(from: getBubbleFrame())
}
// your others code
}

Why is my button displayed but not clickable?

I've created a ViewController containing a user button, which is going to be present in several View Controllers in my application.
I'm adding this ViewController dynamically to the needed ViewControllers. The user button is shown, but it's not clickable. What am I doing wrong?
I've tried setting constraints to the view containing the button, setting the container view's frame, disabling user interaction in the container view (not in the button) and nothing seems to work
import UIKit
class ModulePageViewController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.addSharedButtonsSubView()
}
func addSharedButtonsSubView() {
let sharedButtons = storyboard?.instantiateViewController(withIdentifier: sharedButtonsViewControllerName)
view.addSubview((sharedButtons?.view)!)
sharedButtons?.view.frame = CGRect(x: view.frame.minX, y: view.frame.minY, width: view.frame.width, height: view.frame.height)
addChild(sharedButtons!)
sharedButtons?.didMove(toParent: self)
}
}
You can create a custom view (not ViewController) containing the button and just use it where you need in you app.
#LeCalore ...
I would recommend if you want to use a button or any more stuff on multiple View Controllers then you should just make a new ViewController with that button and whatever else you want on it then use it where ever you want.
ViewController -> Present As Pop Over (Presentation : Over Current Context)
I think that's a better approach atleast for starters.
Else, as user said ... you can make a custom view programatically and call it wherever you need that's another approach but it might give you a bit of trouble.
Open to others view if there's one better.
Gluck

Creating a floating menu in an iOS application

Looking to create a floating menu in Swift for an iOS application I am developing. Something along the lines of the little red circle menu as shown in the following image.
My initial thoughts were to extend the UIViewController class and add the respective drawing/logic there, however, the application is comprised of a few other controllers, more specifically the UITableViewController which in itself extends UIViewController. Is there perhaps a good place for an extension perhaps? Or is there a more eloquent way of drawing the menu on specific views without the mass duplication of menu related code?
The menu itself will be shown on most screens, so I need to selectively enable it. It'll also be somewhat contextual based on the view/screen the user is currently on.
Any awesome ideas?
You can create your own with the animations and all the things, or you can check this library
https://github.com/lourenco-marinho/ActionButton
var actionButton: ActionButton!
override func viewDidLoad() {
super.viewDidLoad()
let twitterImage = UIImage(named: "twitter_icon.png")!
let plusImage = UIImage(named: "googleplus_icon.png")!
let twitter = ActionButtonItem(title: "Twitter", image: twitterImage)
twitter.action = { item in println("Twitter...") }
let google = ActionButtonItem(title: "Google Plus", image: plusImage)
google.action = { item in println("Google Plus...") }
actionButton = ActionButton(attachedToView: self.view, items: [twitter, google])
actionButton.action = { button in button.toggleMenu() }
}
There is another alternative with this great library :
https://github.com/yoavlt/LiquidFloatingActionButton
You just have to implement the delegate and the dataSource in your ViewController:
let floatingActionButton = LiquidFloatingActionButton(frame: floatingFrame)
floatingActionButton.dataSource = self
floatingActionButton.delegate = self
You could use view controller containment. The menu can be its own view controller with its view laid transparently over top the content view controller.
For example this can be set up in the storyboard by dragging out two container views into a vanilla view controller.

UIView does not have a member named, "inertia"

I am attempting to create a button programmatically that will fade out when tapped, change the text, then fade back in. However, when i try to write the code for the fade animation, I get the error, "'UIView' does not have a member named 'inertia' Inertia is the name of the button, of course.
Here is my code for creating the button, it is within a function that is called within the viewDidLoad() function:
var inertia = UIButton.buttonWithType(UIButtonType.System) as UIButton
inertia.frame = CGRectMake(firstView.frame.width/2-(inertia.frame.width/2), firstView.frame.height/10, firstView.frame.width, firstView.frame.height/10)
inertia.frame = CGRectMake(firstView.frame.width/2-(inertia.frame.width/2), firstView.frame.height/10, firstView.frame.width, firstView.frame.height/10)
inertia.setTitle("Newton's First Law of Motion", forState: UIControlState.Normal)
inertia.addTarget(self, action: "tapped:", forControlEvents: .TouchUpInside)
self.firstView.addSubview(inertia)
This is my line of code for when the button is tapped so far, where the error occurs:
UIView.animateWithDuration(0.4, animations: {self.firstView.inertia.alpha = 0})
I believe I am missing something in the button creation, because when I create an outlet for a button from the storyboard the fade animation will not produce an error.
Please help me fix this issue as I will be using this often. Also if you could find a way for me to create the button's frame properly without having to declare it twice that would be helpful as well.
What I have tried (to no avail):
I have put : UIButton! after var inertia
I have tried `UIView.animateWithduration(0.4, animations: {self.inertia.alpha = 0})
Just to break down the problem line, specifically self.firstView.inertia.alpha. Self is obviously whatever class instance you are in. I assume from the error you are reporting and your code that firstView is a UIView. Now you have added inertia as a subview of firstView, but that does not create a property named inertia on the view. In other words, there is no firstView.inertia. What firstView has is a subviews property which is an array of anyobject.
In other words the button that you created and called inertia is now somewhere in the array firstView.subviews, though it's hard to say where depending on how many other views it has as subviews.
You could iterate through the subviews array to find the button which you'd previously called inertia, but it might be simpler to just keep a reference to inertia. You could make it a property in your class (if there is only one such button) and the call your code with
UIView.animateWithDuration(0.4, animations: {self.inertia.alpha = 0})
As I understand from your description you code looks something like this:
class ViewController:UIViewController {
var firstView:UIView!
func tapped(button: UIButton) {
UIView.animateWithDuration(0.4) { self.firstView.inertia.alpha = 0 }
}
override func viewDidLoad() {
super.viewDidLoad()
var inertia = UIButton.buttonWithType(UIButtonType.System) as UIButton
inertia.frame = CGRectMake(firstView.frame.width/2-(inertia.frame.width/2), firstView.frame.height/10, firstView.frame.width, firstView.frame.height/10)
inertia.frame = CGRectMake(firstView.frame.width/2-(inertia.frame.width/2), firstView.frame.height/10, firstView.frame.width, firstView.frame.height/10)
inertia.setTitle("Newton's First Law of Motion", forState: UIControlState.Normal)
inertia.addTarget(self, action: "tapped:", forControlEvents: .TouchUpInside)
self.firstView.addSubview(inertia)
}
}
Now, you get that error because inerta is not declared as a property in your class, you only create it in a function. If you want to use that button when pressed in tapped() then simply change:
UIView.animateWithDuration(0.4) { self.firstView.inertia.alpha = 0 }
// To
UIView.animateWithDuration(0.4) { button.alpha = 0 } // When TouchUpInside the button will pass itself
Or you can make it a propery by adding:
var inertia:UIButton! // Under class ...
And remove var in viewDidLoad when setting it.

iOS using xib + global methods for overlay UIView (Swift)

I'm writing an app that should present overlays in specific situations, like for example the lack of location services enabled for the app.
Overlay is a UIView with a UIImageView (background) a UILabel (title) and a UIButton calling a specific action. I want to use Interface Builder to set up the overlay UI but I would like to recall the overlay and show it on different UIViewControllers, depending on when the lack of location services is detected.
I have set up a custom class (subclass of UIView) to link a xib file. Code below:
class LaunchCustomScreen: UIView
{
#IBOutlet var title: UILabel!
#IBOutlet var enableLocationButton: UIButton!
#IBOutlet var waitingIndicator: UIActivityIndicatorView!
#IBOutlet var bckgroundImage: UIImageView!
func setupDefault()
{
title.text = "Location Services Required"
enableLocationButton.setTitle("Enable Location Services", forState: UIControlState.Normal)
enableLocationButton.addTarget(self,
action: "promptUserForLocation",
forControlEvents: UIControlEvents.TouchUpInside)
hideLocButton()
}
func hideLocButton()
{
enableLocationButton.hidden = true
}
func showLocButton()
{
enableLocationButton.hidden = false
}
}
Then I have created the xib file which is of Class LaunchCustomScreen and I linked the IBOutlets to all the objects in it (UILabels, UIBUtton, UIImageView)
Then I have set some global functions to be called from any other UIViewController in order to show/hide the overlay on the specific view controller and configure it with UIButton hidden or visible (it will be hidden with a waiting indicator when user location is still loading). Below related code:
func setupLaunchDefault(vc: UIViewController) -> LaunchCustomScreen
{
for aSubview in vc.view.subviews
{
if aSubview.isKindOfClass(LaunchCustomScreen)
{
NSLog("Found already a launch screen. Removing")
aSubview.removeFromSuperview()
}
}
var screen: LaunchCustomScreen = LaunchCustomScreen()
screen.setupDefault()
return screen
}
func showLaunchAskLocation(vc:UIViewController)
{
var screen = setupLaunchDefault(vc)
screen.bounds = vc.view.bounds
screen.showLocButton()
vc.view.addSubview(screen)
}
Now I'm trying if the solution works and it crashes on the setupLaunchDefault function. Reason is that even if an instance of LaunchCustomSCreen is created, the variables (title, enableLocationButton) are still nil. I though they should be non-nil thanks to the IBOutlet to the xib... what am I missing?
Thank you in advance for your help!
I have set up a custom class (subclass of UIView) to link a xib file
No, you haven't. No such "link" is possible.
what am I missing?
You're not missing anything, because you've already figured it out!
Merely creating a LaunchCustomScreen instance out of thin air (i.e. by saying LaunchCustomScreen(), as you are doing) merely creates an instance of this class. It has nothing whatever to do with the .xib (nib) file! There is no magic "link" whatever between the class and the nib! Thus, nothing happens that would cause these properties to get any value. They are, as you have rightly explained, nil.
You have designed and configured one special particular instance of LaunchCustomScreen in the nib. That is the instance whose outlets are hooked up, within the same nib. So if you want an instance of LaunchCustomScreen with hooked-up outlets, you must load the nib! Loading the nib is exactly equivalent to making an instance of what's in the nib - it is a form of instantiation. And here, it's the form of instantiation you want, because this instance is the instance you want.
So, the answer is: do not say LaunchCustomScreen() to get your LaunchCustomScreen instance (screen). Instead, load the nib to get your LaunchCustomScreen instance - and all will be well.
So, let's say your .xib file is called LaunchCustomScreen.xib. You would say:
let arr = NSBundle.mainBundle().loadNibNamed("LaunchCustomScreen", owner: nil, options: nil)
let screen = arr[0] as UIView
The first result, arr, is an array of top-level objects instantiated from the nib. The first of those objects (probably the only member of the array) is the view you are after! So you cast it to a UIView and you are ready to stick it into your interface. Since the view comes from the nib, its outlets are set, which is what you're after. You can do this as many times as you need to, to get as many "copies" of this view as you like.

Resources