I have read the manual (https://material.io/develop/ios/components/buttons/), but still have not understood how to do it.
class FloatingButtonController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let floatingButton = MDCFloatingButton()
floatingButton.setImage( UIImage(named: "plus"), for: .normal)
floatingButton.backgroundColor = .white
floatingButton.setElevation(ShadowElevation(rawValue: 6), for: .normal)
floatingButton.addTarget(self, action: #selector(btnFloatingButtonTapped(floatingButton:)), for: .touchUpInside)
self.view.addSubview(floatingButton)
}
#objc func btnFloatingButtonTapped(floatingButton: MDCFloatingButton){
floatingButton.collapse(true) {
floatingButton.expand(true, completion: nil)
}
}
}
My project on the screen. As you can see - the button is missing on the screen. When you click on a blank screen errors appear.
Button touch target does not meet minimum size guidlines of (48, 48). Button: >, Touch Target: {0, 0}
Screenshot of my project
Tell me, please, what am I doing wrong? And how do I get the job right?
You didn't set the frame to button. You need to specify (x, y) position to place button in view.
floatingButton.frame = CGRect(x: 300, y: 300, width: 48, height: 48)
To add button target the button should have size atlease 48x48.
You could constraint it manually or set frame.
OR you could add button via Storyboard too.
Related
I am seeing some weird behavior from an array of buttons I have built in storyboard. I have 4 buttons each of custom type TakesContainerButton and when a button is clicked it changes to the system font, but when a different button is clicked the previously button returns to the desired font, not sure what is going on here
The buttons are also embedded in a stack view, if that matters
Here is the the implementation when one of the buttons is pressed where buttons is an array of the 4 buttons
#IBAction func filterPressed(_ sender: TakesContainerButton) {
for button in buttons {
button.unclick()
}
sender.click()
}
here is the custom class
class TakesContainerButton: UIButton {
var bottom = UIView()
func click(){
self.setTitleColor(.darkGray, for: .normal)
let xOffset:CGFloat = 10
bottom = UIView(frame: CGRect(x: xOffset / 2, y: self.frame.height - 3, width: self.frame.width - xOffset, height: 3))
bottom.layer.cornerRadius = 1.5
bottom.backgroundColor = .darkGray
self.addSubview(bottom)
}
func unclick(){
bottom.removeFromSuperview()
self.setTitleColor(UIColor(hex: "8B8B8B"), for: .normal)
}
override func awakeFromNib(){
setFont()
}
func setFont(){
self.titleLabel?.font = UIFont(name: "Lato-Bold", size: 12)
}
}
In StoryBoard set button :
Type to Custom
Style to Default and
State Config to Default
you should have something like this
Is there any specific reason that you are calling setFont() on every click. As I am able to see that you are not changing the font you should set this font at the time of view loading and leave the font as it is.
I want to run UIActivityIndicator when the application is opened. How can I do this? My code is the way I share it down there. I want this code to work when Launchscreen opens.
#objc func buttonTapped(_ sender: UIButton) {
let size = CGSize(width: 30, height: 30)
let selectedIndicatorIndex = sender.tag
let indicatorType = presentingIndicatorTypes[selectedIndicatorIndex]
startAnimating(size, message: "Loading...", type: indicatorType, fadeInAnimation: nil)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) {
NVActivityIndicatorPresenter.sharedInstance.setMessage("Authenticating...")
}
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
self.stopAnimating(nil)
}
}
for (index, indicatorType) in presentingIndicatorTypes.enumerated() {
let x = 150
let y = 250
let frame = CGRect(x: x, y: y, width: 100, height: 100)
let activityIndicatorView = NVActivityIndicatorView(frame: frame,
type: .orbit)
let animationTypeLabel = UILabel(frame: frame)
activityIndicatorView.padding = 20
if indicatorType == NVActivityIndicatorType.orbit {
activityIndicatorView.padding = 0
}
self.view.addSubview(activityIndicatorView)
self.view.addSubview(animationTypeLabel)
activityIndicatorView.startAnimating()
let button: UIButton = UIButton(frame: frame)
button.tag = index
#if swift(>=4.2)
button.addTarget(self,
action: #selector(buttonTapped(_:)),
for: .touchUpInside)
#else
button.addTarget(self,
action: #selector(buttonTapped(_:)),
for: UIControlEvents.touchUpInside)
#endif
self.view.addSubview(button)
}
What you are trying to achieve is to show UIActivityIndicator during launch screen, which is unfortunately NOT possible. If you want to do any animations on launch screen, use your first view controller as splash screen and redirect to main screen when animation on splash screen ends.
Some ideas:
Create separate loading page and call it from didFinishLaunchingWithOptions method in App delegate
Add loading indicator (can be whatever you want) to it
Set timer of 2-3 seconds, when it ends redirect to your main screen
P.S. delaying application launch just to show users some awesome animation/loading screen is not a good idea. For a first time app users it might seem cool and such, but with an extensive use of an application users might get frustrated waiting even few seconds each time an application is launched.
Good luck :)
I have been trying to fix an issue that I encountered with a tableviewcontroller.
The sections within the tableviewcontroller are views:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let sectionLabel = UILabel()
sectionLabel.text = Catalog.sharedInstance.allSections[section - 1].name.localized(lang: defaults.string(forKey: "language")!)
sectionLabel.font = UIFont(name: "Centabel Book", size: 25)
sectionLabel.backgroundColor = UIColor.white
sectionLabel.clipsToBounds = true
return sectionLabel
}
If I try to add a button programatically to put it over the tableview
let actionButton = JJFloatingActionButton()
override func viewDidLoad() {
super.viewDidLoad()
// Configuration of the Floating Action Button
actionButton.buttonColor = .red
actionButton.addItem { item in
self.performSegue(withIdentifier: "goToSettings", sender: nil)
}
actionButton.display(inViewController: self)
actionButton.clipsToBounds = true
// This doesn't work. It is to bring the button to the front. Now it is hidden by the sections.
view.bringSubviewToFront(actionButton)
// Checks if the language setting is nil, which means it is the first time you run the application. If then... selects English as default.
if defaults.string(forKey: "language") == nil {
defaults.set("en", forKey: "language")
}
}
... I don't know why but the viewForHeaderInSection hides the button. You can check it in the picture below:
floating button hided by the headersection
I tried to use the method:
view.bringSubviewToFront(actionButton)
and also:
actionbutton.superview?.bringSubviewToFront(actionButton)
But none of this brings the button to the front.
I am using a floating action button from github called JJFloatingActionButton. But I tried to add a simple UIButton and I got the same error. This is the code that also gave me the same error inside viewDidLoad:
let button = UIButton(frame: CGRect(x: 100, y: 1000, width: 100, height: 50))
button.backgroundColor = .green
button.setTitle("Test Button", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
self.view.addSubview(button)
Again the same error. You can check the picture:
adding a simple UIButton happens the same problem
May be you can help me with that.
Thanks in advance.
You could try to use a regular UIViewController (not UITableViewController) and add the UITableView by hand.
Like that you would have better control over the view hierarchy.
My view (in the Main.storyboard) contains another UIView which takes only about 80% of the screen's height (set with constraints).
In this second view (I call it the viewContainer) I want to display different views, which works with
viewContainer.bringSubview(toFront: someView)
I created a new group in my project which contains 3 UIViewController classes and 3 xib files which I want to display in my viewContainer.
For each of those xib files I changed the background color to something unique so I can tell if it's working. And it does so far.
Now I tried adding a UIButton to the first UIViewController class and added an #IBAction for it. That just prints text to the console.
When I run the app I can switch between my 3 classes (3 different background colors) and I can also see and click the button I added to the first class when I select it.
But the code is never executed and my console is empty. Is that because my 3 other Views are not shown in my Main.storyboard?
SimpleVC1.swift
import UIKit
class SimpleVC1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func onButtonPressed(_ sender: Any) {
print("test")
}
}
Try using a target instead (and programmatically create the button), it might be easier:
import UIKit
class SimpleVC1: UIViewController {
var button = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(button)
button.frame.size = CGSize(width: 100, height: 100)
button.center = CGPoint(x: 100, y: 100)
button.setTitle("Control 1", for: .normal)
button.addTarget(self, action: #selector(control1), for: .touchUpInside)
button.backgroundColor = UIColor.blue
button.setTitleColor(UIColor.white, for: .normal)
}
#objc func control1() {
//Add your code for when the button is pressed here
button.backgroundColor = UIColor.red
}
}
Using pod 'Player' in an iOS 9.0 app to play a video. I've subclassed Player class to add a UIButton overlay for closing the window.
It appears fine and has highlighting animation when tapped, but closeTapped isn't called when touching up inside.
import UIKit
import Player
class PlayerViewController: Player, PlayerDelegate {
func install() {
view.frame = presentor.view.bounds
presentor.addChildViewController(self)
presentor.view.addSubview(view)
didMove(toParentViewController: presentor)
let closeImage = UIImage(named: "close")!
let closeButton = UIButton(type: .custom)
view.addSubview(closeButton)
closeButton.setImage(closeImage, for: .normal)
closeButton.autoPinEdge(toSuperviewEdge: .top, withInset: 25)
closeButton.autoPinEdge(toSuperviewEdge: .right, withInset: 15)
closeButton.autoSetDimensions(to: CGSize(width: 50, height: 50))
closeButton.addGestureRecognizer(UITapGestureRecognizer())
closeButton.addTarget(self, action: #selector(closeTapped), for: .touchUpInside)
}
func closeTapped() {
logger.debug("Player close tapped")
}
}
I also tried having closeTapped(sender: Any?), didn't help.
Why isn't closeTapped called?
You don't need to add a TapGestureRecognizer to the button. For swift 3.0 you can do it like this:
button.addTarget(self, action: #selector(closeTapped(sender:)), for: .touchUpInside)
func closeTapped(sender: UIButton) {
}
I think the top of your button u added a UITapGestureRecognizer(). Which itself has a #selector. So Your button default .touchUpInside controller is not calling.
Try with commenting
//closeButton.addGestureRecognizer(UITapGestureRecognizer())
this line.
Let me know is this helpful or not.