I have a custom class called colorChangerViewClass that inherits from UIView:
class colorChangerViewClass: UIView {
#IBOutlet weak var controller: ViewController!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// I want to change a textLabel in the main ViewController based on the current finger position here!
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// And here aswell!
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { ... }
func setColor(color: UIColor) {
self.backgroundColor = color
}
}
Inside the touchesBegan and touchesMoved methods I want to change a textLabel in the main ViewController (a different one) based on the current finger position.
What is the best way to establish communication between the two classes colorChangerViewClass and ViewController?
In your case you are trying to communicate child to parent, there are several ways from which you can gain desired out put.
1.Delegation
2. Notification
3. Passing Parent instance object to child (similar as delegate)
I am demonstrating with delegate, you can use delegation as:-
1. Declare
Declare a protocol somewhere out side your ColorChangerViewClass
protocol ColorChangerViewClassDelegate:class {
func fingerDidMoved()
}
2. Create delegate var inside your ColorChangerViewClass
class ColorChangerViewClass: UIView {
//declare delegate var
weak var delegate:ColorChangerViewClassDelegate?
#IBOutlet weak var controller: ViewController!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// I want to change a textLabel in the main ViewController based on the current finger position here!
self.notify()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
self.notify()
// And here aswell!
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
func setColor(color: UIColor) {
self.backgroundColor = color
}
func notify() {
if let delegate = self.delegate {
delegate.fingerDidMoved()
}
}
}
3. Set Delegate of your view to the controller
class SomeVC:UIViewController,ColorChangerViewClassDelegate {
var myLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
//your view
let theView = ColorChangerViewClass() // you might need auto layout or frame declared on your view to define view size
theView.delegate = self
}
//MARK:-deleate method of view
func fingerDidMoved() {
// set text from here
self.myLabel.text = "Your text"
}
}
You are too close to solve the problem, you need to set the reference of your ViewController to controller property of your colorChangerViewClass. Also no need to declare controller as outlet so change its declaration like below.
var controller: ViewController?
Now in touchesBegan and touchesMoved use this controller to access textLabel
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.controller?.textLabel.text = //set text
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
self.controller?.textLabel.text = //set text
}
Now in your ViewController class where you are creating object of colorChangerViewClass set the controller property of it.
#IOutlet var colorView: colorChangerViewClass!
//set controller property in viewDidLoad
colorView.controller = self
Note: class name always start with Uppercase letters so it would be better if you changed your class name to ColorChangerViewClass from colorChangerViewClass.
Related
newbie swift programmer here that needs help with something that probably is trivial...
This is in different File, different View:
class CanvasContainerView: UIView {
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// here are all of the calculations that lead to scoreString being calculated..
var scoreString = round(1000 * accuracyTotal / angleTotal)
}
//lots of other code
}
I need the value of my calculated "scoreString" to be accessible in a different file, different controller. How can i pass this value through if i'm using TouchesMoved function ? Below is how i tried to implement it in different file but failed miserably as there is no "scoreString" in scope:
import UIKit
class CanvasMainViewController: UIViewController {
#IBOutlet weak var ScoreText: UITextField!
/// Prepare the drawing canvas.
/// - Tag: CanvasMainViewController-viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
ScoreText.text = "\(CanvasContainerView.touchesMoved(scoreString))"
}
//lots of code
}
In the end i want my score to be displayed on top of the screen:
So i am aware that there are questions like this already on Stack but whats specific about my question is that im using this "touchesMoved" overriden function that doesn't let me return any value. It shouts it needs void return type.
I will be very thankful for any help.
Using a delegate is the good method :
// the protocol (ie the method called by container view in the controller)
protocol CanvasContainerViewDelegate {
func scoreUpdate(fromView view:CanvasContainerView, newScore: Double)
}
class CanvasContainerView: UIView {
// the delegate that will be called
var delegate: CanvasContainerViewDelegate?
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// here are all of the calculations that lead to scoreString being calculated..
var scoreString = round(1000 * accuracyTotal / angleTotal)
// Telling the delegate the new score value
delegate?.scoreUpdate(fromView: self, newScore: scoreString)
}
//lots of other code
}
class CanvasMainViewController: UIViewController, CanvasContainerViewDelegate {
#IBOutlet weak var ScoreText: UITextField!
#IBOutlet weak var containerView: CanvasContainerView!
/// Prepare the drawing canvas.
/// - Tag: CanvasMainViewController-viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
// set the controller as a delegate of the view
containerView.delegate = self
}
// Update the score (called by the view)
func scoreUpdate(fromView view: CanvasContainerView, newScore: Double) {
ScoreText.text = "\(newScore)"
}
//lots of code
}
Apparently adding public in front of the var declared on top of the file solved the problem. Thank you for participation in trying to help me.
I have custom view that should be clicked and do some action.
I have two CustomView in same screen. I want to detect which one is clicked to do different action.
Is it possible to set some ids there to detect which one is clicked exactly?
Here is my CustomView
protocol CostomViewDelegate: class {
func viewClicked()
}
class CostomView: UIView, UIGestureRecognizer {
#IBOutlet weak var placeholderlbl: UILabel!
#IBOutlet weak var textLbl: UILabel!
weak var delegate: CostomViewDelegate?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.layer.backgroundColor = UIColor.red.cgColor
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.layer.backgroundColor = UIColor.white.cgColor
delegate?.viewClicked()
}
}
If you want to use delegation, then you should change your delegate function so that the view provides a reference to itself to the delegate.
protocol CostomViewDelegate: class {
func costomView(clicked: CostomView)
}
class CostomView: UIView, UIGestureRecognizer {
#IBOutlet weak var placeholderlbl: UILabel!
#IBOutlet weak var textLbl: UILabel!
weak var delegate: CostomViewDelegate?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.layer.backgroundColor = UIColor.red.cgColor
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.layer.backgroundColor = UIColor.white.cgColor
delegate?.costomView(clicked: self)
}
}
Then in your delegate function you can compare the value of the passed reference or other properties in order to take the appropriate action:
func costomView(clicked: CostomView) {
if clicked == self.costomView1 {
// Do something
} else if clicked == self.costomView2 {
// Do something else
}
}
You could also add a property to your CostomView class that holds a closure and invoke that closure when the view is tapped. This is, perhaps, a more "modern" approach, but delegation is still valid and how you do it is a matter of opinion. Personally, one advantage I see for delegation is when viewingthe code you can quickly locate the delegate function in a class, while a closure may be less obvious.
The best way to do it - define touch behaviour for your CostomView, from parent class or view controller for example with closures. The fastest (but pretty ugly) way - set different tags for these views and code different behaviour for different tags.
I have a slider sliderLineSize and a variable lineSize in a ViewController. The UISlider sliderLineSize changes lineSize. However, lineSize actually used in the drawRect section of the viewLine class which attaches to a UIView.
Question:
How do I pass or make accessible the variable lineSize which is set in the ViewController to the class viewLine where it is used in drawRect?
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var myView: UIView!
#IBOutlet weak var myImageView: UIImageView!
var lineSize: Int = 1
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
myImageView.alpha = 0.5
}
#IBAction func sliderLineSize(sender: UISlider) {
lineSize = Int(sender.value)
}
}
class viewLine: UIView {
let path=UIBezierPath()
var incrementalImage:UIImage?
var previousPoint:CGPoint = CGPoint.zero
var strokeColor:UIColor?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect) {
incrementalImage?.drawInRect(rect)
path.lineWidth = lineSize
path.stroke()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
path.moveToPoint(currentPoint)
previousPoint=currentPoint
self.setNeedsDisplay()
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
let midPoint = self.midPoint(previousPoint, p1: currentPoint)
path.addQuadCurveToPoint(midPoint,controlPoint: previousPoint)
previousPoint=currentPoint
path.moveToPoint(midPoint)
self.setNeedsDisplay()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.drawBitmap()
self.setNeedsDisplay()
path.removeAllPoints()
}
func midPoint(p0:CGPoint,p1:CGPoint)->CGPoint {
let x=(p0.x+p1.x)/2
let y=(p0.y+p1.y)/2
return CGPoint(x: x, y: y)
}
func drawBitmap() {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 1)
strokeColor?.setStroke()
if((incrementalImage) == nil){
let rectPath:UIBezierPath = UIBezierPath(rect: self.bounds)
UIColor.whiteColor().setFill()
rectPath.fill()
}
incrementalImage?.drawAtPoint(CGPointZero)
path.stroke()
incrementalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
There are two main ways to do this.
Option 1:
Give your ViewLine class its own lineSize property:
class ViewLine: UIView {
var lineSize = 1
}
Give ViewController a reference to ViewLine, and use a property observer to update the property inside viewLine whenever it changes in ViewController:
class ViewController: UIViewController {
// v~~~ be sure to connect this outlet in interface builder
#IBOutlet weak var viewLine: ViewLine!
var lineSize = 1 {
didSet {
viewLine.lineSize = lineSize
}
}
}
Now your ViewLine class will have its own lineSize property that can be accessed from within its drawRect method directly.
Option 2:
Give your ViewLine class a reference to ViewController:
class ViewLine: UIView {
// v~~~ be sure to connect this outlet in interface builder
#IBOutlet weak var controller: ViewController!
}
Now, in your drawRect method, replace path.lineWidth = lineSize with path.lineWidth = controller.lineSize.
Basically, one of your classes needs a reference to the other in order for them to be able to communicate.
You should make Singleton Model class. A singleton class can be accessed from anywhere. Here is how you should create a singleton class in swift.
class ApplicationModel {
class var sharedInstance: ApplicationModel {
get {
struct Static {
static var instance: ApplicationModel? = nil
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token, {
Static.instance = ApplicationModel()
})
return Static.instance!
}
}
var lineSize = 1
}
Inside ViewController
override func viewDidLoad() {
super.viewDidLoad()
//Instantiate ApplicationModel
//GET
let lineSize = ApplicationModel.sharedInstance.lineSize
//SET
ApplicationModel.sharedInstance.lineSize = 5
}
Inside viewLine
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//Access Application Model
//GET
let lineSize = ApplicationModel.sharedInstance.lineSize
//SET
ApplicationModel.sharedInstance.lineSize = 5
}
Hope this helps!
I was trying to create a function in order to put keyboard away by clicking outside of the keyboard or return key within the keyboard, but unfortunately it only worked when I clicked outside of the keyboard, it doesn't work to press the return key in the keyboard.
import UIKit
class ViewController: UIViewController,UITextFieldDelegate {
#IBOutlet var numberEnter: UITextField!
#IBAction func findButton(sender: AnyObject) {
resultLabel.text = numberEnter.text
}
#IBOutlet var resultLabel: UILabel!
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.
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
func textFieldShouldReturn(textField:UITextField) -> Bool{
textField.resignFirstResponder()
return true
}
}
If you haven't set the delegate for your text field you will need to do that. You can set the delegate in Interface Builder or in code. See this StackOverflow answer for an example: Text Field Should Return, is this correct for ios7?
I am trying to move my UITextView to the upper half of the screen when the user taps it to begin editing. Then, when the user is done, the UITextView will return to the original position. When I run the code and tap the UITextView, the it moves to the new position but then immediately returns. What am I not doing to get the UITextField to remain in the new position until the user is finished editing? I am using Xcode 7.0.1 and Swift2. Thank you.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate {
#IBOutlet var textViewField: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
textViewField.layer.cornerRadius = 10
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
func textViewDidBeginEditing(textView: UITextView) {
UIView.animateWithDuration(1) { () -> Void in
self.textViewField.center = CGPointMake(self.textViewField.center.x, self.textViewField.center.y + 400)}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}