Swift 4 how to know delete key is pressed when UITextField becomes first responder? - uitextfield

I've searched for the answer, it's all about using shouldChangeCharactersInRange function of UITextFieldDelegate. It works for most cases. But what if UITextField is already empty,shouldChangeCharactersInRange method is not called any more when click delete button. Any help appreciated.

This can be done using multiple methods(not straight though!). One is to put an invisible button over it, or by subclassing UITextField and adding it as a custom class of the desired textfield. Then override the method deleteBackward. This method will catch all the backspace events.
Subclass UITextField:
// MyTextField.swift
import UIKit
protocol MyTextFieldDelegate {
func textFieldDidDelete()
}
class MyTextField: UITextField {
var myDelegate: MyTextFieldDelegate?
override func deleteBackward() {
super.deleteBackward()
myDelegate?.textFieldDidDelete()
}
}
Implementation:
// ViewController.swift
import UIKit
class ViewController: UIViewController, MyTextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// initialize textField
let input = MyTextField(frame: CGRect(x: 50, y: 50, width: 150, height: 40))
// set viewController as "myDelegate"
input.myDelegate = self
// add textField to view
view.addSubview(input)
// focus the text field
input.becomeFirstResponder()
}
func textFieldDidDelete() {
print("delete")
}
}

Related

I want to use it as a UIButton when I tap UITextField

I created a custom keyboard screen on tvOS.
If possible, tap on UITextField as it is, I want to transition to the custom keyboard view.
But tapping the UITextField always displays the system keyboard.
What should I do now?
1) Make the view controller implement this delegate: UITextFieldDelegate
class YourViewController: UIViewController, UITextFieldDelegate {
// ...
yourTextField.delegate = self
// ...
}
2) Return false in textFieldShouldBeginEditing, so the text field doesn't respond and the keyboard doesn't open. Instead, open yours or do whatever you want.
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
// HERE, open your keyboard or do whatever you want
return false
}
textField.inputView = UIView()
class YourViewController: UIViewController,UITextFieldDelegate { }
First set your delegate for textfieldtextField.delegate = self, Then
func textFieldDidBeginEditing(_ textField: UITextField) {
textField.addTarget(self, action: #selector(gettextFieldFunction), for: UIControlEvents.touchDown)
}

add UITextField to sprite kit

hi I've been following some tutorials but this ones for swift 1.2
I'm on Xcode 7.2 think its swift 2.1
he uses a UITextfield with spriteKit
but this line causes an error
I've googled but can't find any help
so thought this is the place to help cheers
self.view!.addSubview(TextInput!)
the whole code is
import SpriteKit
class GameScene: SKScene
{ var TextInput:UITextField?
override func didMoveToView(view: SKView)
{
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
myLabel.text = ""
myLabel.fontSize = 15
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
self.addChild(myLabel)
TextInput?.frame = CGRect(x: 200, y: 300, width: 100, height: 40)
self.view!.addSubview(TextInput!)
TextInput?.backgroundColor = UIColor.whiteColor()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches
{
let location = touch.locationInNode(self)
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
} }
You don't seem to be initialising your UITextField anywhere.
Try adding this line to didMoveToView before you set the frame of TextInput:
self.TextInput = UITextField()
Just to note, variable names in Swift should be written in camel case (thisIsCamelCase), so it might be better to rename your variable as textInput. I can't actually find this in the Apple documentation right now, but this convention is used in all of Apple's example code, and is stated by various other sources, e.g.
https://github.com/raywenderlich/swift-style-guide
http://andybargh.com/variables-and-constants-in-swift/#Rules_for_Naming_Variables

Replace NSViewController under Swift2 Storyboard MAC OSX

I am new to Mac OSX and with Apple promoting the fact that the bodies of code are becoming similar decided to tell the folk I am writing code for we should be able to do a Mac OSX version. iPhone and iPad versions are all good and about to release second version so no issues there.
So I am subclassing NSWindowController to get access to the Toolbar and worked out how to remove and add items on the toolbar, but for the life of me I can not get one NSViewController (firstViewController) to dismiss and bring up the second NSViewController (secondViewController) in the same NSWindowController.
So the 2 issues are that
1. I want to be able to performSegueWithIdentifier from the first NSViewController in code and
2. bring up the second NSViewController by replacing the first NSViewController in the same NSWindowController.
If I add a button to the firstViewController and put a segue to the secondViewController then when I select the button the secondViewController comes up just fine but in a seperate window not the same NSWindowController that I want it to and the firstViewController does not get replaced but stays in the NSWindowController.
So I know the segue idea will work but its not working in code and when I do insert the segue from a button it works but into a seperate NSViewController that is not part of the NSWindowController.
I am trying to find some programming guide from Apple on the issue but no luck so far.
Here is an overview from my Storyboard:
Here is my NSWindowController subclassed and the func loginToMe2Team is trigger from the NSToolBar and its working just find as the print statements show up on the console.
import Cocoa
class me2teamWindowsController: NSWindowController {
#IBOutlet var mySignUp : NSToolbarItem!
#IBOutlet var myToolbar : NSToolbar!
let controller = ViewController()
override func windowDidLoad() {
super.windowDidLoad()
print("window loaded")
}
override func windowWillLoad() {
print("window will load")
}
#IBAction func logInToMe2Team(sender: AnyObject){
controller.LogIn() //THIS IS THE FUNC I AM TESTING WITH
}
#IBAction func signUpToMe2Team(sender: AnyObject){
controller.signUp()
}
Here is my NSViewController subclassed with the func LogIn. Its getting selected just fine but the performSegueWithIdentifier is not. And I did cut and past the Identifier to make absolutely sure it was the same.
import Cocoa
import WebKit
class ViewController: NSViewController {
#IBOutlet weak var theWebPage: WebView!
#IBOutlet weak var progressIndicator: NSProgressIndicator!
override func viewDidLoad() {
super.viewDidLoad()
let urlString = "https://thewebpage.com.au"
self.theWebPage.mainFrame.loadRequest(NSURLRequest(URL: NSURL(string: urlString)!))
}
override func viewDidAppear() {
}
func LogIn() {
print("I logged in")
self.performSegueWithIdentifier("goToTeamPage", sender: self)
//THIS IS THE BIT THATS NOT WORKING
}
func signUp() {
print("I have to sign up now")
}
override var representedObject: AnyObject? {
didSet {
}
}
func webView(sender: WebView!, didStartProvisionalLoadForFrame frame: WebFrame!)
{
self.progressIndicator.startAnimation(self)
}
func webView(sender: WebView!, didFinishLoadForFrame frame: WebFrame!)
{
self.progressIndicator.stopAnimation(self)
}
}
You need to use a custom segue class (or possibly NSTabViewController if it’s enough for your needs). Set the segue’s type to Custom, with your class name specified:
…and implement it. With no animation, it’s simple:
class ReplaceSegue: NSStoryboardSegue {
override func perform() {
if let src = self.sourceController as? NSViewController,
let dest = self.destinationController as? NSViewController,
let window = src.view.window {
// this updates the content and adjusts window size
window.contentViewController = dest
}
}
}
In my case, I was using a sheet and wanted to transition to a different sheet with a different size, so I needed to do more:
class ReplaceSheetSegue: NSStoryboardSegue {
override func perform() {
if let src = self.sourceController as? NSViewController,
let dest = self.destinationController as? NSViewController,
let window = src.view.window {
// calculate new frame:
var rect = window.frameRectForContentRect(dest.view.frame)
rect.origin.x += (src.view.frame.width - dest.view.frame.width) / 2
rect.origin.y += src.view.frame.height - dest.view.frame.height
// don’t shrink visible content, prevent minsize from intervening:
window.contentViewController = nil
// animate resizing (TODO: crossover blending):
window.setFrame(window.convertRectToScreen(rect), display: true, animate: true)
// set new controller
window.contentViewController = dest
}
}
}

Non-resizable window swift

I have a NSViewController named Hardness, and I need not to let user resize it. Of course, I can just resize it back every time the users tries, but is there any way just not to let user open a window to full screen, or to stretch the window?
edit/update: Xcode 10.2 • Swift 5
NSWindow has a property called styleMask that allows you to control what kinds of control will be available to the user. If you don't want to allow the user to resize the window you have to remove the style mask .resizable using the mutating method remove(member: NSWindowStyleMask). To enable it again you need to use the mutating method insert(member: NSWindowStyleMask). Note that it will also disable the full screen mode for that window:
removing to disable:
window.styleMask.remove(.resizable)
inserting to enable
window.styleMask.insert(.resizable)
Sample
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var closable: NSButton!
#IBOutlet weak var miniaturizable: NSButton!
#IBOutlet weak var resizable: NSButton!
#IBOutlet weak var titled: NSButton!
lazy var window: NSWindow! = self.view.window
func remove(_ member: NSWindow.StyleMask) {
window.styleMask.remove(member)
}
func insert(_ member: NSWindow.StyleMask) {
window.styleMask.insert(member)
}
#IBAction func toggle(_ sender: NSButton) {
switch sender.state {
case .on:
switch sender {
case closable: insert(.closable)
case miniaturizable: insert(.miniaturizable)
case resizable: insert(.resizable)
case closable: insert(.closable)
case titled: insert(.titled)
default: break
}
case .off:
switch sender {
case closable: remove(.closable)
case miniaturizable: remove(.miniaturizable)
case resizable: remove(.resizable)
case closable: remove(.closable)
case titled: remove(.titled)
default: break
}
default: break
}
}
}
Sample Project
I solved the same issue with the non-resizable window by one line of code in
override func viewDidAppear() {
self.view.window?.styleMask.remove(NSWindowStyleMask.Resizable)
}
The correct approach would be to use bitwise operators.
Disable resize:
window?.styleMask &= ~NSResizableWindowMask
Enable resize:
window?.styleMask |= NSResizableWindowMask
This answer may be of some help in addition to the current one. There's also a nice simple way to accomplish this by using setHidden with NSWindowZoomButton
Setup the functionality as a sub-class of NSWindow:
Objective-C
#import "CustomWindow.h"
#implementation CustomWindow
- (void)awakeFromNib {
NSButton *zoomButton = [self standardWindowButton:NSWindowZoomButton];
[zoomButton setHidden:YES];
}
#end
Swift
import CustomWindow
class CustomWindow {
func awakeFromNib() {
var zoomButton: NSButton = self.standardWindowButton(NSWindowZoomButton)
zoomButton.setHidden(true)
}
}
Connect the custom class to your window in IB and the Zoom button should be now hidden!
A little more elegant solution for Swift 3, so that the | operator can be used:
public func | (left: NSWindowStyleMask, right: NSWindowStyleMask) -> NSWindowStyleMask {
return NSWindowStyleMask(rawValue: left.rawValue | right.rawValue)
}

Change Custom Views drawing when button is clicked in Swift OS X app

So in my Swift OS X app I have one custom view and one button. When I start my app, my view shows a red oval and I need to change that drawing to drawRectangle()-method when i click my button.
My custom view's class MyView looks like following:
import Cocoa
import AppKit
class MyView: NSView {
var isTrue = true
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
// Drawing code here.
if isTrue {
DrawingMethods.drawOval()
} else {
DrawingMethods.drawRectangle()
}
}
#IBAction func buttonPressed(sender: AnyObject) {
isTrue = false
// Now I need to update the view, so it draws rectangle isntead of oval. How I do that?
}
}
And I have my DrawingMethods class:
import Cocoa
public class DrawingMethods: NSObject {
public class func drawOval() {
let color = NSColor(calibratedRed: 1, green: 0, blue: 0, alpha: 1)
let ovalPath = NSBezierPath(ovalInRect: NSMakeRect(64, 54, 50, 45))
color.setFill()
ovalPath.fill()
}
public class func drawRectangle() {
let color = NSColor(calibratedRed: 1, green: 0, blue: 0, alpha: 1)
let rectanglePath = NSBezierPath(rect: NSMakeRect(136, 12, 34, 34))
color.setFill()
rectanglePath.fill()
}
}
So how can i get my custom views draw rectangle instead of oval?
Call setNeedsDisplayInRect() on the view after setting isTrue = false. This will notify the view that it needs to redraw and drawRect will be called again.
Your buttonPressed function should be defined in the ViewController that contains the custom view
import Cocoa
class ViewController: NSViewController {
#IBOutlet customView: MyView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func buttonPressed(sender: AnyObject) {
customView.isTrue = false
customView.setNeedsDisplayInRect(customView.bounds)
}
}
Alternatively, you can just set the needsDisplay property of the view to true to redraw the entire view:
customView.needsDisplay = true

Resources