UIKit slider always starts at 0 - ios

Here is my slider configuration, see that the minimum value is 1, and the preview in xCode show the slider in the right position.
And this is all my code:
import UIKit
class ViewController: UIViewController {
var currentValue: Int = 50
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func showAlert() {
let message = "The value of the slider is: \(currentValue)"
let alert = UIAlertController(
title: "Hello World!",
message: message,
preferredStyle: .alert)
let action = UIAlertAction(
title: "OK",
style: .default,
handler: nil)
alert.addAction(action)
present(alert, animated: true, completion: nil)
}
#IBAction func sliderMoved(_ slider: UISlider) {
currentValue = lroundf(slider.value)
}
}
I am not changing the value of the slider anywere, I tried to only have a view with an slider and the generated code of the view controller, and it did not work, the slider always starts its position at 0.

Related

swift5 UILabel Clickable

I am learning iOS development. And I want to make UILabel clickable
Here is what I have done but with no result.
#IBOutlet weak var coordinate: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
coordinate.adjustsFontSizeToFitWidth = true
let tap = UIGestureRecognizer(target: self, action: #selector(uiLabelClicked()))
coordinate.addGestureRecognizer(tap)
coordinate.isUserInteractionEnabled = true
Below is a function that is expected to perform an action when label is clicked.
#objc func uiLabelClicked(){
let alert = UIAlertController(title: "Coordinate", message: "I have been clicked...", preferredStyle: .alert)
self.present(alert, animated: true, completion: nil)
debugPrint("clicked")
}
I apologize for my English I am using google translator.
Try this:
#IBOutlet weak var coordinate: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
coordinate.adjustsFontSizeToFitWidth = true
let tap = UITapGestureRecognizer(target: self, action: #selector(self.labelAction(_:)))
coordinate.addGestureRecognizer(tap)
coordinate.isUserInteractionEnabled = true
}
#objc func labelAction(_ sender: UIGestureRecognizer) {
let alert = UIAlertController(title: "Coordinate", message: "I have been clicked...", preferredStyle: .alert)
self.present(alert, animated: true, completion: nil)
debugPrint("clicked")
}

UIImagePickerControllerDelegate not being called, selected image never displayed

I'm stumped. Everything is working except it's not. I can call up the camera interface and take or select a photo yet UIImagePickerControllerDelegate is never being called (I've put two print statements that well, never get printed). Everything is correctly connected in IB, or so I believe it is (I'm fully ready for it so be something totally minor that I missed). Anyone care to take a frtesh set of eyes and go over this to see if I just can't see the forest for the trees?
Thanks in advance.
import UIKit
import Foundation
class afterPhotoViewController: UIViewController {
//MARK: - IBOutlet Properties
#IBOutlet weak var afterImageView: UIImageView!
#IBOutlet weak var aftervwImage: UIView!
#IBOutlet weak var cameraBtnPressed: UIButton!
//MARK: - Useful Variables
let afterImagePicker = UIImagePickerController()
var hud = HKProgressHUD()
var localTextFilePath : URL!
var isImageSetted = false
//MARK: - App Delegates
var isMain = false
var originFrame = CGRect()
override func viewDidLoad() {
super.viewDidLoad()
// Init UI Components
self.initUI()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: - UI Init
func initUI() {
// Set Navigation Bar
let backButton = UIBarButtonItem(title: "", style: .plain, target: navigationController, action: nil)
navigationItem.leftBarButtonItem = backButton
self.title = "\(h_proposalNumberStr)-\(h_itemIndex)"
// Set ImageView
self.afterImageView.image = #imageLiteral(resourceName: "ic_placeholder")
self.afterImageView.clipsToBounds = false
cameraBtnPressed.layer.cornerRadius = 15
cameraBtnPressed.layer.borderColor = UIColor.lightGray.cgColor
cameraBtnPressed.layer.borderWidth = 1
self.isImageSetted = false
// self.tableView.reloadData()
}
//MARK: - UI Actions
#IBAction func cameraBtnPressed(_ sender: Any) {
//Create the AlertController and add Its action like button in Actionsheet
let actionSheetController: UIAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let cancelActionButton = UIAlertAction(title: "Cancel", style: .cancel) { _ in
}
actionSheetController.addAction(cancelActionButton)
let chooseLibraryActionButton = UIAlertAction(title: "Choose from Library", style: .default)
{ _ in
self.isMain = true
self.afterImagePicker.allowsEditing = true
self.afterImagePicker.sourceType = .photoLibrary
self.afterImagePicker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
self.present(self.afterImagePicker, animated: true, completion: nil)
}
actionSheetController.addAction(chooseLibraryActionButton)
let takePhotoActionButton = UIAlertAction(title: "Take a Photo", style: .default)
{ _ in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
self.isMain = true
self.afterImagePicker.allowsEditing = false
self.afterImagePicker.sourceType = .camera
self.afterImagePicker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .camera)!
self.afterImagePicker.showsCameraControls = true
self.present(self.afterImagePicker, animated: true, completion: nil)
} else {
Helper.showMessage(vc: self, title: CONSTANTS.APPINFO.APP_NAME, bodyStr: "No camera available.")
}
}
actionSheetController.addAction(takePhotoActionButton)
self.present(actionSheetController, animated: true, completion: nil)
}
//MARK: - UIImagePickerControllerDelegate
extension afterPhotoViewController: UIImagePickerControllerDelegate,UINavigationControllerDelegate {
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
print("called")
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
print("called2")
//getting actual image
var image = info[UIImagePickerControllerEditedImage] as? UIImage
if image == nil {
image = info[UIImagePickerControllerOriginalImage] as? UIImage
}
afterImageView.image = image
// Set Imageview Corner Radius
afterImageView.layer.cornerRadius = 5
afterImageView.clipsToBounds = true
self.isImageSetted = true
picker.dismiss(animated: true, completion: nil)
}
}
#raja Kishan caught my stupid simple error of forgetting to set the delegate.
Now, where's the facepalm emoji.
You have to specify that the UIImagePickerController's delegate is self, so that the events are triggered.
In your case:
afterImagePicker.delegate = self

How do I present a View Controller with UIView, UIButton sub-classes?

So I have created this UIButton Sub-class. It's a reusable component and can be added in any view controller. I need to present an alert view controller with the tap in the button. So basically I need to find out in which view controller the button lies so I can pass a view controller as a parameter.
final class ProfileButton: UIButton {
let picker = UIImagePickerController()
lazy var shadowImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.image = UIImage(named: "download")
return imageView
}()
override public init(frame: CGRect) {
super.init(frame: frame)
setupSelf()
self.addTarget(self, action: #selector(profileButtonTapped), for: .touchUpInside)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override public func layoutSubviews() {
super.layoutSubviews()
shadowImageView.layer.cornerRadius = self.frame.width/2.70
shadowImageView.layer.masksToBounds = true
}
#objc func profileButtonTapped(){
imageHandler(presenter: )
}
#objc func imageHandler(presenter: UIViewController!){
let alertController = UIAlertController(title: "Profile Picture", message: "Please select your profile picture", preferredStyle: .alert)
let okAction = UIAlertAction(title: "Photo Library", style: .default, handler: { (action: UIAlertAction!) in
print("I am working")
})
let cameraAction = UIAlertAction(title: "Camera", style: .default, handler: { (action: UIAlertAction!) in
print("I am working")
})
alertController.addAction(okAction)
alertController.addAction(cameraAction)
presenter.present(alertController, animated: true, completion: nil)
}
I actually need to find out the view controller so I can pass it in the imageHandler(presenter: UIViewController) function.
In this case you can get the top controller using this extension
extension UIApplication {
class func getTopMostViewController() -> UIViewController? {
let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
if var topController = keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
return topController
} else {
return nil
}
}
}
#objc func imageHandler() {
//...
UIApplication.getTopMostViewController()?.present(alertController, animated: true, completion: nil)
}
You could add a weak var reference to the controller inside your UIButton. Better way would be add the handler function in the UIViewController extension and addTarget in the viewDidLoad instead of the UIButton's init(frame:). Here's an example:
final class ProfileButton: UIButton {
//Remove addTarget from init(frame:)
}
class ViewController: UIViewController {
let profileButton = ProfileButton()
override func viewDidLoad() {
super.viewDidLoad()
//...
profileButton.addTarget(self, action: #selector(imageHandler), for: .touchUpInside)
}
}
extension UIViewController {
#objc func imageHandler() {
let alertController = UIAlertController(title: "Profile Picture", message: "Please select your profile picture", preferredStyle: .alert)
let okAction = UIAlertAction(title: "Photo Library", style: .default, handler: { (action: UIAlertAction!) in
print("I am working")
})
let cameraAction = UIAlertAction(title: "Camera", style: .default, handler: { (action: UIAlertAction!) in
print("I am working")
})
alertController.addAction(okAction)
alertController.addAction(cameraAction)
present(alertController, animated: true, completion: nil)
}
}

How to set the button's action from another view controller

how can I create reusable view controller (let's call it "reusableVC") acting like UIAlertController. ReusableVC have "ok" button, that will act depending from where resuableVC called. I know about delegates and NotificationCenter. Just wondering can we pass what "ok" button should do when creating reusableVC, like this:
reusableVC.addAction(UIAlertAction(title: "", style: .default, handler: { (action) in
// some code
}))
If you only need one OK button you may use this solution, otherwise, you can still find interest in this pattern.
class ReusableVC{
var onOKPressed: ( () -> () )?
// Create all your other things and don't forget that you should call onOKPressed() whenever user pushed that OK button
}
class ViewController{
func setupReusableVC(){
let reusableVC = ReusableVC()
reusableVC.onOKPressed = {
print("ok pressed")
}
}
}
The action handler is just a closure. You can declare it everywhere.
In the reusable view controller add a property
var customAction : ((UIAlertAction) -> Void)?
and pass the property as handler
reusableVC.addAction(UIAlertAction(title: "", style: .default, handler: customAction))
In the source view controller create the action
let action : ((UIAlertAction) -> Void)? = { action in
// do something
}
and pass it in perform(segue
Create a UIViewController Extension to include Alert Functionality
extension UIViewController{
open func hideKeyBoardOnTap(){
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
self.view.addGestureRecognizer(tap)
}
#objc private func dismissKeyboard(){
self.view.endEditing(true)
}
open func showAlertWithOK(_ title: String = "Alert!",message: String = "Please take appropriate action"){
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let okButton = UIAlertAction(title: "Ok", style: .default, handler:{ (alertAction) in
self.okAction()
})
alert.addAction(okButton)
DispatchQueue.main.async {
self.present(alert, animated: true, completion: nil)
}
}
open func showAlertWithOkAndCancel(_ title: String = "Alert!",_ message: String = "Please take appropriate action", _ firstButtonTitle: String = "Ok", _ firstButtonStyle: UIAlertActionStyle = .default, _ secondButtonTitle: String = "Cancel",_ secondButtonStyle: UIAlertActionStyle = .cancel){
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let okButton = UIAlertAction(title: firstButtonTitle, style: firstButtonStyle, handler:{ (alertAction) in
self.okAction()
})
let cancelButton = UIAlertAction(title: secondButtonTitle, style: secondButtonStyle, handler: { (alertAction) in
self.cancelAction()
})
alert.addAction(okButton)
alert.addAction(cancelButton)
self.present(alert, animated: true, completion: nil)
}
#objc private func okAction(){
self.dismiss(animated: true, completion: nil)
}
#objc private func cancelAction(){
self.dismiss(animated: true, completion: nil)
}
}
How to Use
func didReceiveError(_ error: CFNetworkErrors) {
var message = error.message
self.showAlertWithOK("Error", message: message)
}
func didEndWebserviceCall() {
self.showAlertWithOK(message: "didEndWebserviceCall")
}
Advantages:
You can access alert using self(which is your viewcontroller in this case)
Code reusability
Clean code.
protocol TapEventDelegate: protocol {
func buttonTap()
}
class ClassWhereDoYouWantToCatchTheEvent: TapEventDelegate {
func buttonTap() {
print("caught!")
}
}
class YourViewControllerClass {
weak var tapEventDelegate: TapEventDelegate?
reusableVC.addAction(UIAlertAction(title: "", style: .default, handler: { (action) in
tapEventDelegate?.buttonTap()
}))
}
to bind your class with YourViewControllerClass and ClassWhereDoYouWantToCatchTheEvent use somewhere at view controller initialization:
classWhereDoYouWantToCatchTheEvent.tapEventHandler = yourViewControllerClass
You can create custom UIViewController class and pass the addAction closure and then you can call that closure on the OK button tap from your CustomAlertController.
final class CustomAlertController: UIViewController {
var actionHandler: (() -> Void)?
lazy var okButton: UIButton = {
let button = UIButton()
button.backgroundColor = .black
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("OK", for: .normal)
button.addTarget(self, action: #selector(CustomAlertController.didTapOkButton(_:)), for: .touchUpInside)
button.layer.cornerRadius = 10
return button
}()
override func loadView() {
view = UIView()
view.backgroundColor = .white
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
addActionButton()
}
private func addActionButton() {
view.addSubview(okButton)
NSLayoutConstraint.activate([
okButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 50),
okButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -50),
okButton.heightAnchor.constraint(equalToConstant: 50),
okButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 100)
])
}
public func addAction(title: String, handler: #escaping (() -> Void) {
okButton.setTitle(title, for: .normal)
actionHandler = handler
}
#objc func didTapOkButton(_ button: UIButton) {
actionHandler?()
dismiss(animated: true)
}
}
Then you can present CustomAlertController from your ViewController class and add action like below
class ViewController: UIViewController {
override func loadView() {
view = UIView()
view.backgroundColor = .white
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alertController = CustomAlertController()
alertController.addAction(title: "OK", handler: { [unowned self] in
self.view.backgroundColor = .blue
print("OK button tapped")
})
present(alertController, animated: true)
}
}

UIButton not working or gets unrecognized selector sent to instance

I have an odd (at least to me) issue in that I used the pod Localize_Swift to localize my app.
I have two issues that I cannot figure out as nearly all documentation about localizing only covers text on the same vc as the localize menu or button. In my case, I have localize strings set up and across the entire app, they are in use with a .localize suffix.
First issue:
The button either does not work. The print() function never gets triggered or if it does work, appears to be randomly, I get the unrecognized selector sent to instance that lists the func changeLanguage as the cause. I commented out all of the code within the function, but still received the error.
I have also deleted the func and recreated it, but still no go.
Second issue:
How to initialize the localization across the entire app with the strings?
SettingsViewController.swift
import UIKit
import Localize_Swift
class SettingsViewController: UITableViewController
{
var availableLanguages = Localize.availableLanguages()
var actionSheet: UIAlertController!
#IBOutlet weak var switchlangButton: UIButton!
#IBOutlet weak var flagImageView: UIImageView!
override func viewDidLoad()
{
super.viewDidLoad()
let backButton:UIBarButtonItem = UIBarButtonItem(title: "Back".localized, style: UIBarButtonItemStyle.Done, target: self, action: #selector(SettingsViewController.backBtnAction(_:)))
self.navigationItem.leftBarButtonItem = backButton
configureView()
availableLanguages.removeAtIndex(0)
print(availableLanguages)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(SettingsViewController.setTranslatedText), name: LCLLanguageChangeNotification, object: nil)
}
func setTranslatedText(){
switchlangButton.setTitle("Switch Language".localized(), forState: UIControlState.Normal)
flagImageView.image = UIImage(named: "flag-en".localized() + ".png")
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self)
}
#IBAction func changeLanguage(sender: AnyObject) {
print ("changeLanguageButton pressed")
actionSheet = UIAlertController(title: nil, message: "Switch Language".localized(), preferredStyle: UIAlertControllerStyle.ActionSheet)
for language in availableLanguages {
let displayName = Localize.displayNameForLanguage(language)
let languageAction = UIAlertAction(title: displayName, style: .Default, handler: {
(alert: UIAlertAction!) -> Void in
Localize.setCurrentLanguage(language)
})
actionSheet.addAction(languageAction)
}
let cancelAction = UIAlertAction(title: "Cancel".localized(), style: UIAlertActionStyle.Cancel, handler: {
(alert: UIAlertAction) -> Void in
})
actionSheet.addAction(cancelAction)
self.presentViewController(actionSheet, animated: true, completion: nil)
}
func configureView(){
switchlangButton.setTitle("Switch Language".localized(), forState: UIControlState.Normal)
flagImageView.image = UIImage(named: "flag-en".localized() + ".png")
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
#IBAction func backBtnAction(sender:UIBarButtonItem)
{
navigationController?.popViewControllerAnimated(true)
}
}
Screenshot of the Settings scene
Just an FYI for troubleshooting, the image does not work either.

Resources