How to set scrollView with minimal scale at start? - objective-c

I have to set UIScrollView at start with 0.28 scale (current scale). How can i do it correclty?
Now to scaling I'm using this methods:
#pragma mark - UIScrollViewDelegate Methods
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return imageView;
}
-(void)scrollViewDidZoom:(UIScrollView *)scrollView {
[self centerScrollViewContent];
}
-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
}
- (void)centerScrollViewContent {
CGSize boundsSize = self.scrollView.bounds.size;
CGRect contentsFrame = imageView.frame;
if (contentsFrame.size.width < boundsSize.width) {
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0f;
} else {
contentsFrame.origin.x = 0.0f;
}
if (contentsFrame.size.height < boundsSize.height) {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
} else {
contentsFrame.origin.y = 0.0f;
}
imageView.frame = contentsFrame;
}

After your scrollView content is loaded, you can set the zoom scale with:
self.scrollView.zoomScale = 0.28;

Related

Keep UIView fixed when attached to UIWindow in iOS8

Up until iOS7, if I wanted to create a sort of a fixed "background" that would not rotate, animate or scale whatsoever, I would have simply attached a UIView to the main UIWindow.
It was a kind of hack... but it served very well its purpose.
In iOS8 they changed the way UIWindow behave among other things (for example now [UIScreen mainScreen].bounds returns different size depending on the orientation).
Anyway...
My question is: how do I get iOS8 to behave as iOS7 and below?
I tried already to create two ViewControllers, one with shouldAutorotate method set to NO but with no luck.
The desired effect is the one shown here:
Any ideas?
If you build your app using iOS8 SDK, you can use nativeBounds, which will always return bounds for portrait orientation, but in the pixels, not in the points.
To get right bounds in points you should divide them by nativeScale.
if ([[UIScreen mainScreen] respondsToSelector:#selector(nativeBounds)]) {
CGFloat scaleFactor = 1.0f / [self nativeScale];
CGRect realBounds = CGRectApplyAffineTransform([self nativeBounds],
CGAffineTransformMakeScale(scaleFactor, scaleFactor));
}
So I think you can subscribe to didChangeStatusBarOrientation notification and in your method calculate new frame for green square and justify rotation:
rect.transform = CGAffineTransformMakeRotation((CGFloat)M_PI * (90.f) / 180.0f);
for landscape right orientation
try to use this subclass with fixed rotation:
#interface RotationView : UIView {
struct {
CGPoint portOrigin;
CGPoint leftOrigin;
CGPoint rightOrigin;
CGPoint upsideOrigin;
} origins;
struct {
NSInteger portDegree;
NSInteger leftDegree;
NSInteger rightDegree;
NSInteger upsideDegree;
} degrees;
}
#end
#implementation RotationView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceOrientationDidChange:)
name:UIDeviceOrientationDidChangeNotification object:nil];
}
return self;
}
- (void)didMoveToSuperview {
[super didMoveToSuperview];
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (orientation == UIInterfaceOrientationPortrait) {
origins.portOrigin = self.frame.origin;
origins.rightOrigin = CGPointMake(CGRectGetMinY(self.frame), CGRectGetWidth(self.superview.frame) - CGRectGetMinX(self.frame) - CGRectGetWidth(self.frame));
origins.leftOrigin = CGPointMake(CGRectGetHeight(self.superview.frame) - CGRectGetMinY(self.frame) - CGRectGetHeight(self.frame), CGRectGetMinX(self.frame));
origins.upsideOrigin = CGPointMake(CGRectGetWidth(self.superview.frame) - CGRectGetMinX(self.frame) - CGRectGetWidth(self.frame),
CGRectGetHeight(self.superview.frame) - CGRectGetMinY(self.frame) - CGRectGetHeight(self.frame));
degrees.portDegree = 0.0F;
degrees.rightDegree = 270;
degrees.leftDegree = 90.0F;
degrees.upsideDegree = 180.0F;
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
origins.portOrigin = CGPointMake(CGRectGetWidth(self.superview.frame) - CGRectGetMinX(self.frame) - CGRectGetWidth(self.frame),
CGRectGetHeight(self.superview.frame) - CGRectGetMinY(self.frame) - CGRectGetHeight(self.frame));
origins.leftOrigin = CGPointMake(CGRectGetMinY(self.frame), CGRectGetWidth(self.superview.frame) - CGRectGetMinX(self.frame) - CGRectGetWidth(self.frame));
origins.rightOrigin = CGPointMake(CGRectGetHeight(self.superview.frame) - CGRectGetMinY(self.frame) - CGRectGetHeight(self.frame), CGRectGetMinX(self.frame));
origins.upsideOrigin = self.frame.origin;
degrees.portDegree = 180.0F;
degrees.rightDegree = 90.0F;
degrees.leftDegree = 270;
degrees.upsideDegree = 0.0F;
} else if (orientation == UIInterfaceOrientationLandscapeLeft) {
origins.upsideOrigin = CGPointMake(CGRectGetHeight(self.superview.frame) - CGRectGetMinY(self.frame) - CGRectGetHeight(self.frame), CGRectGetMinX(self.frame));
origins.leftOrigin = self.frame.origin;
origins.rightOrigin = CGPointMake(CGRectGetWidth(self.superview.frame) - CGRectGetMinX(self.frame) - CGRectGetWidth(self.frame),
CGRectGetHeight(self.superview.frame) - CGRectGetMinY(self.frame) - CGRectGetHeight(self.frame));
origins.portOrigin = CGPointMake(CGRectGetMinY(self.frame), CGRectGetWidth(self.superview.frame) - CGRectGetMinX(self.frame) - CGRectGetWidth(self.frame));
degrees.upsideDegree = 90.0F;
degrees.leftDegree = 0.0F;
degrees.rightDegree = 180.0F;
degrees.portDegree = 270.0;
} else if (orientation == UIInterfaceOrientationLandscapeRight) {
origins.portOrigin = CGPointMake(CGRectGetHeight(self.superview.frame) - CGRectGetMinY(self.frame) - CGRectGetHeight(self.frame), CGRectGetMinX(self.frame));
origins.leftOrigin = CGPointMake(CGRectGetWidth(self.superview.frame) - CGRectGetMinX(self.frame) - CGRectGetWidth(self.frame),
CGRectGetHeight(self.superview.frame) - CGRectGetMinY(self.frame) - CGRectGetHeight(self.frame));
origins.rightOrigin = self.frame.origin;
origins.upsideOrigin = CGPointMake(CGRectGetMinY(self.frame), CGRectGetWidth(self.superview.frame) - CGRectGetMinX(self.frame) - CGRectGetWidth(self.frame));
degrees.portDegree = 90.0F;
degrees.leftDegree = 180.0F;
degrees.rightDegree = 0.0F;
degrees.upsideDegree = 270.0F;
}
}
#pragma mark Manual oritentation change
#define RADIANS(degrees) ((degrees * (float)M_PI) / 180.0f)
- (void)deviceOrientationDidChange:(NSNotification *)notification {
if (!self.superview) {
return;
}
if ([self.superview isKindOfClass:[UIWindow class]]) {
[self setTransformForCurrentOrientation];
}
}
- (void)setTransformForCurrentOrientation {
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UIInterfaceOrientationIsLandscape(orientation)) {
if (orientation == UIInterfaceOrientationLandscapeLeft) {
[self setTransform:CGAffineTransformMakeRotation(RADIANS(degrees.leftDegree))];
[self setOrigin:origins.leftOrigin];
} else {
[self setTransform:CGAffineTransformMakeRotation(RADIANS(degrees.rightDegree))];
[self setOrigin:origins.rightOrigin];
}
} else {
if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
[self setTransform:CGAffineTransformMakeRotation(RADIANS(degrees.upsideDegree))];
[self setOrigin:origins.upsideOrigin];
} else {
[self setTransform:CGAffineTransformMakeRotation(RADIANS(degrees.portDegree))];
[self setOrigin:origins.portOrigin];
}
}
}
#end
setOrigin is category method:
- (void)setX:(CGFloat)x {
CGRect frame = self.frame;
frame.origin.x = x;
self.frame = frame;
}
- (void)setY:(CGFloat)y {
CGRect frame = self.frame;
frame.origin.y = y;
self.frame = frame;
}
- (void)setOrigin:(CGPoint)origin {
[self setX:origin.x];
[self setY:origin.y];
}

Tableview scroll to top not going all the way

I have a navigation bar that I've manually coded to animate the frame of depending on the offset of the scrollView (tableView). Below is a screenshot of what it looks like unscrolled.
Now after setScrollOffset:(0,0) is invoked (by scrollsToTop, not me manually - e.g. by tapping status bar), the scrollview scrolls to the top, but at the position at which there used to be no navigation bar. I can manually scroll the last 44px or so after the animation happens, but obviously thats not the behavior that's expected.
Here is my code for hiding the navbar:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGRect frame = self.navigationController.navigationBar.frame;
CGFloat size = frame.size.height - kMacro1;
CGFloat framePercentageHidden = ((kMacro2 - frame.origin.y) / (frame.size.height - 1));
CGFloat scrollOffset = scrollView.contentOffset.y;
CGFloat scrollDiff = scrollOffset - self.previousScrollViewYOffset;
CGFloat scrollHeight = scrollView.frame.size.height;
CGFloat scrollContentSizeHeight = scrollView.contentSize.height + scrollView.contentInset.bottom;
if (scrollOffset <= -scrollView.contentInset.top) {
frame.origin.y = kMacro2;
} else if ((scrollOffset + scrollHeight) >= scrollContentSizeHeight) {
frame.origin.y = -size;
} else {
frame.origin.y = MIN(kMacro2, MAX(-size, frame.origin.y - scrollDiff));
}
[self.navigationController.navigationBar setFrame:frame];
[self updateBarButtonItems:(1 - framePercentageHidden)];
self.previousScrollViewYOffset = scrollOffset;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self stoppedScrolling];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView
willDecelerate:(BOOL)decelerate
{
if (!decelerate) {
[self stoppedScrolling];
}
}
- (void)stoppedScrolling
{
CGRect frame = self.navigationController.navigationBar.frame;
if (frame.origin.y < kMacro2) {
[self animateNavBarTo:-(frame.size.height - kMacro1)];
}
}
- (void)animateNavBarTo:(CGFloat)y
{
[UIView animateWithDuration:0.2 animations:^{
CGRect frame = self.navigationController.navigationBar.frame;
CGFloat alpha = (frame.origin.y >= y ? 0 : 1);
frame.origin.y = y;
[self.navigationController.navigationBar setFrame:frame];
[self updateBarButtonItems:alpha];
}];
}

Animating UINavigationBar in iOS 7 (like Safari)

When scrolling content in Safari, the title bar animates to a smaller version of its self. What is the best way to implement this?
Currently, I am changing the size of the frame like so:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//
// Table view
//
CGFloat currentPosition = scrollView.contentOffset.y - CGRectGetHeight(self.tableView.tableHeaderView.frame) + CGRectGetHeight(self.navigationController.navigationBar.frame) + CGRectGetHeight([[UIApplication sharedApplication] statusBarFrame]);
if ([scrollView isKindOfClass:[HeadlinesHeadlinesTableView class]]) {
ScrollDirection scrollDirection;
if (self.lastContentOffset > scrollView.contentOffset.y) {
scrollDirection = ScrollDirectionDown;
} else if (self.lastContentOffset < scrollView.contentOffset.y) {
scrollDirection = ScrollDirectionUp;
}
self.lastContentOffset = scrollView.contentOffset.y;
CGRect frame = self.navigationController.navigationBar.frame;
CGFloat minimumFrameHeight = 30.0f;
CGFloat maximumFrameHeight = 44.0f;
CGFloat titleSize = [[self.navigationController.navigationBar.titleTextAttributes objectForKey:NSFontAttributeName] pointSize];
CGFloat minimumTitleHeight = 22.0f;
CGFloat maximumTitleHeight = 30.0f;
if (currentPosition > 0 && CGRectGetHeight(frame) >= minimumFrameHeight && CGRectGetHeight(frame) <= maximumFrameHeight) {
switch (scrollDirection) {
case ScrollDirectionUp:
frame.size.height--;
titleSize--;
break;
case ScrollDirectionDown:
frame.size.height++;
titleSize++;
break;
default:
break;
}
if (CGRectGetHeight(frame) <= minimumFrameHeight) {
frame.size.height = minimumFrameHeight;
}
if (CGRectGetHeight(frame) >= maximumFrameHeight) {
frame.size.height = maximumFrameHeight;
}
if (titleSize <= minimumTitleHeight) {
titleSize = minimumTitleHeight;
}
if (titleSize >= maximumTitleHeight) {
titleSize = maximumTitleHeight;
}
}
[self.navigationController.navigationBar setFrame:frame];
[self.navigationController.navigationBar setTitleTextAttributes: #{ NSFontAttributeName : [UIFont fontWithName:#"Canterbury-Regular" size:titleSize] }];
}
}
Naturally, this way is not smooth and a lot of code, not to mention the fact that I need to fade out bar button items as well.
Thanks in advance!
Take a look at AMScrollingNavbar, it already has fading support.
You can try to change font size of NavigationBar to make the title smaller.

How to center UIImageView in ScrollView (Zooming)

I'm trying to zooming UIImageView in UIScrollView. And i've got this:
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return imageView;
}
-(void)scrollViewDidZoom:(UIScrollView *)scrollView {
[imageView setCenter:CGPointMake(scrollView.center.x, scrollView.center.y)];
}
-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
}
Problem is: When i'm zooming out image it's centered, but when i'm zooming in, image is shifted to left up corner.
Where is problem with my code?
Answer is remove all from scrollViewDidZoom: and add:
[self centerScrollViewContent];
Method implementation:
- (void)centerScrollViewContents {
CGSize boundsSize = self.scrollView.bounds.size;
CGRect contentsFrame = self.containerView.frame;
if (contentsFrame.size.width < boundsSize.width) {
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0f;
} else {
contentsFrame.origin.x = 0.0f;
}
if (contentsFrame.size.height < boundsSize.height) {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
} else {
contentsFrame.origin.y = 0.0f;
}
self.containerView.frame = contentsFrame;
}

Converting between Cocoa and Carbon coordinates?

I am looking for a robust (I mean working in all multi-munitor configuration) algo to convert a cocoa point/rect to carbon equivalent and the reverse operation.
I've googled but was unable to find something which work properly.
Thanks in advance for your help.
Regards,
After several iterations I got to the following category on NSScreen:
+ (NSScreen*) screenWithPoint: (NSPoint) p
{
for (NSScreen *candidate in [NSScreen screens])
if (NSPointInRect(p, [candidate frame]))
return candidate;
return nil;
}
+ (NSScreen*) screenWithMenuBar
{
return [self screenWithPoint:NSZeroPoint];
}
+ (float) menuScreenHeight
{
return NSMaxY([[self screenWithMenuBar] frame]);
}
+ (CGPoint) carbonPointFrom: (NSPoint) cocoaPoint
{
return CGPointMake(cocoaPoint.x, [self menuScreenHeight] - cocoaPoint.y);
}
+ (NSPoint) cocoaPointFrom: (CGPoint) carbonPoint
{
return NSMakePoint(carbonPoint.x, [self menuScreenHeight] - carbonPoint.y);
}
This works fine even with multiple displays.
The posted code from Apple's code from UIElementInspector turn out to be buggy, in that it doesn't account for the origin of a non-main screen. The fixed (and refactored) code looks like this:
+ (CGPoint)carbonScreenPointFromCocoaScreenPoint:(NSPoint)cocoaPoint {
NSScreen* foundScreen = nil;
NSRect screenFrame;
for (NSScreen* screen in [NSScreen screens]) {
screenFrame = [screen frame];
if (NSPointInRect(cocoaPoint, screenFrame)) {
foundScreen = screen;
break;
}
}
if (! foundScreen) return CGPointMake(0.0, 0.0);
return CGPointMake(cocoaPoint.x,
screenFrame.origin.y + screenFrame.size.height - cocoaPoint.y);
}
Or take Apple's code from UIElementInspector sample project:
+ (CGPoint)carbonScreenPointFromCocoaScreenPoint:(NSPoint)cocoaPoint
{
NSScreen *foundScreen = nil;
CGPoint thePoint;
for (NSScreen *screen in [NSScreen screens])
{
if (NSPointInRect(cocoaPoint, [screen frame]))
{
foundScreen = screen;
}
}
if (foundScreen)
{
CGFloat screenHeight = [foundScreen frame].size.height;
thePoint = CGPointMake(cocoaPoint.x, screenHeight - cocoaPoint.y - 1);
}
else
{
thePoint = CGPointMake(0.0, 0.0);
}
return thePoint;
}