I am a beginner so bear with me.
I created a basic timer app and rounded the corners of two buttons. The button was still clickable outside of the circle, I needed to fix that so I found a solution online that said to insert the code into the UIButton's subclass or extension. I found solutions for both ways and chose extension option because the code was easier to read and I could understand it better.
The issue now is that I have a third UIButton that is being affected by the extension and I would like to exclude it. I'm not sure if this is even practical (or possible) so please correct me if there is a better way to approach this. The button I need to exclude from the extension is resetButton.
import UIKit
extension UIButton {
open override func draw(_ rect: CGRect) {
self.layer.cornerRadius = 50.0
self.layer.masksToBounds = true
//exclude resetButton???
}
private var touchPath: UIBezierPath {return UIBezierPath(ovalIn: self.bounds)}
open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return touchPath.contains(point)
}
}
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var startButton: UIButton!
#IBOutlet weak var stopButton: UIButton!
#IBOutlet weak var resetButton: UIButton!
var timeRemaining: Int = 10
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//// Moved to an extension in order to
//// remove the clickable areas outside
//// of the circle
//startButton.layer.cornerRadius = 50.0
//stopButton.layer.cornerRadius = 50.0
}
#IBAction func start(_ sender: Any) {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(step), userInfo: nil, repeats: true)
}
#IBAction func stop(_ sender: Any) {
timer?.invalidate()
}
#IBAction func reset(_ sender: Any) {
timer?.invalidate()
timeRemaining = 10
label.text = "\(timeRemaining)"
}
#objc func step() {
if timeRemaining > 0 {
timeRemaining -= 1
} else {
timer?.invalidate()
}
label.text = "\(timeRemaining)"
}
}
For your case, extension is not the right option as the methods invoked from extension will apply to the type itself (all UIButton objects in this case).
One option for you is to make a subclass of UIButton instead of extension. Something like this:
class RoundedButton: UIButton {
open override func draw(_ rect: CGRect) {
self.layer.cornerRadius = 50.0
self.layer.masksToBounds = true
}
private var touchPath: UIBezierPath {return UIBezierPath(ovalIn: self.bounds)}
open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return touchPath.contains(point)
}
}
And hence you can select the buttons that should inherit the custom layout from the class above:
#IBOutlet weak var startButton: RoundedButton!
#IBOutlet weak var stopButton: RoundedButton!
#IBOutlet weak var resetButton: UIButton! // Will not get the style applied for startButton and stopButton
Related
I was creating animations for buttons using extension in swift but when i call the animation function it generates error.
import UIKit
extension UIButton{
func wiggle() {
let wiggleAnim = CABasicAnimation(keyPath: "psoition")
wiggleAnim.duration = 0.05
wiggleAnim.repeatCount = 5
wiggleAnim.autoreverses = true
wiggleAnim.fromValue = CGPoint(x: self.center.x - 4.0, y: self.center.y)
wiggleAnim.toValue = CGPoint(x: self.center.x + 4.0, y: self.center.y)
layer.add(wiggleAnim, forKey: "position")
}
}
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var colorizeBtn: UIButton!
#IBOutlet weak var wiggleBtn: UIButton!
#IBOutlet weak var dimBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func colorizeBtnWasPressed(_ sender: Any) {
}
#IBAction func wiggleBtnWasPressed(_ sender: Any) {
wiggleBtn.wiggle()
}
#IBAction func dimBtnwasPressed(_ sender: Any) {
}
}
View Controller
Your wiggleBtn is of type UIView but you write an extension to UIButton.
Either change the extension to UIView or change the type of wiggleBtn to UIButton.
I've found a few threads here about this, and some videos online about it as well, but every solution seems to have problems reported by others. The simplest solution I've found is the one below.
import UIKit
class SignupController: UIViewController, UITextFieldDelegate {
// Outlets
#IBOutlet weak var logoImage: UIImageView!
#IBOutlet weak var nameTF: CustomTextField!
#IBOutlet weak var emailTF: CustomTextField!
#IBOutlet weak var passwordTF: CustomTextField!
#IBOutlet weak var confirmPassTF: CustomTextField!
// Actions
#IBAction func signupButton(_ sender: UIButton) {
}
override func viewDidLoad() {
super.viewDidLoad()
logoImage.image = UIImage(named: "logo2")
nameTF.delegate = self
emailTF.delegate = self
passwordTF.delegate = self
confirmPassTF.delegate = self
}
// Moves to next text field each time return key is pressed
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField == nameTF {
textField.resignFirstResponder()
emailTF.becomeFirstResponder()
} else if textField == emailTF {
textField.resignFirstResponder()
passwordTF.becomeFirstResponder()
} else if textField == passwordTF {
textField.resignFirstResponder()
confirmPassTF.becomeFirstResponder()
}else if textField == confirmPassTF {
textField.resignFirstResponder()
}
return true
}
// Dismisses keyboard when tapped
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
}
It works, is very simple, but my project and coding experience are in their infancy, so I'm not sure if this is the best method simply because it's short, or if there's something I'm missing due to lack of experience/knowledge?
Anybody know of a better solution, or is this one just fine?
just do this:
class viewController: UIViewController, UITextFieldDelegate {
// Outlets
#IBOutlet weak var logoImage: UIImageView!
#IBOutlet weak var nameTF: CustomTextField!
#IBOutlet weak var emailTF: CustomTextField!
#IBOutlet weak var passwordTF: CustomTextField!
#IBOutlet weak var confirmPassTF: CustomTextField!
// Actions
#IBAction func signupButton(_ sender: UIButton) {
}
override func viewDidLoad() {
super.viewDidLoad()
logoImage.image = UIImage(named: "logo2")
nameTF.delegate = self
emailTF.delegate = self
passwordTF.delegate = self
confirmPassTF.delegate = self
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dissMissKeyboard))
view.addGestureRecognizer(tap)
}
func dissMissKeyboard() {
view.endEditing(true)
}
I prefer to use UITextField delegate method:
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
view.endEditing(true)
return true
}
or setup inputAccessoryView which have 'done' or 'exit' button.
Then you need to implement the gesture recognition for this . Or you can do like this :
override func viewDidLoad() {
super.viewDidLoad()
//Looks for single or multiple taps.
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dissMissKeyboard))
//Uncomment the line below if you want the tap not not interfere and cancel other interactions.
//tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
//Calls this function when the tap is recognized.
func dissMissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}
I'm currently developing a counter app which every time you press a button it will count up. I have already done this and works 100%, what I'm trying to do is make a another button and when you press it, it shows the current number on the console but it only prints out 0 because that's the default variable I assigned the value to.
My whole class:
var counterNumber = 0
#IBOutlet weak var counterLabel: UILabel!
func initCount(){
counterNumber = 0
}
func numberUp(){
self.counterNumber++;
counterLabel.text = "\(self.counterNumber)"
}
#IBAction func CountUp(sender: UIButton) {
numberUp()
}
#IBAction func RestartButton(sender: UIButton) {
initCount()
}
#IBAction func printButton(sender: UIButton) {
self.numberUp();
print(self.counterNumber)
}
override func viewDidLoad() {
super.viewDidLoad()
initCount()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Just call method numberUp in printButton: action.
var counterNumber = 0//this is a variable of class
#IBOutlet weak var counterLabel: UILabel!
#IBAction func printButton(sender: UIButton) {
self.numberUp();
print(self.counterNumber)
}
func numberUp(){
self.counterNumber++;
counterLabel.text = "\(self.counterNumber)"
}
Use 'self' keyword to call instance variables.
class ViewController: UIViewController {
// Properties
var counterNumber:Int = 0 // Make this variable Global to Class
// IBOutlets Properties
#IBOutlet weak var counterLabel: UILabel!
#IBAction func printButton(sender: UIButton) {
self.numberUp()
self.counterLabel.text = "\(self.counterNumber)"
print("\n You Pressed ==> \(sender.title) button \(self.counterNumber) times")
}
func numberUp() {
self.counterNumber += 1
self.counterLabel.text = "\(counterNumber)"
}
}
I've done plenty of searching but am not finding the answer to my question.
My two UITextFields fields are resetting using the clear function. The UILabel retains the original value from the printWatts function, doesn't clear. Would appreciate any advice to resolve this small issue as I learn Swift. Thanks!
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var inputFeet: UITextField!
#IBOutlet weak var inputWatts: UITextField!
#IBOutlet weak var resultsLabel: UILabel!
var stripFeet = ""
var wattValue = ""
var totalWatts : Float = 0.0
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func submitButton(sender: AnyObject) {
calculateWatts()
}
#IBAction func clearButton(sender: AnyObject) {
clear()
}
func calculateWatts() {
if let stripFeet = inputFeet.text,
wattValue = inputWatts.text,
fstripFeet = Float(stripFeet),
fwattValue = Float(wattValue){
totalWatts = fstripFeet * fwattValue
}
printWatts()
}
func printWatts() {
let formatWatts = String(format: "%0.2f", totalWatts)
resultsLabel.text = "Total watts: \(formatWatts)"
}
func clear(){
inputFeet.text = ""
inputWatts.text = ""
self.resultsLabel.text = ""
}
}
Thanks to #Eendje for suggesting that I check my connections. I had the submit and clear actions both connected to my submit button. Option drag is too convenient. All good now.
I need to develop custom UISlider using swift. The problem is I don't know how to make sure label following slider's thumbnail like following below:
My code so far
import Foundation
import UIKit
class Slider: UISlider {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.layer.borderColor = UIColor.redColor().CGColor
self.layer.borderWidth = 0.2
self.tintColor = UIColor.redColor()
}
}
Probably is worth to take a look at this method, this can't be called directly but you can use it while subclassing
func thumbRectForBounds(_ bounds: CGRect,
trackRect rect: CGRect,
value value: Float) -> CGRect
More info also on this question and here
I had the exact thing for audio files.
The protocol is used to inform the player when user changes the value of the slider.
func updateSliderPosition(position: Float)
is called every half second by the player to change position of the slider current value.
import UIKit
protocol AudioSliderControlDelegate: class
{
func audioSliderControlDdiChangeValue(sender: AudioSliderControl, value: Float)
}
class AudioSliderControl: UIControl
{
#IBOutlet weak var slider: UISlider!
#IBOutlet weak var currentPositionLabel: UILabel!
#IBOutlet weak var totalDurationLabel: UILabel!
weak var delegate: AudioSliderControlDelegate?
private var totalLenght: Double?
override func awakeFromNib()
{
super.awakeFromNib()
backgroundColor = UIColor.clevooOrange()
slider.addTarget(self, action: "sliderValueChanged:", forControlEvents: .ValueChanged)
self.addSeperatorToTop()
}
//MARK:
//MARK: - Setup
func setupForDuration(duration: Double)
{
totalLenght = duration
currentPositionLabel.text = Double(0).formattedDuration()
totalDurationLabel.text = (duration + 0.5).formattedDuration()
slider.setValue(0, animated: false)
}
func updateSliderPosition(position: Float)
{
self.currentPositionLabel.text = (totalLenght! * Double(position)).formattedDuration()
self.slider.value = position
}
//MARK:
//MARK: - Notification
func sliderValueChanged(slider: UISlider)
{
self.currentPositionLabel.text = (totalLenght! * Double(slider.value)).formattedDuration()
delegate?.audioSliderControlDdiChangeValue(self, value: slider.value)
}
}