I am new to programming. Really new and am trying to get the "outputLabel" to fade in when I press the "quoteButtonTapped" button. I have tried to set the alpha to 0.0 and then with a delay to alpha 1.0 but
self.outputLabel.alpha does not work.
Wow! I am perhaps missing something really basic here but the "quoteButtonTapped" does select a random quotation from an array and it's reference label, but how can I get the label text to fade in?
I included code below:
class ViewController: UIViewController {
#IBOutlet weak var outputLabel: UILabel!
#IBOutlet weak var borderImage: UIImageView!
#IBOutlet weak var scrollViewWindow: UIScrollView!
#IBOutlet weak var referenceLabel: UILabel!
#IBAction func quoteButtonTapped(sender: AnyObject) {
scrollViewWindow.contentSize.height = 800
}
override func viewDidLoad() {
super.viewDidLoad()
}
func displayCurrentScripture() {
let range: UInt32 = UInt32(quotes.count)
let randomNumber = Int(arc4random_uniform(range))
let QuoteString = quotes.objectAtIndex(randomNumber)
let ReferenceString = references.objectAtIndex(randomNumber)
self.outputLabel.text = QuoteString as? String
self.referenceLabel.text = ReferenceString as? String
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
UILabel.referenceLabel..
}
displayCurrentScripture()
}
Try This :
override func viewDidLoad() {
super.viewDidLoad()
displayCurrentScripture();
}
func displayCurrentScripture() {
let range: UInt32 = UInt32(quotes.count)
let randomNumber = Int(arc4random_uniform(range))
let QuoteString = quotes.objectAtIndex(randomNumber)
let ReferenceString = references.objectAtIndex(randomNumber)
self.outputLabel.alpha = 0.0
self.referenceLabel.alpha = 0.0
self.outputLabel.text = QuoteString as? String
self.referenceLabel.text = ReferenceString as? String
UIView.animateWithDuration(0.2, animations: { () -> Void in
self.outputLabel.alpha = 1.0
self.referenceLabel.alpha = 1.0
});
}
Related
I have an app where it is a marketplace and when you click on a product, it opens a detail view controller passing the data to display on the DetailVC. Additionally, inside the DetailVC, if you click on a button to claim the product, it segues to another VC to finalize the transaction.
In the DetailVC, there is a back button which is an unwind segue back to the main marketplace VC. Inside the TransactionVC, there is a cancel button which takes you back to the DetailVC.
When I am clicking the backButton in the DetailVC to take me back to the main market VC but I am getting a SIGBART Error and this :
020-07-15 09:05:23.707490-0500 evolutionatx[707:141952] Could not cast value of type 'evolutionatx.MarketplaceViewController' (0x1032c7868) to 'evolutionatx.PopUpPurchaseViewController' (0x1032c7ba8).
Here is the code for the DetailVC
import UIKit
import iCarousel
import CoreData
class MarketDetailViewController: UIViewController, UIScrollViewDelegate, iCarouselDelegate, iCarouselDataSource {
var productImageArray = [UIImage]()
var productVideo = String()
var pointsToPurchase = String()
var productName = String()
var productDescription = String()
var companyLogo = UIImage()
var companyWebsite = String()
var additionalProductImage = [UIImage]()
var companyName = String()
var promoCODE = String()
var buyLink = String()
var slides:[Slide] = [];
//IB
#IBOutlet weak var productNameLabel: UILabel!
#IBOutlet weak var productPriceLabel: UILabel!
#IBOutlet weak var productDescLabel: UILabel!
#IBOutlet weak var claimButton: UIButton!
#IBOutlet weak var imgScrollView: UIScrollView!
#IBOutlet weak var websiteButton: UIButton!
#IBOutlet weak var pageControl: UIPageControl!
#IBOutlet weak var logoDisplay: UIImageView!
#IBOutlet weak var carouselView: iCarousel!
#IBOutlet weak var otherProductslabe: UILabel!
var carouselImages = [UIImage]()
var evoCoin = Int()
override func awakeFromNib() {
super.awakeFromNib()
carouselImages = productImageArray
}
override func viewDidLoad() {
super.viewDidLoad()
valueSetter()
imgScrollView.delegate = self
slides = createSlides()
setupSlideScrollView(slides: slides)
pageControl.numberOfPages = slides.count
pageControl.currentPage = 0
view.bringSubviewToFront(pageControl)
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
pageControl.currentPage = Int(pageIndex)
let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x
// vertical
let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
let currentVerticalOffset: CGFloat = scrollView.contentOffset.y
let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset
}
#IBAction func claimProduct(_ sender: Any) {
print("tap rec")
claimProductandPurchase()
}
func claimProductandPurchase(){
evoCOiner()
if(evoCoin >= Int(pointsToPurchase)!){
print("Transaction Successful")
performSegue(withIdentifier: "proceedQuestion", sender: self)
}
else{
showToast(controller: self, message: "Insufficient EvoCoins", seconds: 0.5)
}
}
func showToast(controller: UIViewController, message : String, seconds: Double) {
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
alert.view.backgroundColor = UIColor.black
alert.view.alpha = 0.6
alert.view.layer.cornerRadius = 15
controller.present(alert, animated: true)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + seconds) {
alert.dismiss(animated: true)
}
}
func evoCoiner(){
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "EvoCoins")
request.returnsObjectsAsFaults = false
do{
let result = try context.fetch(request)
for data in result as! [NSManagedObject]
{
evoCoin = data.value(forKey: "evoCoins") as! Int
}
}catch{
print("Failed")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let detailController = segue.destination as! PopUpPurchaseViewController
detailController.ppromo = promoCODE
detailController.link = buyLink
detailController.coinToPurchase = Int(pointsToPurchase)!
}
//This is the unwind used by the transaction back button
#IBAction func unwindToItem(segue: UIStoryboardSegue) {
}
}
Here is the code in the transaction VC
import UIKit
import AMTabView
import CoreData
class MarketplaceViewController: UIViewController, TabItem {
#IBOutlet weak var sView: UIView!
#IBOutlet weak var evoCoinLabe: UILabel!
//For the sake of simplicity I only kept the Unwind functions
//MARK: - UNWIND FUNCTIONS
#IBAction func unwindToMainMarketView(segue: UIStoryboardSegue) {
}
}
How can I fix this error?
Please advise if my question was not clear or properly phrased (if so, sorry I am pretty new to all of this)
As #matt already said in his comment and the error clearly states, you cannot cast a MarketplaceViewController to a PopUpPurchaseViewController.
Furthermore instead of doing a forced cast, always look for a safe one like below. Doing so will prevent crashes.
if let detailController = segue.destination as? PopUpPurchaseViewController {
...
}
else {
// log failed to cast
}
I am now working on a UITextfield. I hope to know how to add four discontinuous bottom border to a UITextfield, and how to make the space between input digits larger to make them fit exactly on the four lines respectively. Moreover, if possible, how to make the line become black (while other lines remain grey) when users are inputing digit on that line? Thank you so much!
Use following subclass of UITextField and create textfield for each digit either in storyboard or programatically.
Note that each textfield has to set a tag, such as
1st Digit: textField1.tag=1
2nd Digit: textField1.tag=2
3rd Digit: textField1.tag=3
4th Digit: textField1.tag=4
class CustomTextField: UITextField {
private let normalStateColor = UIColor.lightGray.cgColor
private let focusStateColor = UIColor.black.cgColor
private let border = CALayer()
private let borderHeight: CGFloat = 4.0
// MARK:- Init
required init?(coder aDecoder: NSCoder) {
super.init(coder:aDecoder)
setup()
}
override init(frame:CGRect) {
super.init(frame:frame)
setup()
}
override func awakeFromNib() {
super.awakeFromNib()
setup()
}
// MARK:- Overrides
override func layoutSubviews() {
super.layoutSubviews()
let size = self.frame.size
self.border.frame = CGRect(x: 0, y: size.height - borderHeight, width: size.width, height: borderHeight)
}
override func willMove(toSuperview newSuperview: UIView!) {
guard newSuperview != nil else {
NotificationCenter.default.removeObserver(self)
return
}
NotificationCenter.default.addObserver(self, selector: #selector(beginEdit),
name: UITextField.textDidBeginEditingNotification, object: self)
NotificationCenter.default.addObserver(self, selector: #selector(endEdit),
name: UITextField.textDidEndEditingNotification, object: self)
}
#objc func beginEdit() {
border.backgroundColor = self.focusStateColor
}
#objc func endEdit() {
border.backgroundColor = self.normalStateColor
}
private func setup() {
border.backgroundColor = self.normalStateColor
textAlignment = .center
borderStyle = .none
layer.addSublayer(border)
delegate = self
}
}
extension CustomTextField: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField.text!.count < 1 && string.count > 0 {
textField.text = string
textField.superview?.viewWithTag(textField.tag + 1)?.becomeFirstResponder()
return false
} else if textField.text!.count >= 1 && string.count == 0 {
textField.text = ""
textField.superview?.viewWithTag(textField.tag - 1)?.becomeFirstResponder()
return false
}
return true
}
}
That yields
check this..
ViewController.swift
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var txtOne: UITextField!
#IBOutlet weak var txtTwo: UITextField!
#IBOutlet weak var txtThree: UITextField!
#IBOutlet weak var txtFour: UITextField!
#IBOutlet weak var vwFour: UIView!
#IBOutlet weak var vwThree: UIView!
#IBOutlet weak var vwTwo: UIView!
#IBOutlet weak var vwOne: UIView!
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == txtOne {
vwOne.backgroundColor = .black
vwTwo.backgroundColor = .lightGray
vwThree.backgroundColor = .lightGray
vwFour.backgroundColor = .lightGray
} else if textField == txtTwo {
vwTwo.backgroundColor = .black
vwOne.backgroundColor = .lightGray
vwThree.backgroundColor = .lightGray
vwFour.backgroundColor = .lightGray
} else if textField == txtThree {
vwThree.backgroundColor = .black
vwTwo.backgroundColor = .lightGray
vwOne.backgroundColor = .lightGray
vwFour.backgroundColor = .lightGray
} else {
vwFour.backgroundColor = .black
vwTwo.backgroundColor = .lightGray
vwThree.backgroundColor = .lightGray
vwOne.backgroundColor = .lightGray
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
I am getting an error. It is returning nil on a DispatchQueue call.
DispatchQueue.main.async {
self.headerImageView.image = image // <- CRASH
}
Turns out that this is where I am getting a crash.
headerImageView is just a variable which is not connected to the storyboard via IBOutlet. Here is the entire code:
import UIKit
import WebKit
let offset_HeaderStop:CGFloat = 40.0
let offset_B_LabelHeader:CGFloat = 95.0
let distance_W_LabelHeader:CGFloat = 35.0
class MovieDetailsViewController: UIViewController, UIScrollViewDelegate {
var movie: Movie?
var urlBuilder = MovieUrlBuilder()
var config = TMDBConfiguration()
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var headerView: UIView!
#IBOutlet weak var headerLabel: UILabel!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var genreLabel: UILabel!
#IBOutlet weak var ratingLabel: UILabel!
#IBOutlet weak var releaseLabel: UILabel!
#IBOutlet weak var descriptionText: UITextView!
#IBOutlet weak var trailerContainerView: UIView!
#IBOutlet weak var trailerLabel: UILabel!
#IBOutlet weak var videoContainer: WKWebView!
var headerImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
headerImageView = UIImageView(frame: headerView.bounds)
headerImageView.image = UIImage(named: "Poster")
headerImageView.contentMode = .scaleAspectFill
headerView.insertSubview(headerImageView, belowSubview: headerLabel)
headerView.clipsToBounds = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
fetchPopularMovies()
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offset = scrollView.contentOffset.y
var headerTransform = CATransform3DIdentity
if offset < 0 {
let headerScaleFactor: CGFloat = -(offset) / headerView.bounds.height
let headerSizeVariation = ((headerView.bounds.height * (1.0 + headerScaleFactor)) - headerView.bounds.height)/2.0
headerTransform = CATransform3DTranslate(headerTransform, 0, headerSizeVariation, 0)
headerTransform = CATransform3DScale(headerTransform, 1.0 + headerScaleFactor, 1.0 + headerScaleFactor, 0)
headerView.layer.transform = headerTransform
} else {
headerTransform = CATransform3DTranslate(headerTransform, 0, max(-offset_HeaderStop, -offset), 0)
let labelTransform = CATransform3DMakeTranslation(0, max(-distance_W_LabelHeader, offset_B_LabelHeader - offset), 0)
headerLabel.layer.transform = labelTransform
}
headerView.layer.transform = headerTransform
}
override var preferredStatusBarStyle: UIStatusBarStyle{
return UIStatusBarStyle.lightContent
}
private func fetchPopularMovies() {
if let poster = movie?.backdropPath {
let baseURL = URL(string: config.baseImageURL)!
let url = baseURL.appendingPathComponent("w500").appendingPathComponent(poster)
let request = URLRequest(url: url)
let task = urlBuilder.session.dataTask(with: request) {(data, response, error) in
do {
if let image = UIImage(data: data!) {
DispatchQueue.main.async {
self.headerImageView.image = image // <- CRASH
}
}
}
}
task.resume()
}
}
}
Thank you for the support!
You are initializing the image view in viewDidAppear which will be called after viewWillAppear where the image view is populated. Despite the asynchronous task it's not guaranteed that the view is initialized before being populated.
I recommend to initialize the image view lazily, the benefit is that the property is non-optional and it's initialized once when it's accessed the first time.
lazy var headerImageView: UIImageView = {
let view = UIImageView(frame: self.headerView.bounds)
view.image = UIImage(named: "Poster")
view.contentMode = .scaleAspectFill
self.headerView.insertSubview(view, belowSubview: self.headerLabel)
view.clipsToBounds = true
return view
}()
Your async call is located in fetchPopularMovies, which is called at viewWillAppear. You initialise your image view in viewDidAppear, which is called after viewWillAppear.
Basically, headerImageView is nil.
"But I put the call in an async block! So viewDidAppear should have been called already when I set the image view's image, right?" you said.
Well, relying on async to say "I want this thing to run after a certain method returns" is not a good idea. It is not always guaranteed to do that.
To fix this, you need to initialise header image view before fetchPopularMovies is called. You can put it in viewDidLoad for example.
"Optional type Bool cannot be used as a boolean; test for !nil instead"
Is the error I'm getting
I'm trying to make a "slot machine" app, very basic,
You press the UIButton, and the three images should all change, randomly, if the 3 matches, print "You won!"
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var img1: UIImageView!
#IBOutlet weak var img2: UIImageView!
#IBOutlet weak var img3: UIImageView!
#IBOutlet weak var rollBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// 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.
}
#IBAction func onRollPress(sender: AnyObject) {
let randomRoll = ImgArray().getRandomImage()
img1.image = randomRoll
img2.image = randomRoll
img3.image = randomRoll
if (img1.image! == img2 && img3) {
print("You won!")
}
}
}
If your images are in an array, why not get the indexes of the images and compare that. Or you could convert the images to base64 strings and compare those.
Edit: Not knowing much about your ImgArray class, this may work for you:
#IBAction func onRollPress(sender: AnyObject) {
let randomRoll1 = ImgArray().getRandomImage()
let randomRoll2 = ImgArray().getRandomImage()
let randomRoll3 = ImgArray().getRandomImage()
img1.image = randomRoll1
img2.image = randomRoll2
img3.image = randomRoll3
let imgIndex1 = ImgArray().indexOf(randomRoll1)
let imgIndex2 = ImgArray().indexOf(randomRoll2)
let imgIndex3 = ImgArray().indexOf(randomRoll3)
if (imgIndex1 == imgIndex2 && imgIndex3) {
print("You won!")
}
}
When I enter an amount in the text field I get in total the amount in tenths place, so how can I get hundredths place instead of tenths place?
Also how can I get the tip percentage label an integer instead of a decimal?
import UIKit
class ViewController: UIViewController, SettingsDelegate {
//Inputs
#IBOutlet weak var amountTextField: UITextField!
//Labels
#IBOutlet weak var TipPercentageLabel: UILabel!
#IBOutlet weak var numberOfPersonLabel: UILabel!
#IBOutlet weak var tipAmountLabel: UILabel!
#IBOutlet weak var totalBillLabel: UILabel!
#IBOutlet weak var billPerPersonLabel: UILabel!
//Slider & Stepper
#IBOutlet weak var tipSlider: UISlider!
#IBOutlet weak var personsStepper: UIStepper!
//Variables
var tipPercentage : Double = NSUserDefaults.standardUserDefaults().doubleForKey("DefaultTipRate") ?? 0.20
var numberOfPerson:Int = 1
let numberFormatter:NSNumberFormatter = NSNumberFormatter()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tipAmountLabel.text = "$0.00"
totalBillLabel.text = "Bill Total"
billPerPersonLabel.text = "$0.00"
numberOfPersonLabel.text = "1"
self.amountTextField.becomeFirstResponder()
print("DefaultTipRate")
let tipPercentage : Double = NSUserDefaults.standardUserDefaults().doubleForKey("DefaultTipRate")
TipPercentageLabel.text = self.numberFormatter.stringFromNumber(tipPercentage)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setupContainer() {
tipSlider.minimumValue = 0
tipSlider.maximumValue = 100
tipSlider.value = 20
tipSlider.addTarget(self, action: "sliderTipChanged:", forControlEvents: .ValueChanged)
personsStepper.minimumValue = 1
personsStepper.maximumValue = 30
personsStepper.value = 1
personsStepper.addTarget(self, action: "sliderPersonChanged:", forControlEvents: .ValueChanged)
amountTextField.text = ""
refreshCalculation()
}
#IBAction func OnEditingFieldBill(sender: AnyObject) {
refreshCalculation()
}
func refreshCalculation() {
numberFormatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
if let amount = numberFormatter.numberFromString(amountTextField.text!) as? Double {
let tipAmount = amount * tipPercentage
let totalBill = amount + tipAmount
let billPerPerson = totalBill / Double(numberOfPerson)
numberFormatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
tipAmountLabel.text = numberFormatter.stringFromNumber(tipAmount)
totalBillLabel.text = numberFormatter.stringFromNumber(totalBill)
billPerPersonLabel.text = numberFormatter.stringFromNumber(billPerPerson)
} else {
tipAmountLabel.text = "-"
totalBillLabel.text = "-"
billPerPersonLabel.text = "-"
}
numberFormatter.numberStyle = NSNumberFormatterStyle.PercentStyle
numberFormatter.minimumFractionDigits = 2
numberFormatter.maximumFractionDigits = 2
TipPercentageLabel.text = String(format: "%.0f%%", tipPercentage)
numberOfPersonLabel.text = "\(numberOfPerson)"
}
#IBAction func sliderTipChanged(sender: AnyObject) {
tipPercentage = Double(round(tipSlider.value)) / 100
refreshCalculation()
}
#IBAction func StepperPersonChanged(sender: AnyObject) {
numberOfPerson = Int(round(personsStepper.value))
refreshCalculation()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let SettingsViewController = segue.destinationViewController as? SettingsViewController {
SettingsViewController.delegate = self
refreshCalculation()
}
}
func tipPercentageChanged(newValue: Double) {
TipPercentageLabel.text = "\(newValue)%"
tipPercentage = newValue
refreshCalculation()
}
SETTINGS VIEW CODE
import UIKit
protocol SettingsDelegate{
func tipPercentageChanged(newValue : Double)
}
class SettingsViewController: UIViewController {
#IBOutlet weak var tipControl: UISegmentedControl!
var tipRates:Double?
var destName : String!
var delegate :SettingsDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func changeValue(sender: UISegmentedControl) {
var tipRate = [0.05, 0.10, 0.15, 0.20, 0.25, 0.30]
tipRates = (tipRate[tipControl.selectedSegmentIndex])
delegate?.tipPercentageChanged(tipRates!); print("(tipRates)")
NSUserDefaults.standardUserDefaults().setDouble(tipRates!, forKey: "DefaultTipRate")
NSUserDefaults.standardUserDefaults().synchronize()
}
}
Since you are using NSNumberFormatter, set maximumFractionDigits and minimumFractionDigits properties to 2:
let numberFormatter = NSNumberFormatter()
numberFormatter.maximumFractionDigits = 2
numberFormatter.minimumFractionDigits = 2
let str = numberFormatter.stringFromNumber(14.7) // "14.70"
Alternatively, you could use the String(format:) constructor:
let str = String(format: "%.2f", 14.7) // "14.70"
For your tip percentage, since you are storing it as a decimal percentage, you can do:
let tipPercentage: Double = 0.17
TipPercentageLabel.text = String(format: "%.0f%%", tipPercentage * 100) // "17%"