I have two text fields to insert numbers, I am trying to find out how it could work out if the user is just inserting one value in one of the text fields or two. I tried to do it with if statements, but that does not work. Looks also like I have a mistake some where in the code I get the issue: fatal error: unexpectedly found nil while unwrapping an Optional value I would be happy for some help - as you can see I am a beginner in swift coding. Thanks so Far!
#IBOutlet var budgetShow: UILabel!
#IBOutlet var restShow: UILabel!
#IBOutlet var daysShow: UILabel!
#IBOutlet var dayssShow: UILabel!
#IBOutlet var inputDays: UITextField!
#IBOutlet var inputBudget: UITextField!
#IBAction func findResult(sender: AnyObject) {
var inputBudgetInt = inputBudget.text.toInt()
var inputDaysInt = inputDays.text.toInt()
var dailyRate = 85.50
if inputDays != nil {
var days = Double(inputBudgetInt!) / dailyRate
var daysCosts = dailyRate * days
var daysShow = Int(days)
var costsShow = Int(daysCosts)
dayssShow.text = "For \(costsShow) you can stay \(daysShow) Days."
}
if inputBudget != nil {
var budget = dailyRate / Double(inputBudgetInt!)
var budgetShow = Int(budget)
daysShow.text = "You need /(budgetShow)"
}
var daysBudget = Double(inputBudgetInt!) / Double(inputDaysInt!)
var show = daysBudget - dailyRate
var costs = Double(inputDaysInt!) * dailyRate
var rest = Double(inputBudgetInt!) - costs
var could = Double(inputBudgetInt!) / dailyRate
var couldShow = Int(could)
var restedShow = Int(rest)
var costShow = Int(costs)
var dayShow = Int(inputDaysInt!)
if show > 0 {
budgetShow.text = "For \(dayShow) Days you need \(costShow) €"
restShow.text = "Rest Budget after \(dayShow) Days is \(restedShow) €"
daysShow.text = "With your budget you could stay up to \(couldShow) days"
} else {
budgetShow.text = "Change your budget or days"
}
}
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.
}
}
One way to handle optionals safely is if let, like follows:
if let inputBudgetInt = inputBudgetInt {
// safely use it without need for "!" or "?"
var days = Double(inputBudgetInt) / dailyRate
}
This basically means "if this optional has a value, unwrap it and use it here".
I like to keep the name the same personally, you can use a different name if you want.
Another way is using "?", especially good for chaining. If you have a reference to a cell for example:
cell.textField?.text = "Foo"
If textField (optional) has no value, this line silently does nothing.
You should avoid "!" as much as possible as it can easily cause a crash. Only if you are 100% sure it has a value should you risk it. As a beginner I would stick to if let to make sure your optionals have values.
Related
I have three UITextFields that will only contain a whole number between 0 and either 13066 or 3915 maximum. It's presented with a special font where font1 at 50pt is larger than font2 at 50pt so I only need to play around with the font file, not the size.
1) I need help finding a way to have the hundreds presented with font2 but when the number >= 1000, the digits for thousands is presented with font1, while the hundreds still maintain font2. As this is a UITextField input, I need this to happen real-time.
Animated picture of how the end result eventually will be!
2) If you watch the animation, you'll see that each of the three fields totals to the field at the bottom. This is straight forward. However, I also want to reverse this, i.e filling in the total and the dials and digits should fill in as shown (half in each MAIN up to 3920 and remaining in CTR up to 13066). How do I code a functioning reversible calculation like that and avoid conflict?
This is what I got so far but it doesn't quite do what I want yet:
`class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var centerField: UITextField!
#IBOutlet weak var main1Field: UITextField!
#IBOutlet weak var main2Field: UITextField!
#IBOutlet weak var totalField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
//UITextField delegation
centerField.delegate = self
main1Field.delegate = self
main2Field.delegate = self
totalField.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//Change font when number input exceeds 3 digits
func getAttributedString(for number: Int) -> NSAttributedString {
let defaultAttributes = [
NSAttributedStringKey.font: UIFont(name: "PMDG_777_DU_A", size: UIFont.labelFontSize)!
]
let bigNumberAttributes = [
NSAttributedStringKey.font: UIFont(name: "PMDG_777_DU_B", size: UIFont.labelFontSize)!
]
let attributedString = NSMutableAttributedString(string: "\(number)", attributes: defaultAttributes)
if attributedString.length > 3 {
let substr = attributedString.string.dropLast(3)
let range = NSMakeRange(0, substr.utf16.count)
attributedString.setAttributes(bigNumberAttributes, range: range)
}
return attributedString
}
//Hide keyboard when hitting Return
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
//Hide keyboard when tapping outside of field
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
//Real-time calculation of entries made to the fields and output it live to the total
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
//Convert the String inserted into the fields into Int and create variables
let centerFuel = Int(centerField.text!) ?? 0
centerField.attributedText = getAttributedString(for: centerFuel)
let main1Fuel = Int(main1Field.text!) ?? 0
main1Field.attributedText = getAttributedString(for: main1Fuel)
let main2Fuel = Int(main2Field.text!) ?? 0
main2Field.attributedText = getAttributedString(for: main2Fuel)
let total: Int = centerFuel + main1Fuel + main2Fuel
totalField.attributedText = getAttributedString(for: total)
return true
}
Use NSMutableAttributedString:
func getAttributedString(for number: Int) -> NSAttributedString {
precondition(number >= 0)
let defaultAttributes = [
NSAttributedStringKey.font: UIFont.systemFont(ofSize: 18)
]
let bigNumberAttributes = [
NSAttributedStringKey.font: UIFont.systemFont(ofSize: 30)
]
let attributedString = NSMutableAttributedString(string: "\(number)", attributes: defaultAttributes)
if attributedString.length > 3 {
let range = NSMakeRange(0, attributedString.length - 3)
attributedString.setAttributes(bigNumberAttributes, range: range)
}
return attributedString
}
Then set the attributedText property on your label:
label.attributedText = getAttributedString(for: 13006)
And you can get result like this:
Adjust the styles to taste!
Here is a sample solution:
func attributedString(fromIntStr: String) -> NSAttributedString {
print("Working with: \(fromIntStr)")
let finalAttr = NSMutableAttributedString.init()
let length = fromIntStr.count
if length > 3 //we test this because we can't do dropLast(n) where n is negative
{
let start = String(fromIntStr.dropLast(3))
let firstPart = NSAttributedString.init(string: start,
attributes: [.font: UIFont.systemFont(ofSize: 20)])
finalAttr.append(firstPart)
}
var dropEnd = 0
if length > 3 //we test this because we can't do dropFirst(n) where n is negative
{
dropEnd = length - 3
}
else
{
dropEnd = 0 //That's just an explicit value but it was already set by default
}
let end = String(fromIntStr.dropFirst(dropEnd))
let lastPart = NSAttributedString.init(string: end,
attributes: [.font: UIFont.systemFont(ofSize: 15)])
finalAttr.append(lastPart)
//It seems that you want a right alignement and since we are using NSAttributedString we can do it by using ParagraphStyle
let paragraphStyle = NSMutableParagraphStyle.init()
paragraphStyle.alignment = .right
finalAttr.addAttribute(.paragraphStyle,
value: paragraphStyle,
range: NSRange(location: 0, length: finalAttr.length))
return finalAttr
}
It can be tested on Playground adding this at the end:
let values = ["", "9", "89", "789", "6789", "56789"]
let view = UIView.init(frame: CGRect(x: 0, y: 0, width: 800, height: 400))
for (i, str) in values.enumerated().reversed()
{
let label = UILabel.init(frame: CGRect(x: 0, y: i*50, width: 800, height: 50))
let attr = attributedString(fromIntStr: str)
label.attributedText = attr
view.addSubview(label)
}
view
There are various way to do this but here is the logic I used:
• Create a NSMutableAttributedString.
• Separate the string in two strings (one for 0-999, the other one for the rest)
• Create from them two NSAttributedString with the corresponding font
• Append them to the NSMutableAttributedString previously created.
Of course this could be improved:
Is dropFirst()/dropLast() the best solutions?
I supposed that you add already a String value from a Int (I didn't do the conversion).
Another solution more classic would have been:
• Create a NSMutableAttributedString from the whole String.
• Apply small font on range last from last-3
• Apply big font on range start to last -3
Last point be ommited if you apply the big font from the start on the whole string.
I have scrollView in which if there is no data, I need to hide (collapse the space occupied by it) so that the lower view can come upwards.
I tried this code with no luck. Please help me.
if(dataForScroll==0){
var newFrame:CGRect = self.myScroll.frame;
newFrame.size.height = 0;
self.myScroll.frame = newFrame
}
A simple example with Swift 3 version, i think it might be solves your problem. Let me know if have any queries
#IBOutlet var mainScrollView: UIScrollView!
#IBOutlet var view1: UIView!
#IBOutlet var view2: UIView!
#IBOutlet var view3: UIView!
var data1 = NSArray()
var data2 = NSArray()
var data3 = NSArray()
func setFrame()
{
// data = Something you need to get
if data1.count == 0
{
self.view1.frame.size.height = 0
}
else
{
// return its actual height you need
}
if data2.count == 0
{
self.view2.frame.size.height = 0
}
else
{
// return its actual height you need
}
if data3.count == 0
{
self.view3.frame.size.height = 0
}
else
{
// return its actual height you need
}
var frame = self.view1.frame
frame.origin.y = 5
self.view1.frame = frame
frame = self.view2.frame
frame.origin.y = self.view1.frame.origin.y + self.view1.frame.size.height + 5
self.view2.frame = frame
frame = self.view3.frame
frame.origin.y = self.view2.frame.origin.y + self.view2.frame.size.height + 5
self.view3.frame = frame
var scrollHeight:CGFloat = 0.0
var contentRect:CGRect = CGRect.zero
for views in self.mainScrollView.subviews
{
let subView:UIView = views
contentRect = contentRect.union(subView.frame)
print(subView.frame.size.height)
scrollHeight = scrollHeight + subView.frame.size.height
}
self.mainScrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: scrollHeight + 20) // the "+ 20" reamains the spaces between the views, you can change as per your need
}
I have an array of CGPoints. I need a personal label for every fourth point in array, so I need to create several NSTextFields programmatically. I can add points with mouse clicks and can create as many points as I wish. Labels for these points must be all active to show text for user simultaneously. How can I do it?
(macOS, Xcode 7, Swift 2)
Here's my code:
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var drawView: DrawView!
#IBOutlet weak var view: NSView!
let label = NSTextField(frame: NSMakeRect(0,0,100,50))
var pointsArray: [CGPoint] = []
func applicationWillUpdate(aNotification: NSNotification) {
label.backgroundColor = NSColor.clearColor()
label.bezeled = false
label.stringValue = "\(pointsArray.count/4)"
var multiple = (1...25).map { _ in label }
for index in 0..<(pointsArray.count/4) {
let point = CGPoint(x: pointsArray[index*4].x, y: pointsArray[index*4].y)
label.frame = CGRect(origin: point, size: CGSize(width: label.bounds.width, height: label.bounds.height))
let sticker = multiple[index]
view.addSubview(sticker)
}
}
}
At runtime I see only one label but I need to see several labels simultaneously (on every fourth CGPoint). If I have 100 CGPoints I must have 25 labels.
I see only one label
Now that I've straightened out your curly braces and indentation, it's easy to see why. Your loop is incorrectly constructed, so that you create one label and change its frame four times. You need to create four separate labels with four separate frames.
Code for creating several NSTextFields:
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var drawView: DrawView!
var pointsArray: [CGPoint] = []
var label1 = NSTextField(frame: NSMakeRect(0,0,100,50))
var label2 = NSTextField(frame: NSMakeRect(0,0,100,50))
var label3 = NSTextField(frame: NSMakeRect(0,0,100,50))
// ....................................................
var label25 = NSTextField(frame: NSMakeRect(0,0,100,50))
override func awakeFromNib() {
super.awakeFromNib()
var labelArray = [label1, label2, label3, ....., label25]
for i in 0 ..< (pointsArray.count / 4) {
labelArray[i].backgroundColor = NSColor.clearColor()
labelArray[i].bezeled = false
labelArray[i].stringValue = "\(i + 1)"
let point = CGPoint(x: (pointsArray[i * 4].x),
y: (pointsArray[i * 4].y))
var originPoint: [CGPoint] = []
originPoint.append(point)
labelArray[i].frame = .init(origin: originPoint[0],
size: CGSize(width: labelArray[i].bounds.width,
height: labelArray[i].bounds.height))
self.view.addSubview(labelArray[i])
}
}
}
I have multiple UITextFields and I'm making the same changes to the border, radius and color.
#IBOutlet weak var answer1Text: UITextField!
#IBOutlet weak var answer2Text: UITextField!
#IBOutlet weak var answer3Text: UITextField!
#IBOutlet weak var answer4Text: UITextField!
#IBOutlet weak var answer5Text: UITextField!
self.answer1Text.layer.cornerRadius = 5
self.answer1Text.layer.borderWidth = 2
let borderColor = UIColor(colorLiteralRed: 125.0/255.0, green:210.0/255.0, blue: 238.0/255.0, alpha: 1.0)
self.answer1Text.layer.borderColor = borderColor.CGColor
Repeating the code five times for each textfield is very inefficient. I was thinking a for loop would be the best solution but I can't figure out how to replace the int in the text field name. For example,
for var i = 0; i < 6; i++ {
self.answer1Text.layer.cornerRadius = 5 // Not sure how to replace the 1 here
}
If a for loop is the best solution, how do you do so? If not, what's the best way to implement?
Thanks!
You need to store all your answerTexts to NSArray and loop through this array. In iteration of loop you can reach to your UITextField object from an array by index and set your properties:
var answerTextsArray = [self.answer1Text, self.answer2Text, self.answer3Text, self.answer4Text, self.answer5Text]
for var i = 0; i < answerTextsArray!.count; i++ {
var myTextField = answerTextsArray[i]
myTextField.layer.cornerRadius = 5
myTextField.layer.borderWidth = 2
let borderColor = UIColor(colorLiteralRed: 125.0/255.0, green: 210.0/255.0, blue: 238.0/255.0, alpha: 1.0)
myTextField.layer.borderColor = borderColor.CGColor
}
Okay so I have 4 images, and they are named in sequence 'colour1.jpg', colour2.jpg, 'colour3.jpg', 'colour4.jpg'. Each of these images will act as a button background image.
The idea is there are 4 buttons on the screen, and each time one of the buttons is pressed, the images all change randomly on each of the buttons.
I am using the arc4random_uniform to randomise the images. But it doesn't work, at the moment, if the user presses one of the buttons, a random image is chosen, but it is identical across all 4 buttons. and then it won't ever change from that image. ie. if you press the same or another button, nothing happens. It just remains on the previous image.
I am new to swift so appreciate your patience with me, but would really like to learn where I'm going wrong.
class InterfaceController: WKInterfaceController {
#IBOutlet var blueColour: WKInterfaceButton!
#IBOutlet var pinkColour: WKInterfaceButton!
#IBOutlet var greenColour: WKInterfaceButton!
#IBOutlet var yellowColour: WKInterfaceButton!
var randomImageA1 = arc4random_uniform(4)
var randomImageA2 = arc4random_uniform(4)
var randomImageA3 = arc4random_uniform(4)
var randomImageA4 = arc4random_uniform(4)
var randomImageB1 = arc4random_uniform(4)
var randomImageB2 = arc4random_uniform(4)
var randomImageB3 = arc4random_uniform(4)
var randomImageB4 = arc4random_uniform(4)
var randomImageC1 = arc4random_uniform(4)
var randomImageC2 = arc4random_uniform(4)
var randomImageC3 = arc4random_uniform(4)
var randomImageC4 = arc4random_uniform(4)
var randomImageD1 = arc4random_uniform(4)
var randomImageD2 = arc4random_uniform(4)
var randomImageD3 = arc4random_uniform(4)
var randomImageD4 = arc4random_uniform(4)
#IBAction func onePressed() {
blueColour.setBackgroundImageNamed("colour\(randomImageA1).jpg")
pinkColour.setBackgroundImageNamed("colour\(randomImageA2).jpg")
greenColour.setBackgroundImageNamed("colour\(randomImageA3).jpg")
yellowColour.setBackgroundImageNamed("colour\(randomImageA4).jpg")
}
#IBAction func twoPressed() {
blueColour.setBackgroundImageNamed("colour\(randomImageB1).jpg")
pinkColour.setBackgroundImageNamed("colour\(randomImageB2).jpg")
greenColour.setBackgroundImageNamed("colour\(randomImageB3).jpg")
yellowColour.setBackgroundImageNamed("colour\(randomImageB4).jpg")
}
#IBAction func threePressed() {
blueColour.setBackgroundImageNamed("colour\(randomImageC1).jpg")
pinkColour.setBackgroundImageNamed("colour\(randomImageC2).jpg")
greenColour.setBackgroundImageNamed("colour\(randomImageC3).jpg")
yellowColour.setBackgroundImageNamed("colour\(randomImageC4).jpg")
}
#IBAction func fourPressed() {
blueColour.setBackgroundImageNamed("colour\(randomImageD1).jpg")
pinkColour.setBackgroundImageNamed("colour\(randomImageD2).jpg")
greenColour.setBackgroundImageNamed("colour\(randomImageD3).jpg")
yellowColour.setBackgroundImageNamed("colour\(randomImageD4).jpg")
}
You are only calling randomImage = arc4random_uniform(5) one time. If that function randomly chooses an image for you, then you need to call it before every call to setBackgroundImage()
Your success of randomness will also depend on how you are randomizing your image within randomImage = arc4random_uniform(5). Hard to say whether that will always return the same image or not without seeing your implementation of randomness.
Example:
#IBOutlet var blueColour: WKInterfaceButton!
#IBOutlet var pinkColour: WKInterfaceButton!
#IBOutlet var greenColour: WKInterfaceButton!
#IBOutlet var yellowColour: WKInterfaceButton!
var randomImage
#IBAction func onePressed() {
randomImage = arc4random_uniform(4)
blueColour.setBackgroundImageNamed("colour\(randomImage).jpg")
randomImage = arc4random_uniform(4)
pinkColour.setBackgroundImageNamed("colour\(randomImage).jpg")
randomImage = arc4random_uniform(4)
greenColour.setBackgroundImageNamed("colour\(randomImage).jpg")
randomImage = arc4random_uniform(4)
yellowColour.setBackgroundImageNamed("colour\(randomImage).jpg")
}