I have a VC that has an inputAccessoryView that is used to display a textfield (much like the messages app). When I push this view onto the navigation stack everything works fine and by that I mean that the tableview adjusts its insets to make sure nothing scrolls underneath that accessory view. However, if from that view I push on another instance of the same view controller class the insets will not be adjusted and the scrolling of the table will be behind the accessory view.
This issue is seen in iOS 8 only. The other interesting thing about this is that if you then click in the accessory view to open the keyboard the insets are adjusted properly for the keyboard being visible and again when it's hidden.
Also if you don't click the text field to fix the issue and hit back the previous VC is broken as well.
I'm fairly certain based on the information above that this is an iOS 8 bug. I'm hoping someone has seen this and come up with semi reasonable fix.
Nasty solution but a solution nonetheless:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.inputAccessoryView.inputAccessoryTextField becomeFirstResponder];
[self.inputAccessoryView.inputAccessoryTextField resignFirstResponder];
});
}
This allows the view to redraw the insets
Related
In my app I have a NSTableView in NSViewController with a NSArrayController provide the content.
It works great, however, when I scroll to some position of tableview, quit app and re-launch it, It will restore the last scroll position. I don't like this behavior, I want it to keep at the top.
I tried to setAutosaveTableColumns to NO on NSTableView, it seems not the option I need. It still works the old way.
Does is any option to turn this off?
The scroll position is stored by NSScrollView, which implements encodeRestorableStateWithCoder:/restoreStateWithCoder: since OS X Lion.
(Interface Builder automatically wraps a table view in a NSScrollView→NSClipView→NSTableView hierarchy).
To get a scroll view that is scrolled to top after an app relaunch you have several options:
Turn off view state restoration for the entire window in Interface Builder:
Subclass NSScrollView and override encodeRestorableStateWithCoder: with an empty implementation (Don't forget to set it as class for your your table view instance in IB):
Programmatically scroll to top after app relaunch:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[self.scrollView contentView] scrollToPoint:NSMakePoint(0.0, 0.0)];
[self.scrollView reflectScrolledClipView:[self.scrollView contentView]];
}
Personally I'd go with method 3, because turning off state restoration for the whole window might break some behaviour that your users expect and method 2 is against Apple's recommendation on calling [super encodeRestorableStateWithCoder:] when subclassing NSView.
I'm using a simple UIScrollview in a One of my TabBarViews. I want this to work with autolayout so I did some searching I found out the the ViewDidappear method works with autolayot.
The scroller works fine with the viewdidAppear instead of viewDidLoad, but when i switch to another tab without scrolling back to the top it does not release or something.
When I go back to the scrollview tab the scroller is not able to go all the way to the top?
It starts where i left of and scrolls all the lenght from there.
http://tinypic.com/r/24dmys8/6
Start of scroll, when I contiune to scrolldown and switch tab.
http://tinypic.com/r/2e37vb9/6
When I come back from another tab the scroll starts at this point. I think Iit's some kind of release problem... But I can't work out what?!
Here is the code I've used:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.ScrollviewVT2 setContentSize:CGSizeMake(320.0,1440.0)];
[self.ScrollviewVT2 setContentOffset:CGPointZero animated:YES];
}
I'm using a view-based NSTableView with a custom NSTableRowView. I would like to use custom row background drawing via drawBackgroundInRect, based upon mouse location using trackingAreas. The goal is to draw a custom background for the unselected row the mouse is currently hovering over.
This is virtually identical to the HoverTableView example from the WWDC 2011 session View Based NSTableView Basic to Advanced. You can see that behavior in action in the Mail, Contacts & Calendars System Preferences Pane in the account types table view on the right.
Unlike the examples, I have thousands of rows in my table view. Everything works as in the examples unless I scroll the table view rapidly (e.g., with a two-finger flick via trackpad). In this case, it seems that updateTrackingAreas is not called fast enough. Rows that scroll under the mouse get highlighted but are never notified that the mouse left their tracking area and therefore remain highlighted. The result is mulitple rows showing the mouse-over highlight and, due to the reuse queue, these will scroll off one end of the table view and reappear on the other (with different data of course) still highlighted as if they are moused-over. Scrolling slowly eliminates the problem; but considering I expect to scroll thousands and thousands of rows, scrolling slowly is not an expected user behavior.
I've tried various combinations of NSTrackingAreaOptions to no avail and am now stumped. Any suggestions on to solve this issue would be appreciated.
I think the answer to the question is "you cannot," i.e., that updateTrackingAreas for NSTableRowView in a fast-scrolling NSTableView does not happen consistently fast enough on the run loop to rely upon it for determining if the pointer is inside a row view or not. Again, see the HoverTableView example code to see where updateTrackingAreas is being used.
I do think I have a suitable solution though. I noticed that Twitter for Mac (RIP) has mouse-over views that appear with mouse movement but disappear on scroll, very similar to the mouse-over highglight I was hoping to achieve.
To execute this, I basically made my custom NSTableRowView have a delegate (my custom NSTableViewController) whom it would ask if it should highlight on hover. I used a custom NSScrollView for my NSTableView and called
[self.contentView setPostsBoundsChangedNotifications:YES];
in its awakeFromNib and also made it register self as the observer of that notification. On receiving that notification, which implies that my table view is scrolling, my custom NSScrollView forwards a message to my NSTableViewController.
When my NSTableViewController receives the message that the table view is scrolling, it disables highlighting on mouse-over and, if there is not already a valid timer running from a previous notification, fires a short timer to reenable highlight on mouse-over once scrolling has stopped. As an extra precaution, at state transitions between enable and disable highlight on mouse-over, my NSTableViewController uses enumerateAvailableRowViewsUsingBlock to clear mouseInside for every row view.
Not sure if this is necessarily the best way, but it achieves the effect I wanted.
The solution for this issue is described here: mouseExited isn't called when mouse leaves trackingArea while scrolling
My updateTrackingAreas method now looks like:
- (void)updateTrackingAreas {
if (trackingArea)
[self removeTrackingArea:trackingArea];
[trackingArea release];
trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect
options:NSTrackingInVisibleRect |
NSTrackingActiveAlways |
NSTrackingMouseEnteredAndExited
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
NSPoint mouseLocation = [[self window] mouseLocationOutsideOfEventStream];
mouseLocation = [self convertPoint: mouseLocation fromView: nil];
if (NSPointInRect(mouseLocation, [self bounds]))
[self mouseEntered:nil];
else
[self mouseExited:nil];
[super updateTrackingAreas];
}
I have toolbar at the top of the (full screen) main view in my iPad. The toolbar has a barButtonItem that when pressed, shows a popover.
In the popover, I have a UIButton that when pressed, tells the delegate (the main view controller) to dismiss the popover and show a full page modal view.
This all works fine.
When I dismiss the modal view, the area of the screen the popover occupied - including the main view and toolbar buttons - is no longer responding to touch events.
This problem corrects itself if I rotate the device and only occurs in Landscape mode.
Any suggestions?
Update: This bug does not happen when running in the Simulator, only on an actual iPad.
The delegate method I have to dismiss the full screen modal view..
- (void)fullScreenViewControllerDidFinish:(FullScreenWebViewController *)fullScreenWebView {
[self dismissViewControllerAnimated:YES completion:^{
[self setFullScreenWVC:nil];
[[self view] setNeedsLayout]; //Does't fix the issue
}];
}
Update:
Using Instruments, I've gotten the iPad to show me how it's laying out subviews. It looks like it thinks the iPad is in Portrait when the modal view is dismissed but the device is obviously in landscape.
I fixed the problem.
I was using
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
instead of
UIDeviceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
The iPad wasn't getting the right orientation for some reason.
Thanks for your help.
I may be misunderstanding you issue, but I would suggest trying to call "setNeedsLayout" in your main view once the modal view is dismissed. This should trigger the auto resize of your view layout and may resolve the issue if it has not auto resized.
Take a look at this link for more information:
http://developer.apple.com/library/ios/ipad/#documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/instm/UIView/setNeedsLayout
I have an NSView in IB which sits above the app window. I have a subclass of NSView (AddSource) which I assign to the NSView.
On awakeFromNib I instantiate the view:
//add a new Add Source class
addSourceView = [[AddSource alloc] initWithFrame:NSMakeRect(0.0, 959.0, 307.0, 118.0)];
[[winMain contentView] addSubview:addSourceView];
in addSourceView's drawRect method I am adding a white background to the view:
[[NSColor whiteColor] set];
NSRectFill(rect);
[self setNeedsDisplay:YES];//added this to see if it might solve the problem
In winMain's contentView I have a NSButton that when clicked slides the addSourceView onto the window:
NSRect addSourceViewFrame = [addSourceView frame];
addSourceViewFrame.origin.y = 841.0;
[[addSourceView animator] setFrame:addSourceViewFrame];
But it seems as if the app is painting over the IBOutlets I placed on the NSView in IB. If, in IB, I repoistion the NSView so that it is on screen when the app launches everything works fine, the IBOutlets are there as well as the background color.
I'm not sure why this is happening. I've done this before with no problems. I must be doing something different this time.
Thanks for any help.
*note - on the 3rd screen capture, when I say this is what the app looks like when opened, that's when I hard code the Y position of the NSView. When it is functioning correctly it should open as screen capture 1.
Most likely your buttons and custom view are siblings, i.e. they are both subviews of your window's content view. Since siblings are "Stacked" depending on the order in which they are added, when you add the view in code it is being added on top of the buttons. You should be able to fix it by explicitly specifying where the view should be positioned relative to its new siblings like so:
[[winMain contentView] addSubview:addSourceView positioned:NSWindowBelow relativeTo:nil];
which should place it below any existing subviews of your window's content view. Also, remove the setNeedsDisplay: line in drawRect, that leads to unncessary, possibly infinite, redrawing.
EDIT: OK I see what you're doing.
I would suggest creating a standalove view in the NIB by dragging a "Custom View" object into the left hand side (the vertically-aligned archived objects section) and adding your controls there, that should ensure the controls are actualy subviews of the view, then you can just create a reference to the archived view in code, and add/remove it dynamically as needed.
Honestly though, you should probably be using a sheet for these kinds of modal dialogs. Why reinvent the wheel, and make your app uglier in the process?
You added TWO AddSource views to the window. You added one in IB - this view contains your textFields and buttons that are connected to the IBOutlets and it is positioned outside the window.
Then in -awakeFromNib you create another, blank AddSource view (containing nothing) and animate it into the window.
I can't recommend highly enough the Hillegass as the best introduction to IB and the correct way to build Cocoa Apps.
Also, Assertions can be useful to make sure what you think is happening is actually what is happening.
If you are certain you added a button to your view in IB, assert it is so:-
- (void)awakeFromNib {
NSAssert( myButton, #"did i hook up the outlet?");
}
NSAssert is a macro that has zero overhead in a release build.
Calling [self setNeedsDisplay:YES] from -drawRect just causes the same -drawRect to be called again. This will give you big problems.