I have a textView docked to the bottom of the view. However, the keyboard wont dismiss when the user taps outside the commentTextView.
Current Attempt:
import UIKit
class CommentsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var commentBar: UIView!
#IBOutlet var commentTextField: UITextField!
override var inputAccessoryView: UIView {
return commentBar
}
override func canBecomeFirstResponder() -> Bool {
commentBar.removeFromSuperview()
return true
}
func textFieldShouldReturn(textField: UITextField!) -> Bool {
self.view.endEditing(true);
return false;
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true);
commentTextField.resignFirstResponder()
}
According to Apple's documentation, the keyboard won't dismiss by default when the user taps outside of the UITextView. You do need to handle this programmatically when you want to dismiss the keyboard by calling commentTextField.resignFirstResponder().
UITextFiled Reference about Managing the Keyboard
It is your application’s responsibility to dismiss the keyboard at the time of your choosing. You might dismiss the keyboard in response to a specific user action, such as the user tapping a particular button in your user interface. To dismiss the keyboard, send the resignFirstResponder message to the text view that is currently the first responder.
There are many ways for a user may hide the keyboard.
Situation 1: one is when the user tap on the Return button on the keyboard. This is exactly what your following function is for:
func textFieldShouldReturn(textField: UITextField!) -> Bool {
commentTextField.resignFirstResponder();
return true;
}
But the major problem is that the above function won't get called because you forget to set the UITextFieldDelegate. In short, you need to change the class definition to the following:
class CommentsViewController: UIViewController, UITextFieldDelegate /*Add This*/, UITableViewDelegate, UITableViewDataSource {
// ....
}
You will also have to set the delete either in the storyboard or by code. It is the same as setting the UITableViewDelegate and UITableViewDataSource. By the following is an example of setting it in code:
override func viewDidLoad() {
super.viewDidLoad()
commentTextField.delegate = self;
}
Situation 2: when user tap on the table view. You can simply implement the following UITableViewDelegate and it should work.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
commentTextField.resignFirstResponder();
}
Situation 3: when the user tap on a background view. This is what the following code is for. However, this function will not get called when user is tap on the table view. If you want to know why, please refer to the responder chain for more details.
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
// self.view.endEditing(true); // This line is redundant.
commentTextField.resignFirstResponder()
}
To sum up, there is no quick and easy way to dismiss the keyboard say "when the user taps outside the textView". You do need to handle all different situations according to your need.
Try to set keyboard resign on your tableview as shown in figure.
check any
-dismiss on drag
-dismiss interactively
did you add Table View?
if yes, tableViewCell will receive the touch event instead of controller.view.
you could override the method in custom tableView cell:
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
if (xxTextField.isFirstResponder){
return viewController.view
}
return self
}
Another way you can try,maybe it work:
add UITapGestureRecognizer to controller.view.
When you say "outside of my UITextField", I'm guessing you mean "on another element in my view". I can see that you have a UITableViewDelegate and UITableViewDataSource, which tells me you have a tableView inside CommentsViewController.
You can implement the function func tableView(_ tableView: UITableView,
didSelectRowAtIndexPath indexPath: NSIndexPath) and there you can resign the keyboard by calling commentTextField.resignFirstResponder()
First, your view controller needs to implement UITextFieldDelegate, so add that. Then, set your view controller as the delegate for the textfield
then add these methods. The first one will resignFirstResponder when your text field ends editing. The second resigns when you hit return. The last forces your textfield to end editing when you tap the background.
func textFieldDidEndEditing(textField: UITextField) {
textField.resignFirstResponder()
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
self.commentTextField.endEditing(true)
}
Modify
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true);
commentTextField.resignFirstResponder()
}
To
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event)
self.view.endEditing(true)
}
It should do the job.
Try this
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
self.view.endEditing(true);
commentTextField.resignFirstResponder()
}
Related
I have a custom cell for a UITableView. When user taps on a button in cell, user has to get navigated from the current ViewController1 to ViewController2. I have defined the button action in the custom cell class. But needs a call back to the ViewController1.
I tried using closure similar to how we use blocks in objective C. It works fine while using in the same class. But getting errors while using in 2 different classes.
You need to use delegate protocols there.
Example: Protocol for sending UserItem when something happened in cell:
protocol TappedUserDelegate: class {
func userInfoTapped(_ tappedUser: UserItem?)
}
In your controller:
extension Controller: TappedUserDelegate {
func userInfoTapped(_ user: UserItem?) {
// user is tapped user in cell
}
}
In your tableView func:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// ........
cell.delegateUserTaps = self // for user info taps to perform segue
// ........
}
In your custom cell:
class CustomCell: UITableViewCell {
weak var delegateUserTaps: TappedUserDelegate? // for sending user info
// ........
func userInfoTapped() {
delegateUserTaps?.userInfoTapped(userItem) // <- send data to controller
}
}
When userInfoTapped will be called, your function in controller will be performed with this user.
I've given you an idea.
Hope it helps
Is there any way of preventing a contextual menu (and the associated selection "ring" around the cell view) being shown when right-clicking on a specific cell in a view-based NSTableView ?
I'm not talking about disabling the right-click action on ALL the cells, but only on specific ones.
I've obviously tried all the delegate methods dealing with selection changes but none works because the selectedRow property is not changing, only the clickedRow does.
So basically I'm looking for something equivalent to
func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool
but for the clicked row not the selected row.
Note: the questions is about NSTableView on macOS and not the UITableViewon iOS.
I've found a way to do what I wanted, although looks like a little to involved for something that should be simpler. So I welcome any simpler solution.
It can be done by subclassing NSTableView :
class MyTableView : NSTableView {
override func menu(for event: NSEvent) -> NSMenu? {
let clickedPoint = self.convert(event.locationInWindow, from: nil)
let row = self.row(at: clickedPoint)
// no contextual menu for the last row
return row == self.numberOfRows - 1 ? nil : super.menu(for: event)
}
}
This example prevents the contextual menu to be shown for the last row, but a more generic solution could be implemented by adding a delegate with a method to return the menu for each cell.
Instead of subclassing NSTableView, a much easier approach is to set a menu delegate and remove all items within public func menuNeedsUpdate(_ menu: NSMenu) delegate method.
Example:
class MyViewController: NSViewController {
override func viewDidLoad() {
let menu = NSMenu()
menu.delegate = self
tableView.menu = menu
}
}
extension MyViewController: NSMenuDelegate {
public func menuNeedsUpdate(_ menu: NSMenu) {
//This will prevent menu from showing
menu.removeAllItems()
//Check if user has clicked on the cell or somewhere inside tableView
//area that is not populated with cells
guard tableView.clickedRow >= 0 else { return }
//Get model
let item = items[tableView.clickedRow]
//For cells that need context menu, add necessary menu items
if item.needsContextMenu {
menu.addItem(NSMenuItem(title: "Edit", action: #selector(tableViewEditItemClicked(_:)), keyEquivalent: "e"))
menu.addItem(NSMenuItem(title: "Delete", action: #selector(tableViewEditItemClicked(_:)), keyEquivalent: "d"))
}
}
}
I am trying to show/hide a button only if the information is available. For example, I get the information from the database, and if the field returns blank the a button should be hidden else show the button.
#IBAction func emailBtn(_ sender: AnyObject) {
//blank
}
viewdidload()
if emailURL.characters.count >= 5
{
emailBtn.isHidden = false //Giving error Please see the screenshot
}
else
{
emailBtn.isHidden = true // Giving error Please see the screenshot
}
}
Screenshot
You're trying to hide an #IBAction function. What you're intending to do is hide the button. What you need to do is create an outlet in your code that references that button.
In the Storyboard, Control+Drag the button to your class. Create an outlet. This will create something like the following:
#IBOutlet weak var myButton: UIButton!
You want to reference that button in viewDidLoad()
myButton.isHidden = true
I am making an application for tvOS. I have a view that contains a UIButton and a custom UIView that contains a couple other custom views. The simulator is only able to highlight the UIButton and not the custom view.
According to the Building Apple TV Apps Docs:
If your custom view needs to be focusable, override canBecomeFocused to return YES (by default, it returns NO).
According to the canBecomeFocused Docs:
canBecomeFocused will return
YES if the view can become focused; NO otherwise.
However, attempting to assign YES to canBecomeFocused by doing this:
self.customView.canBecomeFocused = YES;
Gives this error:
No setter method 'setCanBecomeFocused:' for assignment to property
How do I accomplish this?
It looks like UIView declares the function/property.
Have you tried overriding the function like so?
Swift
override func canBecomeFocused() -> Bool {
return true
}
Objective-C
- (BOOL)canBecomeFocused {
return YES;
}
I haven't tried this, but it may work for you.
Besides of overriding the canBecomeFocused method in your custom view:
override func canBecomeFocused() -> Bool {
return true
}
Make sure your custom view userInteractionEnabled is true. This is the complete list to be sure your view can be focused:
Why Is This View Not Focusable?
There are a number of reasons a view that is expected to be focusable may not be, including (but not limited to):
The view’s canBecomeFocused method returns NO.
The view’s hidden
property has a value of YES.
The view’s alpha property has a value of 0.
The view’s user interaction is disabled.
The view is obscured by another view on top of it.
Above answers are not enough this my customView code block.
Swift
import UIKit
class Focus: UIView {
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/
override func canBecomeFocused() -> Bool {
return true
}
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
if context.previouslyFocusedView === self {
UIView.animateWithDuration(0.1, animations: { () -> Void in
context.previouslyFocusedView?.transform = CGAffineTransformMakeScale(1.0, 1.0)
})
}
if context.nextFocusedView === self {
UIView.animateWithDuration(0.1, animations: { () -> Void in
context.nextFocusedView?.transform = CGAffineTransformMakeScale(1.4, 1.4)
})
}
}
}
I have created an App for Mac Desktop, it is working, but Apple rejected it because when we run the App and close it by using "X", the we can not re-open it from the dock though the App icon is still there but it doesn't open the App again and the main issue for that I am struggling is that "If we close the App then in the menu bar there is no option to open it" other App which I have seen does that.
What should I do?
Here's an answer for Swift 3:
Conform to NSWindowDelegate in your View Controller class. Then hide the window instead of closing it by overriding the following method.
self.view.window?.delegate = self
func windowShouldClose(_ sender: Any) -> Bool {
NSApplication.shared().hide(self)
return false
}
Then unhide the application when the app icon is clicked in the dock.
func applicationDidBecomeActive(_ notification: Notification) {
NSApplication.shared().unhide(self)
}
To implement simple show/hide functionality for the red (x) button, make your App Delegate class the window delegate for your main window, as well.
Then add the following code to it:
- (BOOL)windowShouldClose:(id)sender {
[[NSApplication sharedApplication] hide:self];
return NO;
}
- (void)applicationDidBecomeActive:(NSNotification *)notification {
[[NSApplication sharedApplication] unhide:self];
}
my 2 cernts for swift 5/Xcode 10
note: You can call these methods also in ViewController (if useful) to prevent splitting code between NASWindow/NSView-Controllers.
in this case:
class ViewController: NSViewController, **NSWindowDelegate**
{
...
override func viewWillAppear() {
// we choose to delegate ourselves. must be done here, in viewDidLoad window is nil
let window = self.view.window
window!.delegate = self
}
...
no neeed to pass self.. : (as per other guys above.)
func windowShouldClose(_ sender: NSWindow) -> Bool {
NSApplication.shared.hide(nil)
return false // prevent closing.
}
func applicationDidBecomeActive(_ notification: Notification) {
NSApplication.shared.unhide(nil)
}