Skip to content

Commit

Permalink
Keyboard avoiding count algorithm changed
Browse files Browse the repository at this point in the history
  • Loading branch information
Evgeniy Kirpichenko authored and Evgeniy Kirpichenko committed Dec 7, 2012
1 parent c34e6bb commit e88280e
Show file tree
Hide file tree
Showing 16 changed files with 512 additions and 25 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ DerivedData
.DS*
*.xcworkspace
xcuserdata
Pods
Podfile.lock
12 changes: 12 additions & 0 deletions EKKeyboardAvoidingScrollView.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
D921D05016721EF500AF97A7 /* CGRectTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = D921D04F16721EF500AF97A7 /* CGRectTransform.h */; settings = {ATTRIBUTES = (); }; };
D9F3BB35166F4B8A00F0DEAE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9F3BB34166F4B8A00F0DEAE /* Foundation.framework */; };
D9F3BB3A166F4B8A00F0DEAE /* EKKeyboardAvoidingScrollView.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = D9F3BB39166F4B8A00F0DEAE /* EKKeyboardAvoidingScrollView.h */; };
D9F3BB3C166F4B8A00F0DEAE /* EKKeyboardAvoidingScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = D9F3BB3B166F4B8A00F0DEAE /* EKKeyboardAvoidingScrollView.m */; };
Expand All @@ -30,6 +31,7 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
D921D04F16721EF500AF97A7 /* CGRectTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CGRectTransform.h; sourceTree = "<group>"; };
D9F3BB31166F4B8A00F0DEAE /* libEKKeyboardAvoidingScrollView.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libEKKeyboardAvoidingScrollView.a; sourceTree = BUILT_PRODUCTS_DIR; };
D9F3BB34166F4B8A00F0DEAE /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
D9F3BB38166F4B8A00F0DEAE /* EKKeyboardAvoidingScrollView-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "EKKeyboardAvoidingScrollView-Prefix.pch"; sourceTree = "<group>"; };
Expand All @@ -51,6 +53,14 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
D921D054167222D200AF97A7 /* CGRectTransform */ = {
isa = PBXGroup;
children = (
D921D04F16721EF500AF97A7 /* CGRectTransform.h */,
);
name = CGRectTransform;
sourceTree = "<group>";
};
D9F3BB26166F4B8A00F0DEAE = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -84,6 +94,7 @@
D9F3BB39166F4B8A00F0DEAE /* EKKeyboardAvoidingScrollView.h */,
D9F3BB3B166F4B8A00F0DEAE /* EKKeyboardAvoidingScrollView.m */,
D9F3BB37166F4B8A00F0DEAE /* Supporting Files */,
D921D054167222D200AF97A7 /* CGRectTransform */,
);
path = EKKeyboardAvoidingScrollView;
sourceTree = "<group>";
Expand All @@ -104,6 +115,7 @@
buildActionMask = 2147483647;
files = (
D9F3BB95166F6A9200F0DEAE /* EKKeyboardAvoidingScrollViewManger.h in Headers */,
D921D05016721EF500AF97A7 /* CGRectTransform.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
41 changes: 41 additions & 0 deletions EKKeyboardAvoidingScrollView/CGRectTransform.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// CGRectTransform.h
// EKKeyboardAvoidingScrollView
//
// Created by Evgeniy Kirpichenko on 12/7/12.
// Copyright (c) 2012 Evgeniy Kirpichenko. All rights reserved.
//

//

#import <UIKit/UIKit.h>

typedef enum {
CGRectTransformRotateLeft,
CGRectTransformRotateRight,
CGRectTransformExpand
} CGRectTransform;

CGRect CGRectTransformed(CGRect rect, CGSize viewSize, CGRectTransform transform)
{
switch (transform) {
case CGRectTransformRotateLeft:
return CGRectMake(rect.origin.y,
viewSize.width - CGRectGetMaxX(rect),
rect.size.height,
rect.size.width);
case CGRectTransformRotateRight:
return CGRectMake(viewSize.height - CGRectGetMaxY(rect),
rect.origin.x,
rect.size.height,
rect.size.width);
case CGRectTransformExpand:
return CGRectMake(viewSize.width - CGRectGetMaxX(rect),
viewSize.height - CGRectGetMaxY(rect),
rect.size.width,
rect.size.height);
default:
return rect;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#endif

139 changes: 119 additions & 20 deletions EKKeyboardAvoidingScrollView/EKKeyboardAvoidingScrollViewManger.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,20 @@
//

#import "EKKeyboardAvoidingScrollViewManger.h"
#import "CGRectTransform.h"

#import <objc/objc-runtime.h>

@interface RegisteredScrollPack : NSObject
@property (nonatomic, assign) UIScrollView *scrollView;
@property (nonatomic, assign) UIEdgeInsets scrollDefaultInsets;
@end

@implementation RegisteredScrollPack
@end

- (void) dealloc
{
[self setScrollView:nil];
[super dealloc];
}

@end
//NSString *const kFrameKeyPath = @"frame";

static EKKeyboardAvoidingScrollViewManger *kUIScrollViewDisplayManager;

Expand Down Expand Up @@ -70,6 +69,11 @@ - (void) registerScrollViewForKeyboardAvoiding:(UIScrollView *) scrollView
scrollPack = [self prepareScrollPackWithScrollView:scrollView];
[registeredScrolls addObject:scrollPack];
[self updateRegisteredScroll:scrollPack];

// [scrollView addObserver:self
// forKeyPath:kFrameKeyPath
// options:NSKeyValueObservingOptionNew
// context:nil];
}
}
}
Expand All @@ -80,7 +84,9 @@ - (void) unregisterScrollViewFromKeyboardAvoiding:(UIScrollView *) scrollView
if (scrollView != nil) {
RegisteredScrollPack *scrollPack = [self registeredScrollForView:scrollView];
if (scrollPack != nil) {
[scrollView window];
[scrollView setContentInset:[scrollPack scrollDefaultInsets]];
// [scrollView removeObserver:self forKeyPath:kFrameKeyPath context:nil];
[registeredScrolls removeObject:scrollPack];
}
}
Expand All @@ -105,7 +111,7 @@ - (void) keyboardFrameDidChange:(NSNotification *) notification
[self setKeyboardFrame:[keyboardFrameValue CGRectValue]];
[self updateRegisteredScrolls];

NSLog(@"scrolls count = %d",[registeredScrolls count]);
NSLog(@"keyboardframe = %@",NSStringFromCGRect([self keyboardFrame]));
}

#pragma mark -
Expand Down Expand Up @@ -146,24 +152,117 @@ - (void) updateRegisteredScroll:(RegisteredScrollPack *) scrollPack

- (UIEdgeInsets) scrollViewContentInsets:(RegisteredScrollPack *) scrollPack
{
UIEdgeInsets insets = [scrollPack scrollDefaultInsets];
UIScrollView *scrollView = [scrollPack scrollView];

CGRect scrollViewFrame = [[scrollView superview] convertRect:[scrollView frame] toView:nil];
NSLog(@"wind scrollviewframe = %@",NSStringFromCGRect(scrollViewFrame));
// fromView:nil];

CGRect transformedScrollFrame = [self transformCGRectToDefaultCoordinates:scrollViewFrame];
CGRect transformedKeyboardFrame = [self transformCGRectToDefaultCoordinates:[self keyboardFrame]];




UIEdgeInsets inset = [self contentInsetWithDefaultInset:[scrollPack scrollDefaultInsets]
viewFrame:transformedScrollFrame
keyboardFrame:transformedKeyboardFrame];
NSLog(@"inset = %@",NSStringFromUIEdgeInsets(inset));
NSLog(@"transf keyb = %@",NSStringFromCGRect(transformedKeyboardFrame));
NSLog(@"transformedScrollFrame = %@",NSStringFromCGRect(transformedScrollFrame));

return [self contentInsetWithDefaultInset:[scrollPack scrollDefaultInsets]
viewFrame:transformedScrollFrame
keyboardFrame:transformedKeyboardFrame];

// return insets;
}

CGRect scrollViewFrame = [[scrollPack scrollView] frame];
CGRect keyboardRect = [[[scrollPack scrollView] superview] convertRect:[self keyboardFrame]
fromView:nil];
if (CGRectIntersectsRect(keyboardRect, scrollViewFrame) &&
!CGRectEqualToRect(keyboardRect, CGRectZero) &&
!CGRectContainsRect(keyboardRect, scrollViewFrame))
#pragma mark -
#pragma mark geometry

- (UIEdgeInsets) contentInsetWithDefaultInset:(UIEdgeInsets) inset
viewFrame:(CGRect) scrollViewFrame
keyboardFrame:(CGRect) keyboardFrame
{
UIEdgeInsets contentInset = inset;
if (CGRectIntersectsRect(keyboardFrame, scrollViewFrame) &&
!CGRectEqualToRect(keyboardFrame, CGRectZero) &&
!CGRectContainsRect(keyboardFrame, scrollViewFrame))
{
if (keyboardRect.origin.y <= scrollViewFrame.origin.y) {
insets.top += CGRectGetMaxY(keyboardRect) - CGRectGetMinY(scrollViewFrame);
if (keyboardFrame.origin.y <= scrollViewFrame.origin.y) {
contentInset.top += CGRectGetMaxY(keyboardFrame) - CGRectGetMinY(scrollViewFrame);
}
else if (keyboardRect.origin.y <= CGRectGetMaxY(scrollViewFrame) &&
CGRectGetMaxY(keyboardRect) >= CGRectGetMaxY(scrollViewFrame)) {
insets.bottom += CGRectGetMaxY(scrollViewFrame) - CGRectGetMinY(keyboardRect);
else if (keyboardFrame.origin.y <= CGRectGetMaxY(scrollViewFrame) &&
CGRectGetMaxY(keyboardFrame) >= CGRectGetMaxY(scrollViewFrame)) {
contentInset.bottom += CGRectGetMaxY(scrollViewFrame) - CGRectGetMinY(keyboardFrame);
}
}
return insets;
return contentInset;
}

- (CGRect) transformCGRectToDefaultCoordinates:(CGRect) rect
{
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGSize windowSize = [[[[UIApplication sharedApplication] windows] objectAtIndex:0] frame].size;
return [self transformCGRect:rect inViewWithSize:windowSize withOrientation:orientation];
}

- (CGRect) transformCGRect:(CGRect) rect
inViewWithSize:(CGSize) size
withOrientation:(UIInterfaceOrientation) orientation
{
switch (orientation) {
case UIInterfaceOrientationLandscapeRight:
return CGRectTransformed(rect, size, CGRectTransformRotateLeft);
case UIInterfaceOrientationLandscapeLeft:
return CGRectTransformed(rect, size, CGRectTransformRotateRight);
case UIInterfaceOrientationPortraitUpsideDown:
return CGRectTransformed(rect, size, CGRectTransformExpand);
default:
return rect;
}
}

#pragma mark -
#pragma mark scroll frame changes observing

- (void) observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
NSLog(@"data = %@",change);
NSLog(@"scroll frame = %@",NSStringFromCGRect([object frame]));
RegisteredScrollPack *scrollPack = [self registeredScrollForView:object];
[self updateRegisteredScroll:scrollPack];
}


#pragma mark -
#pragma mark window observing

- (void) registerForWindowObserving:(void (^)(id _self, UIView* subview)) listener
{
if (listener == NULL ) {
NSLog(@"listener cannot be NULL.");
return;
}

Method setWindowMethod = class_getInstanceMethod([UIView class], @selector(setWindow:));
IMP originalImplementation = method_getImplementation(setWindowMethod);

void (^block)(id, UIWindow*) = ^(id _self, UIWindow* window) {
originalImplementation(_self, @selector(setWindow:), window);
listener(_self, window);
};

IMP newImplementation = imp_implementationWithBlock((void*)block);
method_setImplementation(setWindowMethod, newImplementation);
}

- (void) unregisterForWindowObserving {

}

@end
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>mls.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Prefix header for all source files of the 'EKKeyboardAvoidingScrollViewExample-unit_tests' target in the 'EKKeyboardAvoidingScrollViewExample-unit_tests' project
//

#import <Availability.h>

#ifndef __IPHONE_3_0
#warning "This project uses features only available in iOS SDK 3.0 and later."
#endif

#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

#import <Cedar-iOS/SpecHelper.h>
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#import <UIKit/UIKit.h>
#import <EKKeyboardAvoidingScrollView/CGRectTransform.h>

using namespace Cedar::Matchers;
using namespace Cedar::Doubles;

SPEC_BEGIN(CGRectTransforming)

describe(@"CGRect transformation:", ^{
context(@"CGRectTransformLeft",^{
it(@"Rectangle {{10,15},{50,100}} in view with size {320,480} should be transformed to {{15,260},{100,50}}", ^{
CGRect baseRect = CGRectMake(10, 15, 50, 100);
CGRect transformedRect = CGRectTransformed(baseRect, {320,480}, CGRectTransformRotateLeft);
expect(transformedRect.origin.x).to(equal(15));
expect(transformedRect.origin.y).to(equal(260));
expect(transformedRect.size.width).to(equal(100));
expect(transformedRect.size.height).to(equal(50));
});
});

context(@"CGRectTransformRight",^{
it(@"Rectangle {{10,15},{50,100}} in view with size {320,480} should be transformed to {{365,10},{100,50}}", ^{
CGRect baseRect = CGRectMake(10, 15, 50, 100);
CGRect transformedRect = CGRectTransformed(baseRect, {320,480}, CGRectTransformRotateRight);
expect(transformedRect.origin.x).to(equal(365));
expect(transformedRect.origin.y).to(equal(10));
expect(transformedRect.size.width).to(equal(100));
expect(transformedRect.size.height).to(equal(50));
});
});

context(@"CGRectTransformExpand",^{
it(@"Rectangle {{10,15},{50,100}} in view with size {320,480} should be transformed to {{260,365},{50,100}}", ^{
CGRect baseRect = CGRectMake(10, 15, 50, 100);
CGRect transformedRect = CGRectTransformed(baseRect, {320,480}, CGRectTransformExpand);
expect(transformedRect.origin.x).to(equal(260));
expect(transformedRect.origin.y).to(equal(365));
expect(transformedRect.size.width).to(equal(50));
expect(transformedRect.size.height).to(equal(100));
});
});
});

SPEC_END

Loading

0 comments on commit e88280e

Please sign in to comment.