How do I count and display current line number on iOS - ios

I created two UITextView. One for line numbers and one for editing. However I can't seem to get the former to display line count. Here's what I've written so far and I'm sure I've made a mistake, just unsure where.
var previousRect = CGRectZero
var lineArray = ["1"]
func textViewDidChange(textView: UITextView) {
let pos = editorView.endOfDocument
let currentRect = editorView.caretRectForPosition(pos)
if(currentRect.origin.y > previousRect.origin.y){
//new line reached, write your code
var i = 0
i += 1
lineArray.append("\(i)")
let numberOfLinesString = "\(lineArray)"
lineNumbering.text = "\(lineArray)\n"
}
previousRect = currentRect
}

Related

How do I check if the same key exists in an Array?

I am trying to make a RPG game in IOS, with a similar dialogue system in Baldurs Gate. I have created two arrays in a plist file. Like this:
As you can see I have two arrays: PlayerMessage; a list (it will be) of multiple choices that the player can touch and NPCMessages; the text that is displayed when the PlayerMessage is touched
I am at the stage where I can touch on the NPC and it will display a black box (NPCMessageer node) with text from the array (PlayerMessage via the plist file).
However, I don't know how to connect Item 0 in PlayerMessage and NPC Message and if they exist change the Message: SKLabelNode! text to one in NPCMessage. Does anyone know how to compare if another item exist in another array?
Here is the code that I have used:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
for touch in (touches) {
NPC.name = "NPC"
let Location = touch.location(in: self)
var CorrectedLocation = CGPoint()
CorrectedLocation.x = Location.x - LocalCamera.position.x
CorrectedLocation.y = Location.y - LocalCamera.position.y
let node = self.atPoint(CorrectedLocation)
var Message: SKLabelNode!
Message = SKLabelNode(fontNamed: "Trebuchet MS")
if (node.name == "NPC") {
let NPCMessageer = SKSpriteNode (color: UIColor.black, size: CGSize(width:1000, height:1000))
NPCMessageer.zPosition = 99
NPCMessageer.position = CGPoint(x:-500, y:-200)
Message.fontSize = 50
Message.color = UIColor.white; Message.position = CGPoint(x:-500, y:-100)
Message.zPosition = 100
addChild(NPCMessageer)
self.addChild(Message)
for PlayerMessage in NPC.PlayerMessage {
Message.text = PlayerMessage as?String}
let label = self.atPoint(CorrectedLocation)
if label.name == "Message"
{
if NPC.PlayerMessage == NPC.NPCMessage
{
Message.text = NPC.NPCMessage as?String
}
If I understand correctly you want to find a given element from one array in another array.
You can then use firstIdex(of:) and if an element exist use the returned index to set the Message object
let item = PlayerMessage[0] //assuming this is what you want to find
if let index = NPCMessage.firstIndex(of: item) {
let Message.text = NPCMessage[index]
}

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

How not to show 0´s in label?

I have some buttons that print some text in a label when pushed. I also have a counter in front of the text to show how many times the respective button is pushed. But if some of the buttons isn´t pushed, it shows 0 in the label. Is it possible to convert the initial value on the int to blank space?
I have tried something like this:
var addCount:int = 0
var blankSpace = ""
if addCount == 0 {
addcount = blankSpace
}
else {
....
}
I have also tried:
if addCount == 0 {
addCount = String (blankSpace)
}
else {
}
and I have tried:
if addCount == 0 {
addCount = String ("")
}
I´m probably going about this all wrong, and I would appreciate help with this.
*
*
*
Edit: I thought there was some magic trick in swift to make the 0 disappear, so I took some shortcuts when I asked my question. Here is the whole setup:
I have four buttons in View Controller 1 that prints some text and adds 1 to counter. The data is based through a Swift file allSum.
The label that displays the text and counter is in View Controller 2.
allSum:
import UIKit
class allSum: NSObject {
var btn1Pressed:String = ""
var addToBtn1:Int = 0
var btn2Pressed:String = ""
var addToBtn2:Int = 0
var btn3Pressed:String = ""
var addToBtn3:Int = 0
var btn4Pressed:String = ""
var addToBtn4:Int = 0
func printToLabel() -> String{ //return a string with the current status
return ("\(addToBtn1) \(btn1Pressed + "")") + ("\(addToBtn2) \(btn2Pressed + "")") + ("\(addToBtn3) \(btn3Pressed + "")") + ("\(addToBtn4) \(btn4Pressed + "")")
}
View Controller 1
var total = allSum
var button1 = "Button 1 Pressed\n"
var button2 = "Button 2 Pressed\n"
var button3 = "Button 3 Pressed\n"
var button4 = "Button 4 Pressed\n"
#IBAction func no1(_ sender: UIButton) {
total.btn1Pressed = button1
toal.addToBtn1 += 1
}
#IBAction func no2(_ sender: UIButton) {
total.btn2Pressed = button2
toal.addToBtn2 += 1
}
#IBAction func no3(_ sender: UIButton) {
total.btn3Pressed = button3
toal.addToBtn3 += 1
}
#IBAction func no4(_ sender: UIButton) {
total.btn4Pressed = button4
toal.addToBtn4 += 1
}
View Controller 2
var total = allSum?
label.text = total.printToLabel()
With this setup, the label is showing 0 0 0 0 when no buttons are pressed.
So, my problem is that I can't set the label.text = "" since I also have other variables printed to it.
Sorry for my initial laziness
Set the actual label text as a blank space.
var addCount:Int = 0
var blankSpace = ""
if addCount == 0 {
yourlabel.text = blankSpace
} else {
yourlabel.text = "\(addCount)"
}
UPDATED:
Here's a way to write your current code with less code and fix your issue of changing 0's to blank strings
AllSum
class AllSum {
var sumsArray: [Int] = [0,0,0,0]
func stringForLabel() -> String { //return a string with the current status
var string = ""
for (index, value) in self.sumsArray.enumerated() {
if value > 0 {
string = string + "\(value) Button \(index + 1) was pressed\n"
}
}
return string
}
}
View Controller 1
You can use tags in UIBuilder, to match the indices in your array. Link up all buttons to the same function
var total = AllSum()
#IBAction func numberPressed(_ sender: UIButton) {
total.sumsArray[sender.tag] = sumsArray[sender.tag] + 1
}
View Controller 2
var total = AllSum()
label.text = total.stringForLabel()
You won't be able to assign a string, i.e. "", to a variable you've declared as an Int. In this case you'd be better off dealing with this at the time that you set the text on the label. You can use a simple if/else statement, or a ternary operator if you want a one-liner:
if addCount == 0 {
self.label.text = ""
} else {
self.label.text = "\(addCount)"
}
And for the ternary option:
self.label.text = addCount == 0 ? "" : "\(addCount)"
You're trying to set an Int to a String. Swift is a type safe language and doesn't let you do that. If you need, for some reason, to have the same variable represent both states, you can use an enum with an associated value and still use it as long as it is Describable.
Instead you can just have a computed value that returns a String that returns a blank String if the variable is zero:
func displayCount () -> String {
return addCount == 0 ? String() : String(describing:addCount)
}

Type of expression is ambiguous | SpringyCollectionViewFlowLayout

As described in this UICollectionViewFlowlayout, Step 1:
// Need to overflow our actual visible rect slightly to avoid flickering.
var visibleRect = CGRectInset(self.collectionView!.bounds, -100, -100)
var itemsInVisibleRectArray: NSArray = super.layoutAttributesForElementsInRect(visibleRect)!
var itemsIndexPathsInVisibleRectSet: NSSet = NSSet(array: itemsInVisibleRectArray.valueForKey("indexPath") as [AnyObject])
// Step 1: Remove any behaviours that are no longer visible.
var noLongerVisibleBehaviours = (self.dynamicAnimator.behaviors as NSArray).filteredArrayUsingPredicate(NSPredicate(block: {behaviour, bindings in
var currentlyVisible: Bool = itemsIndexPathsInVisibleRectSet.member((behaviour as UIAttachmentBehavior).items.first!.indexPath) != nil
return !currentlyVisible
}))
"Type of expression is ambiguous without more context" .. what should I do? I am really stuck :/
Thank you for any help I can get on this...
If anyone might just want to solve this problem, look here:
let visibleRect = CGRectInset(self.collectionView!.bounds, -100, -100)
let itemsInVisibleRect = super.layoutAttributesForElementsInRect(visibleRect)!
let indexPathsInVisibleRect = Set(itemsInVisibleRect.map({ (attribute) -> NSIndexPath in
return attribute.indexPath
}))
// Step 1: Remove any behaviours that are no longer visible.
let noLongerVisisbleBehaviors = self.dynamicAnimator.behaviors.filter { (eachBehavior) -> Bool in
var currentlyVisible = false
if let behavior = eachBehavior as? UIAttachmentBehavior, first = behavior.items.first as? UICollectionViewLayoutAttributes {
currentlyVisible = indexPathsInVisibleRect.contains(first.indexPath)
}
return !currentlyVisible
}
Thankfully, this has proven to be a truly a huge save for the day :}

Usage for plotAreaViewPointForPlotPoint in CorePlot 1.5.1

I'm trying to add something like UIPopoverController into the barPlot with coreplot 1.5.1 and swift. Like this one Core Plot: How to present popover from a bar selected by the user
So we need to know the point where the selected bar is ,But looks like some functions are different, like plotAreaViewPointForPlotPoint. In 1.5.1, there are two parameters:
And I'm try to find the right way to use it but failed, here is my code:
func barPlot(plot: CPTBarPlot!, barWasSelectedAtRecordIndex idx: UInt, withEvent event: UIEvent!) {
// Remove all the annotations
graphView.hostedGraph.plotAreaFrame.plotArea.removeAllAnnotations()
// Setup a style for the annotation
let hitAnnotationTextStyle = CPTMutableTextStyle.textStyle() as! CPTMutableTextStyle
hitAnnotationTextStyle.color = CPTColor.whiteColor()
hitAnnotationTextStyle.fontSize = 12.0;
hitAnnotationTextStyle.fontName = FONT_HEITI;
// Determine point of symbol in plot coordinates
let anchorPoint = [Int(idx),0]
// Add annotation
// First make a string for the y value
let string = "\(idx),values is:\(mArray.objectAtIndex(Int(idx)))"
// Now add the annotation to the plot area
let textLayer = CPTTextLayer(text: string, style: hitAnnotationTextStyle)
// popview, DxPopover is something like UIPopover Controller in iPhone
var popView = DXPopover()
annotationLabel.text = string
var pointers = [NSDecimal](count: 2, repeatedValue: CPTDecimalFromUnsignedInteger(0))
pointers[0] = CPTDecimalFromUnsignedInteger(idx)
var plotPointer: UnsafeMutablePointer<NSDecimal> = UnsafeMutablePointer<NSDecimal>.alloc(pointers.count)
plotPointer.initializeFrom(pointers)
var popPoint = graphView.hostedGraph.defaultPlotSpace.plotAreaViewPointForPlotPoint(plotPointer, numberOfCoordinates: idx)
popView.showAtPoint(popPoint, popoverPostion: DXPopoverPosition.Down, withContentView: self.annotationView, inView: graphView)
// selectedBarAnnotation = CPTPlotSpaceAnnotation(plotSpace: graphView.hostedGraph.defaultPlotSpace, anchorPlotPoint: anchorPoint)
// selectedBarAnnotation!.contentLayer = textLayer
// selectedBarAnnotation!.displacement = CGPointMake(0.0, -15.0)
// graphView.hostedGraph.plotAreaFrame.plotArea.addAnnotation(selectedBarAnnotation)
}
And it will crush at this line:
var popPoint = graphView.hostedGraph.defaultPlotSpace.plotAreaViewPointForPlotPoint(plotPointer, numberOfCoordinates: idx)
SO, HOW CAN I GET THE RIGHT CGPOINT?
Thanks very much!
=================EDIT===================
I change my codes to this, and can get the right point, Thanks to #Bannings
var popView = DXPopover()
annotationLabel.text = string
var pointers = [NSDecimal](count: 2, repeatedValue: CPTDecimalFromUnsignedInteger(0))
let plotXvalue = self.numberForPlot(plot, field: UInt(CPTScatterPlotFieldX.value), recordIndex: idx)
pointers[0] = CPTDecimalFromFloat(plotXvalue.floatValue)
println("\(CPTDecimalFromUnsignedInteger(idx))")
let plotspace = graphView.hostedGraph.defaultPlotSpace
println("\(plotspace.numberOfCoordinates)")
var popPoint = plotspace.plotAreaViewPointForPlotPoint(&pointers, numberOfCoordinates: plotspace.numberOfCoordinates)
popView.showAtPoint(popPoint, popoverPostion: DXPopoverPosition.Down, withContentView: self.annotationView, inView: graphView)
Try this:
var popPoint = graphView.hostedGraph.defaultPlotSpace.plotAreaViewPointForPlotPoint(&pointers, numberOfCoordinates: idx)

Resources