Pictures in the label (Swift) - ios

I have code to display the history in the calculator but the signs (+, -, ×, ÷) are taken from the "case" (Photo 1)
How can I make it so that in the history the signs (+, -, ×, ÷) are displayed by the pictures I have set (Photo 2)
#IBAction func equalitySignPressed(sender: UIButton) {
if stillTyping {
secondOperand = currentInput
}
dotIsPlaced = false
addHistory(text: operationSign + displayResultLabel.text!)
switch operationSign {
case "+":
operateWithTwoOperands{$0 + $1}
case "-":
operateWithTwoOperands{$0 - $1}
case "×":
operateWithTwoOperands{$0 * $1}
case "÷":
operateWithTwoOperands{$0 / $1}
default: break
}
}
History:
func addHistory(text: String){
//Add text
resultLabelText.text = resultLabelText.text! + "" + text
}

You can make your symbols images and use NSTextAttachment to construct a NSAttributedAtring that replaces the text in your string with the corresponding NSTextAttachment with your symbol image. Here is an example playground that does it with one image, but you can easily add more images to the dictionary to replace all of the other symbols with images:
import PlaygroundSupport
import UIKit
class V: UIViewController {
let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(label)
label.textColor = .red
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let expression = "5 + 5"
let plusAttachment = NSTextAttachment()
plusAttachment.image = UIImage(named: "star.png")
let plusString = NSAttributedString(attachment: plusAttachment)
let substitutions: [Character: NSAttributedString] = ["+": plusString]
let attributedExpression = NSMutableAttributedString()
for character in expression {
if let substitution = substitutions[character] {
attributedExpression.append(substitution)
} else {
attributedExpression.append(NSAttributedString(string: String(character)))
}
}
label.attributedText = attributedExpression
label.sizeToFit()
}
}
PlaygroundPage.current.liveView = V()

I suggest you get an emoji font that displays mathematical signs with a border around them. Use that font to create NSAttributedStrings and set it as the label's attributedText.
As to how to use custom fonts, you can refer to here or just search on SO. There are lots of questions about this topic.
I also see that you want the text to be bold, that can be done with attributed strings as well.
Alternatively, you can add those cool math signs as attachments to NSAttributedStrings, but I doubt it's easy to get the sizes correct.

Related

Update output as user types in textfield

I have code to sum four text fields and output the total in a label. Currently the code sums the fields after finishing editing, that is, selecting another text field. Is there a way to sum the text fields as the user types?
#IBAction func TankFuelChanged(_ sender: Any) {
let leftMainTankQuantityValue = Int(leftMainTankQuantity.text ?? "") ?? 0
let rightMainTankQuantityValue = Int(rightMainTankQuantity.text ?? "") ?? 0
let auxTankQuantityValue = Int(auxTankQuantity.text ?? "") ?? 0
let tailTankQuantityValue = Int(tailTankQuantity.text ?? "") ?? 0
let total = leftMainTankQuantityValue + rightMainTankQuantityValue + auxTankQuantityValue + tailTankQuantityValue
totalFuelLoad.text = "\(total)"
What you are looking for is an event triggered when text field changes. You can drag an action from storyboard or you can add them programmatically by using addTarget similar to UIButton but need to use event editingChanged. Check the following code:
var allTextFields: [UITextField] {
return [leftMainTankQuantity, rightMainTankQuantity, auxTankQuantity, tailTankQuantity]
}
override func viewDidLoad() {
super.viewDidLoad()
allTextFields.forEach { $0.addTarget(self, action: #selector(onTextFieldChange), for: .editingChanged) }
}
#objc private func onTextFieldChange() {
updateResult()
}
private func updateResult() {
let strings: [String] = allTextFields.compactMap { $0.text } // Will remove all nil texts
let integers: [Int] = strings.compactMap { Int($0) } // Will remove all non-integer texts
let sum = integers.reduce(0, { $0 + $1 }) // Will compute a sum
print(sum) // TODO: update your result here
}
A method must be marked #objc because of the #selector next to that I hope code speaks for itself.

Randomized String & UIImageView together

I'm working on an app which lets users have randomized data when you shake your device.
I have 4 arrays to hold the string data and function which creates randomized number;
let characters = ["Zoolog", "Xander"]
let problems = ["Asteroid", "Dr Evil"]
let places = ["Vast Desert", "Ice Caves"]
let time = ["Wednesday 12th, 1220", "1236"]
func randomCharacter() -> String {
let randomNumber = GKRandomSource.sharedRandom().nextInt(upperBound: characters.count)
return characters[randomNumber]
}
func randomPlaces() -> String {
let randomNumberOne = GKRandomSource.sharedRandom().nextInt(upperBound: places.count)
return places[randomNumberOne]
}
func randomProblems() -> String {
let randomNumberTwo = GKRandomSource.sharedRandom().nextInt(upperBound: problems.count)
return problems[randomNumberTwo]
}
func randomTime() -> String {
let randomNumberThree = GKRandomSource.sharedRandom().nextInt(upperBound: time.count)
return time[randomNumberThree]
}
On my viewController, data is randomized and users get a randomized data on their screen once they shake their devices.
override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
if(event?.subtype == UIEventSubtype.motionShake) {
characterName.text = myStoryCharacters.randomCharacter()
placeName.text = myStoryCharacters.randomPlaces()
problemName.text = myStoryCharacters.randomProblems()
timeName.text = myStoryCharacters.randomTime()
}
}
I also have an imageView for the character picture. So once the data is randomized I would like my users to see the characters and their names as well. But at the moment, I can only randomize the imageView and characters separately not together.
I've gone through some sample codes but couldn't understand how to approach this.
--Updated
Note: I don't have a problem with the code I have. I don't know how to randomize the characterImageView to match with the characterName. So if a picture belongs to a character in my character array then the nameLabel and imageView should match.
override func viewDidLoad() {
super.viewDidLoad()
super.becomeFirstResponder()
// Do any additional setup after loading the view, typically from a nib.
characterImageView.image = UIImage(named: "elegantEmma")
placeImageView.image = UIImage(named: "zombieLand")
problemImageView.image = UIImage(named: "meteor")
timeImageView.image = UIImage(named: "time")
//First random value shown on the launch
characterName.text = myStoryCharacters.randomCharacter()
placeName.text = myStoryCharacters.randomPlaces()
problemName.text = myStoryCharacters.randomProblems()
timeName.text = myStoryCharacters.randomTime()
You need to store the image names in arrays as well, so for example for your characters have...
let characters = ["Zoolog", "Xander"]
let characterImages = ["ZoologImage", "XanderImage"] // These relate to the image names in your assets
func randomCharacter() -> String {
let randomNumber = GKRandomSource.sharedRandom().nextInt(upperBound: characters.count)
characterImageView.image = UIImage(named: characterImages[randomNumber])
return characters[randomNumber]
}
Then do the same for the other arrays, you could also change the random functions to set the text and not bother returning it, unless of course you need it for something else

History in calculator (Swift)

I have code for running the history in the application.
My app screenshot:
How can I improve it so that the numbers are displayed immediately when pressed (as shown in the video), and not just by pressing =.
// Connected to button "="
#IBAction func equalitySignPressed(sender: UIButton) {
if stillTyping {
secondOperand = currentInput
}
dotIsPlaced = false
addHistory(text: operationSign + displayResultLabel.text!)
switch operationSign {
case "+":
operateWithTwoOperands{$0 + $1}
case "-":
operateWithTwoOperands{$0 - $1}
case "×":
operateWithTwoOperands{$0 * $1}
case "÷":
operateWithTwoOperands{$0 / $1}
default: break
}
}
func addHistory(text: String){
//Add text
resultLabelText.text = resultLabelText.text! + "" + text
}
One option could be to define a separate variable for the label string that is constantly updated using calls to addHistory() after every UIButton press (number or operator), and then the updating of the label itself handled by didSet inside the variable definition:
var resultLabelString: String = "" {
didSet {
self.resultLabelText.text = self.resultLabelText.text! + "" + resultLabelString
}
}
func addHistory(text: String){
self.resultLabelString = text
}

How do I set up the buttons that are linked to didPressNumber to add to each other when pressed

How do I set up the buttons that are linked to didPressNumber to add to each other when pressed so lets say its a calculator and I want set it up where each button is pressed has a letter and number value when it is pressed it adds to the previous one press and I want to set up 2 labels one displaying the number value and one displaying the letter value and how would I set up the value of each number?
enum modes {
case not_set
case addition
case subtraction
case equals
}
#IBAction func didPressNumber(_ sender: UIButton) {
let stringValue:String? = sender.titleLabel?.text
if (lastButtonWasMode) {
lastButtonWasMode = false
labelString = "0"
}
labelString = labelString.appending(stringValue!)
updateText()
}
func updateText() {
guard let labelInt:Int = Int(labelString) else {
return
}
if (currentMode == .not_set) {
savedNum = labelInt
}
let formatter: NumberFormatter = NumberFormatter()
formatter.numberStyle = .decimal
let num:NSNumber = NSNumber(value: labelInt)
label.text = formatter.string(from: num)
}
func changeMode(newMode:modes) {
if (savedNum == 0) {
return
}
currentMode = newMode
lastButtonWasMode = true
}

Make Clickable UILabel Using Swift

I want to Set Particular Word clickable in UILabel text using Swift.
Is it possible?
If more than one label is here how can I detect which word is pressed?
You can not do with the simple label.
There is library available in the github.
https://github.com/TTTAttributedLabel/TTTAttributedLabel
From this you can use the method called yourLabel.addLinkToURL()
class ViewController: UIViewController , TTTAttributedLabelDelegate{
#IBOutlet var lbl: TTTAttributedLabel!
override func viewDidLoad() {
super.viewDidLoad()
var str : NSString = "Hello this is link"
lbl.delegate = self
lbl.text = str as String
var range : NSRange = str.rangeOfString("link")
lbl.addLinkToURL(NSURL(string: "http://github.com/mattt/")!, withRange: range)
}
func attributedLabel(label: TTTAttributedLabel!, didSelectLinkWithURL url: NSURL!) {
UIApplication.sharedApplication().openURL(url)
}
}
SWIFT 3.0
privacyLabel.delegate = self
let strPolicy : NSString = "Agree to the Terms & Conditions"
privacyLabel.text = strPolicy as String
let range1 : NSRange = strPolicy.range(of: "Terms & Conditions")
privacyLabel.addLink(to: URL(string: "http://Terms.com")!, with: range1)
func attributedLabel(_ label: TTTAttributedLabel!, didSelectLinkWith url: URL!) {
print("url \(url)")
// UIApplication.sharedApplication().openURL(url)
}
I'd like to share my library https://github.com/psharanda/Atributika
It contains modern replacement of TTTAtributedLabel + powerful set of methods to detect and style different stuff like tags, hashtags, mentions etc (everything of that can be clickable)
Some code to show how it works:
let link = Style
.font(.boldSystemFont(ofSize: 14))
.foregroundColor(.black)
.foregroundColor(.red, .highlighted)
let tos = link.named("tos")
let pp = link.named("pp")
let all = Style
.font(.systemFont(ofSize: 14))
.foregroundColor(.gray)
let text = "<tos>Terms of Service</tos> and <pp>Privacy Policy</pp>"
.style(tags: tos, pp)
.styleAll(all)
let tosLabel = AttributedLabel()
tosLabel.textAlignment = .center
tosLabel.attributedText = text
tosLabel.onClick = { label, detection in
switch detection.type {
case .tag(let tag):
switch tag.name {
case "pp":
print("Privacy Policy clicked")
case "tos":
print("Terms of Service clicked")
default:
break
}
default:
break
}
}
view.addSubview(tosLabel)

Resources