I have a working UIButton in my view controller's view.
I have a UIView instance on top of the button (I'll refer to it as topView) in the same view controller's view. If a condition is met I am forwarding all of the touch events (began, moved, ended, canceled) to the view's nextResponder.
But when the condition is triggered, the button is not receiving the event. If I move the topView so it is not over the button, the button works (or set the userInteractionEnabled property to false). If topView is over the button, the button does not work. So frustrating because I can see the button under the view!
Do I have to do anything in the view controller to receive the touch events from sending them to the nextResponder?
I have read all the documents I can on the Responder Chain, but I am still a bit confused.
The nextResponder of a view is either its view controller or its superview. The UIButton in your setup is neither, so it doesn't receive the events.
In this situation, instead of forwarding the events to the nextResponder you should override pointInside:withEvent: to return NO. That way the system will act like your view isn't even there. According to the documentation, you could also set userInteractionEnabled to NO on your view for the same effect.
Related
My Cocoa App uses one ViewController. I do not use the InterfaceBuilder On app launch a view will be created and the user can do stuff. When clicking a specific button the VC (as the view's delegate) receives a message and then replaces the view with another.
In this new view I want a specific UI element to be the first responder. So far I have not been successful.
The new view has a reference to the desired element (a subview), so the VC can pass it to the window's makeFirstResponder(:_) method.
I tried to do that in the following places:
at the end of the view's init
in the view controller's viewWillAppear()
in the VCs viewDidAppear()
in the latter two I tried:
if let myView = self.view as? MyView {
... here I try to set the UI element as firstResponder ...
}
But in any case I get the following Message:
[General] ERROR: Setting <NSTableView: 0x7f8c1f840600> as the first responder for window <NSWindow: 0x7f8c1ef0efc0>, but it is in a different window ((null))! This would eventually crash when the view is freed. The first responder will be set to nil.
So it appears that at the time I try to set the firstResponder the new view has not yet been attached to the window.
What I also tried is to override the MyView's becomeFirstResponder()method, assuming that when the view is finally presented in the window it will receive that command, but unfortunately this method does not get called.
Is there an easy way to specify an entry point for the responder chain / key view loop per view?
I've a window with a split view. Left is a NSTableView, to the right a custom view.
When my custom view is active in a 'command mode' I need it to remain first responder status so it can receive a cancelOperation: event when the escape key is pressed. But I do want the user to be able to change the selection in the table view.
Unfortunately, as long as my custom view refuses to resign first responder status the table view doesn't respond.
How can I make sure that the table view allows changing the selection without becoming first responder? Or how can I make sure the cancelOperation: event is delivered to my custom view, while it's not first responder?
the table view allows changing the selection without becoming first responder
Don't do this. It will confuse the user. The table view should become first responder.
Or how can I make sure the cancelOperation: event is delivered to my custom view, while it's not first responder
Put Cancel button in the window with key equivalent Escape. Or if you don't want a button, let an object in the responder chain (view controller, window controller) catch the escape key by implementing cancel: and tell the custom view to cancel.
I have a window with two views in it:
Both the movie view and the controller view override mouseDown: and mouseUp:, for different purposes (the movie view has a target and action and reacts as a button, whereas the controller seeks and supports dragging).
The twist is, when I click within the movie view—which, as shown in the screenshot, will generally be large enough to make missing it and hitting the controller view instead wildly improbable—the mouseDown: and mouseUp: messages are sent to the controller view! The movie view never receives either message.
I have not overridden hitTest: in the movie view or in its parent view (which is a plain NSView), only in the controller view (for reasons that have to do with a tracking area I have on that view—my implementation simply returns self, which is the controller view).
So, what gives?
Well, you probably guessed it: It was my hitTest: implementation in the controller view.
It turns out that hitTest: is not only sent to the views whose frames the mouse location lies within; it is sent to every view in the window, even views that were nowhere near the mouse at either end of the click.
So, when overriding hitTest:, make sure that you verify that the point is actually within yourself. The simplest way is to send [super hitTest:thePoint] and only do your custom hit-test if the result is not nil. (Unless you want to steal clicks from other views in the window.)
i am working on storyboards which has couple of views on first view a condition is placed i want if the condition satisfies then only navigation should happen
For this i have used Custom segue but no matter my condition satisfies or not it navigates to new view.
I have created method in custom segue class
- (void) perform{
NSLog(#"source %#",self.sourceViewController);
NSLog(#"dest %#",self.destinationViewController);
UIViewController *sVC=self.sourceViewController;
UIViewController *dVC=self.destinationViewController;
[sVC.navigationController pushViewController:dVC animated:YES];
}
I want to set condition if result is 1 then only it should navigate. Woul prepareforsegue or initwithsegue provide me any help
Are you saying that you only want to perform the segue if a condition is true?
If so, instead of creating the segue directly from a control or table cell, create a triggerless segue. A triggerless segue has the view controller as its source, and it won't ever fire automatically. Instead you can fire it programmatically any time you like, including from an IBAction.
To create a triggerless segue, start control+dragging the segue from the containing view controller icon in the scene dock at the bottom of the scene. Drag to the destination scene like normal, and pick the segue type. Select the segue, and in the inspector, choose a segue identifier.
At runtime, when you want to perform the segue, invoke -[UIViewController performSegueWithIdentifier:sender:]. You can pass any object you'd like for the sender, including nil. If the sender has no use to you, pass nil.
So, in summary:
Create a triggerless segue from the view controller to the destination scene
Set an identifier for the segue in the inspector
At runtime, and form code, call -[UIViewController performSegueWithIdentifier:sender:] when you want to trigger the segue.
I'm trying to implement a view controller for a custom NSOpenGLView based view (this is Cocoa, not Cocoa Touch).
The view is contained within a NIB loaded window but it does not have its own NIB. In fact the window contains multiple instances of the view.
I want to route mouse events to the controller instead of to the view. I would like for this to happen as soon as the user clicks within the corresponding view.
So how can this be done ?
I've tried having the view's becomeFirstResponder method call makeFirstResponder with the controller as argument. However that doesn't seem to work, the view still receives the mouse events instead of the controller if NSView::becomeFirstResponder returns YES. If it returns NO then neither of my classes receive the mouse events.
Of course I could implement the mouse event handling methods in the view and explicitly forward them to the controller but it seems like there should be a better way to handle this.
For general "first responder" status, I recommend Charles Parnot's MTViewController, an NSViewController subclass that uses KVO to make certain the controller is in the responder chain with no extra effort on your part.
However, in your case, you want mouse events too. There's really no way around this - your view will need to translate mouse events into controller interactions.