I have put a label in a text box and I want to shift this label to left side after tapping this text box. In the following screenshot 'hello' is a label and I want to shift it left after tapping on the text box.
I wrote the following code but the 'textFieldDidBeginEditing' function is not called
#IBOutlet weak var lblhello: UILabel!
func textFieldDidBeginEditing(numtxt: UITextField!) { //delegate method
lblhello.frame = CGRectMake(98, 156, 42, 21)
}
I'm making the assumption based on previous comments that you want to manually specify the frame size, and aren't using constraints.
First off, you need to add UITextFieldDelegate to your viewController.
This is done like so in the beginning of your VC class:
class yourViewControllerName: UIViewController, UITextFieldDelegate {
Then you want to specify the delegate of your UITextField, (most likely in viewDidLoad)
yourTextFieldName.delegate = self
Now you can use the textFieldDelegate functions. The on you're looking for is probably this:
func textFieldDidBeginEditing(textField: UITextField) -> Bool {
lblhello.frame = CGRectMake(160, 200, 60, 40)
return true
}
If everything is set up correctly that should change the frame of lblhello when a user begins editing your UITextField.
One common problem I often hear for people saying this doesn't work. Is caused by the label being specified in viewDidLoad(). Most of the time you want to declare the label before viewDidLoad(), otherwise functions like this doesn't have access to it.
In case you want to move it back to it's original position afterwards. You do almost the same as you did in textFieldDidBeginEditing except you use textFieldDidEndEditing instead.
However, on a side-note. I do suggest getting used to using constraints rather than setting the frame for things like this.
Related
Each time the user presses enter, a new NSTextView is made. This works correctly, and the new NSTextView becomes the first responder, as is my goal. However, the cursor does not move into the new NSTextView despite it being the first responder.
Below is my code:
func makeNSView(context: NSViewRepresentableContext<TextView>) -> TextView.NSViewType {
let textView = NSTextView()
textView.textContainer?.lineFragmentPadding = 10
textView.textContainerInset = .zero
textView.font = NSFont.systemFont(ofSize: 12)
textView.becomeFirstResponder()
//NSApp.activate(ignoringOtherApps: true) ----> doesn't make difference but is supposed to help switch cursor
print("\(textView) is first responder") //proof that the first responder is shifting, but the cursor does not move with it for some reason
return textView
}
I have tried to use this line as suggested by a different answer:
NSApp.activate(ignoringOtherApps: true)
However, it doesn't make any difference. I have also tried inserting text at a selected range, but it doesn't insert text in any of the NSTextViews displayed regardless of whether they are the first responder.
What methods exist to move the cursor to a different NSTextView (preferably to the First Responder)?
Let me know if any more information is needed.
I was able to get the desired behaviour by doing this:
func makeNSView(context: NSViewRepresentableContext<TextView>) -> TextView.NSViewType {
let textView = NSTextView()
textView.textContainer?.lineFragmentPadding = 10
textView.textContainerInset = .zero
textView.font = NSFont.systemFont(ofSize: 12)
DispatchQueue.main.async {textView.window?.makeFirstResponder(textView)
textView.setSelectedRange(NSMakeRange(0, 0)) }
print("\(textView) is first responder") //proof that the first responder is shifting, but the cursor does not for some reason
return textView
}
The answer originally comes from here: How to make first responder in SwiftUI macOS
Thanks for all the help!
As Warren Burton mentions in a comment, you have not added the new view to a window's view hierarchy at the point that you're trying to make it the first responder. That can't work.
Furthermore, calling becomeFirstResponder() does not make the receiver the first responder. (This is different from UIKit.) In fact, you're never supposed to call becomeFirstResponder() on macOS (except to forward to the superclass in an override). The documentation calls this out specifically:
Use the NSWindow makeFirstResponder(_:) method, not this method, to make an object the first responder. Never invoke this method directly.
(Emphasis added.) becomeFirstResponder() is called by Cocoa to inform a view (or other responder) that it has become the first responder. It doesn't cause a change, it notifies about a change.
So, once the view has been added to a window's view hierarchy, invoke textView.window.makeFirstResponder(textView).
I know that this question may sounds duplicate, but looking at the several answer, nothing is working for me yet.
Basically I have a Quizz App, a question is shown and the user needs to fill several UITextFields to answer the question (i.e. if the answer is VENICE, 6 UITextFields will be shown, 1 per letter).
It was able to detect one character in the UITextFields and once the user hits a key it will jump to the following UITextField. I use the tag of the UITextField and the method becomeFirstResponder.
The problem is that I will like to detect the backspace when a UITextField is empty so I will jump to the previous UITextField.
I have tried this solution from Jacob Caraballo (Detect backspace in empty UITextField) but I am not sure, how to use it with my existing UITextField.
For example, I have tried:
// #IBOutlet weak var textField1: UITextField!
#IBOutlet weak var textField1:MyTextField!
But calling the delegate
textField1.myDelegate = self
It crashes
I also notice, that using the Jacob's solution I won't be able to check which UITextField was used as the func textFieldDidDelete() doesn't not have an UITextField as parameter and I will need to check its tag i.e.
If textField.tag == 5 {
textField4.becomeFirstResponder()
}
Any help on this please?
If you use Jacob's solution, the deleteBackward method will be called with the current UITextField instance. So you can add a protocol to that UITextField class and pass it back to your view.
Something like this:
protocol MyTextFieldDelegate: class {
func backwardDetected(textField: MyTextField)
}
class MyTextField: UITextField {
weak var myTextFieldDelegate: MyTextFieldDelegate?
override func deleteBackward() {
super.deleteBackward()
self.myTextFieldDelegate?.backwardDetected(textField: self)
}
}
I am using Custom Cell in UITableView. And the basic model of the cell is as follows.
I would like to have the dashed line dynamically deformed according to the size of the Menu Name box in this cell. So I wrote the following code:
menuField.frame.size.width = getWidth(text: menuField.text!)
menuField.layoutIfNeeded()
dotLine.layoutIfNeeded()
func getWidth(text: String) -> CGFloat {
let txtField = UITextField(frame: .zero)
txtField.text = text
txtField.sizeToFit()
return txtField.frame.size.width
}
This worked very well. Only increase if only! If the Menu Name Frame is reduced below the currently set size, the size remains unchanged.
As you can see from the image above, I need to make not only the size of the dotted line increase but also the shrinkage. I do not know what my problem is. Please help me!
You don't need any of code you wrote, autolayout does this for you. Just set autolayout like this:
Dash is constraint with your value
- MenuTextField - Dotted line - Price -
I have solved my problem. First, I added the width dimension Constraints of the Menu Text Box and imported it into the IBOutlet variable.
#IBOutlet weak var menuWidth: NSLayoutConstraint!
And I changed the value of the variable according to the text length.
menuWidth.constant = getWidth(text: menuField.text!)
This method is not yet fully functional. But it works the way I want.
Also thanks to Robert Dresler who answered me :) Thanks!
My goal is to safe a reference from the button, label or textfield inside a variable.
The problem is that I don't know on which control the user tapped.
I am having a simple application which looks like this:
The user can touch any control.
It is easy enough with just those three controls because I can drag in a action. But if I am having many of them I can't handle them all over the action methods. Is there a general way in which I can safe a reference to the control in a variable so that I can know which of the controls is the active one?
Edit
As suggested I am using a function and assigning the variable to the sender of the function. This is how it looks in code:
var currentObject: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
myTextfield.action = #selector(myAction)
}
func myAction(sender: NSTextField)
{
print("aktuell: \(sender)")
currentObject = sender
}
As you can see this only works for a NSTextfield. Is there a way in which the function works for every control?
Set the tag attribute for each item, and then you can check sender.tag to identify which object is calling it.
To set the tag, select the Attributes inspector in Storyboard (upper right side - middle button of Utilities) and look for this section:
override func viewDidLoad() {
super.viewDidLoad()
self.enterNumberTextField.clearsOnBeginEditing = true
}
Setting this bool true does not persist in later code, and i do not reset it in any of my code. Setting the bool does not force the text box to clear when the user puts the cursor in it. I check the value of the bool and it is true on the first pass through code, though the text box does not clear. On subsequent passes through code the bool is reset to false. not by my code.
I have also tried putting this line of code into the IBAction function where all the processing is done in this program. Same result. Does not clear text box and is reset to false inside the if {} where all the work is done.
Can someone tell me why this is happening, and if there is a place where this bool should be set to true such that it persists throughout the program's execution.
From the Swift documentation:
Even if this property is set to true, the text field delegate can override this behavior by returning false from its textFieldShouldClear: method.
Does your view adhere to the UITextFieldDelegate protocol? Do you implement the textFieldShouldClear method? This sounds like it could be the source of your problem.
EDIT:
What happens if you do something like this:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.clearsOnBeginEditing = true
textField.delegate = self
}
func textFieldShouldClear(textField: UITextField) -> Bool {
return true
}
}
That is, add the UITextFieldDelegate protocol at the top, and then implement textFieldShouldClear so it always returns true. This may not be what you ultimately want, but it might solve the issue. Check out the Swift documentation for more info on protocols and delegation.
The problem was I only had one text field and was never giving up focus. I added another text field to transfer focus to , now when I put focus back in the text field of interest, it does clear. Simple, must transfer focus for that method to work.