UIScrollView doesn't remember the position - objective-c

Has anyone ever had the problem that a UIScrollView, which gets moved by [UIScrollView setContentOffset:...] doesn't "remember" it's new position? It however does, if the user scrolls via touch-and-drag.
Symptoms: If the UIScrollView doesn't remember the new position, it "flips" back to the original position it last remembers (which is the position which has been used via touch-and-drag) whenever it's being touched.
Interesting:
This only happens in 4.0 and
didn't happen in 3.1
This only happens if pagingEnabled == YES is
set

It turned out that the contentInsets would confuse the contentOffsets in iOS 4.0 ... must be a bug in the SDK?

Related

How can I support a split view in landscape on the iPhone 6 or 5s?

In my app there's a lot of wasted space in landscape on the iPhone 6, and to a lesser extent even on 4" screens. I'm already using iOS 8's UISplitViewController changes to support the two-pane view in landscape on the iPhone 6 Plus, but it'd be useful to see both panes on some smaller devices as well.
Conveniently Apple had a WWDC 2014 session, "Building Adaptive Apps with UIKit" which included details on exactly how to do this. You can download the sample code here, but in short: they put the UISplitViewController inside of a UIViewController subclass. The subclass uses setOverrideTraitCollection:forChildViewController: to force [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassRegular] on the split view when it considers the width wide enough. At the time the sample code worked well, and still does on most devices.
However after attempting to use this code in my own app, I discovered it fails horribly on the iPhone 6 Plus. You can see this yourself if you download the sample code and make two changes:
Add a storyboard, add an empty view controller to that, and set it as the "Launch Screen File". This is necessary to run the app at its native resolution on the 6 Plus.
In AAPLTraitOverrideViewController.m, change line 21 to size.width > 500.0, or anything greater than 414. This is necessary to ensure the split view only shows a single view in portrait on the 6 Plus.
Now you can run the app in the simulator. To see the problem, just do this:
Rotate the device to landscape (command-right arrow)
Rotate it immediately back to portrait (command-left arrow)
You can already see that something's not right. All of the table cells should have an arrow on the right side in portrait, but they don't. They're behaving like they're still in a split view. If you tap one of those rows, it gets worse—the detail view slides up from the bottom, and the navigation bar is gone.
I think there must be a bug in iOS 8 here that's causing the problem. But since this code was shared before the iPhone 6 Plus was announced, it also seems possible that it just needs some adjustments to make it compatible with that device. So far the only solution I've found is to change line 21 to something like if (size.width > 500.0 && size.width < 736.0) but I don't want to use code that could break again the next time Apple introduces a new screen size. Is there a better way to handle this?
Seems like you'll always want to make the horizontal size class regular (UIUserInterfaceSizeClassRegular). To do this, override traitCollectionDidChange:. In this method, if the vertical size class is compact (suggesting it's likely in landscape), override the trait collection so that the horizontal size class is regular.
UITraitCollection *compactHeight = [UITraitCollection traitCollectionWithVerticalSizeClass:UIUserInterfaceSizeClassCompact];
if ([self.traitCollection containsTraitsInCollection:compactHeight]) {
UITraitCollection *regularWidth = [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassRegular];
self.forcedTraitCollection = [UITraitCollection traitCollectionWithTraitsFromCollections:#[self.traitCollection, regularWidth]];
[self setOverrideTraitCollection:self.forcedTraitCollection forChildViewController:_viewController];
} else {
[self setOverrideTraitCollection:nil forChildViewController:_viewController];
}
However, if you'll want more specific behavior, you'll have to rely on canvas size for app-specific behavior.

iOS 7 + Auto Layout: Strange UIImageView behaviour

I've got a strange UIImageView behaviour:
I've got a UIViewController with an embedded UIImageView and a close button. Very basic stuff, done a thousand times. I didn't use Auto Layout that much in the past, but another view controller in the same Storyboard has nearly the same config and doesn't appear as strange as this specific one.
In my Storyboard the Controller looks like that:
...and on the device it looks like that:
That image is 1024x768, so it should be filled to the bounds. Content mode in the image view is Aspect fill. When i dismiss the view, i can see that the upper part of the image view must be hidden at the top with some negative Y or something.
I need Auto Layout in this storyboard, because it's an iPhone + iPad App with both orientations.
Has someone hat a behaviour like that before?
Thank you!
Edit:
Here is the layout panel:
First, get rid of the alignment constraints, they are not needed if you're already anchoring your view to every side with a set distance.
Second, check the mode property of your UIImageView in the interface builder. If the image was not big enough and you had it set for "TOP" instead of, say, "aspect fill", you'd see something like this even though the view is actually covering the whole screen.
I'm sorry that I have to say this, but it was, as you certainly thought, my own fault.
The problem was that I made a photo with the iPad, and the iPad can be used in both orientations in this app. The photo was taken and was then used for an own view that allows the user to put annotations on the image.
The image gets then saved, and that was were the problem occured: I call
UIGraphicsBeginImageContextWithOptions(self.view.frame.size, NO, 0.0);
The landscape image was now taken into a portrait frame. After adjusting this and only allowing portrait mode, everything worked well.
Thanks anyways for your answers. And sorry for asking a question when the problem was another one and my own fault.

Does NSSplitView autosavename work?

I can't seem to get NSSplitView autosave to work - can anyone confirm that by adding an autosavename in IB it should work ? I am using auto layout but my splitView is not remembering the position of the divider.
EDIT
I would expect the position of the divider to be remembered between application restarts. All I see is the divider position always starting at the default position that was set originally in IB.
Well strangely enough this now seems to be working! So I guess I can answer my own question - YES setting an autosave name in IB should result in the SplitView remembering the divider position between application launches.
No idea when it started working or why it was not working for a while. My bad no doubt.
FYI I am using a subclassed NSSplitView with autolayout. One thing I have changed is I load the right views at runtime now. Anyway for those struggling with splitViews, they can be made to work with some fiddling it seems.

Same Command, Different Results setFrame: NSView

I'm experiencing what I think is a very strange issue.
First and foremost, my application moves UI elements around the screen using the following example command:
[view setFrame:NSRectFromCGRect(CGRectMake(0, 0, 0, 0))];
I give my users the possibility to resize the application's NSWindow to one other size with this command:
[self.window setFrame:NSRectFromCGRect(CGRectMake(0, 0, 0, 0)) display:YES animate:YES];
When in 'resized mode', I obviously change every single setFrame command to the appropriate coordinate system.
However, there is an issue: when (if) the user switches back to the original NSWindow size by clicking on the button again, and the application performs the UI movements again, the views that are moved around are not in the location they are supposed to be in.
To clarify: my UI movement code runs fine, over and over, either in normal or resized mode. However, if I switch from one to the other, some items (not all) are shifted.
What could be causing this strange behavior? I'm using the same exact commands (within each screen resolution), and NSLogs confirm the UI elements are in the location that I specified; however, this location is clearly not the one I'm attempting to move to.
Has anyone experienced a similar issue here?
You've probably set some sort of autoresizing mask in Interface Builder that's interfering with your manual placements. Go in to your nib and remove all the springs and struts in the Size inspector. Although if possible you should let autosizing handle the placement, or move to Auto Layout which was introduced in 10.7.
After days and days of trying to figure this out, I've come to the following conclusion: the resizing code simply wasn't working.
I confirmed this by using NSLog after I resized my window. In the end, I changed my resizing code by adding the following line after the traditional setFrame: method:
[self.window setContentSize:NSSizeFromCGSize(CGSizeMake(desiredWidth, desiredHeight))];

NSNotification Scrolling - User vs Programmatic

I have a program with an NSTextView (actually, a custom subclass) into which a lot of lines of data are likely to be programmatically inserted. (It reads a stream of serial data from a USB port.) I have a checkbox for enabling/disabling autoscrolling. I want to allow the user to break out of autoscrolling simply by trying to scroll back up. So, I need a notification that tells me when the user has scrolled, not just when the bounds have changed, since this happens every time more serial data gets inserted. Is this possible?
Surely you could use the notification that tells you when any scrolling takes place, and then check if the text view is scrolled entirely to the bottom? If it is, turn auto-scrolling on. If not, turn it off.
It's not the best, but this works in my case. I think it could be done a little cleaner with some NSEvent manipulation, but I realized that I can check to see if the user has started scrolling by checking the current scroll position against the total document rectangle height.
NSRect totalRect = [[serialScrollView contentView] documentRect];
NSRect visibleRect = [[serialScrollView contentView] documentVisibleRect];
NSInteger totalHeight = totalRect.size.height;
NSInteger visibleHeight = visibleRect.size.height;
NSInteger position = visibleRect.origin.y;
NSInteger scrollPoint = position + visibleHeight;
if (totalHeight != scrollPoint)
[autoscrolls setState:0];
So basically, if the scroll position becomes anything other than what the program expects it to be from programmatic writes, it turns autoscrolling off. A cool thing about this implementation is that if you ad an else [autoscrolls setState:1];, it turns autoscrolling back on when you scroll back down to catch up with the stream. This emulates the scrolling behavior in the terminal when you're running a shell script with lots of output, like a yum install on Fedora or that sort of thing.