├── Images
└── InterfaceBuilderSubclassExample.png
├── Tests
├── KGHitTestingViewsTests.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── project.pbxproj
└── KGHitTestingViewsTests
│ ├── Info.plist
│ ├── KGHitTestBaseTest.h
│ ├── KGHitTestViewTests.m
│ ├── KGHitTestButtonTests.m
│ ├── KGHitTestControlTests.m
│ ├── KGHitTestBaseTest.m
│ └── KGHitTestCategoryTests.m
├── Example
├── KGHitTestingViewsExample.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── project.pbxproj
└── KGHitTestingViewsExample
│ ├── ViewController.h
│ ├── AppDelegate.h
│ ├── main.m
│ ├── AppDelegate.m
│ ├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ └── Contents.json
│ ├── Info.plist
│ ├── Base.lproj
│ ├── LaunchScreen.xib
│ └── Main.storyboard
│ └── ViewController.m
├── .gitignore
├── KGHitTestingViews.podspec
├── LICENSE
├── KGHitTestingViews
├── UIView+KGHitTesting.h
├── KGHitTestingHelper.h
├── KGHitTestingView.m
├── KGHitTestingButton.m
├── KGHitTestingControl.m
├── KGHitTesting.h
├── KGHitTestingHelper.m
├── KGHitTestingView.h
├── KGHitTestingButton.h
├── KGHitTestingControl.h
└── UIView+KGHitTesting.m
└── README.md
/Images/InterfaceBuilderSubclassExample.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kgaidis/KGHitTestingViews/HEAD/Images/InterfaceBuilderSubclassExample.png
--------------------------------------------------------------------------------
/Tests/KGHitTestingViewsTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/KGHitTestingViewsExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | *.pbxuser
3 | !default.pbxuser
4 | *.mode1v3
5 | !default.mode1v3
6 | *.mode2v3
7 | !default.mode2v3
8 | *.perspectivev3
9 | !default.perspectivev3
10 | xcuserdata
11 | *.xccheckout
12 | *.moved-aside
13 | DerivedData
14 | *.hmap
15 | *.ipa
16 | *.xcuserstate
17 | .DS_Store
--------------------------------------------------------------------------------
/Example/KGHitTestingViewsExample/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // KGHitTestingViewsExample
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | // Copyright (c) 2015 Krisjanis Gaidis. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 | @end
--------------------------------------------------------------------------------
/Example/KGHitTestingViewsExample/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // KGHitTestingViewsExample
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | // Copyright (c) 2015 Krisjanis Gaidis. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
--------------------------------------------------------------------------------
/Example/KGHitTestingViewsExample/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // KGHitTestingViewsExample
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | // Copyright (c) 2015 Krisjanis Gaidis. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Example/KGHitTestingViewsExample/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // KGHitTestingViewsExample
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | // Copyright (c) 2015 Krisjanis Gaidis. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
18 | // Override point for customization after application launch.
19 | return YES;
20 | }
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/KGHitTestingViews.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'KGHitTestingViews'
3 | s.version = '0.9.5'
4 | s.license = { :type => "MIT", :file => "LICENSE" }
5 | s.summary = 'A small helper library to effortlessly increase the hit test area of a view, control or a button.'
6 | s.author = { 'Krisjanis Gaidis' => 'http://www.krisjanisgaidis.com/' }
7 | s.source = { :git => 'https://github.com/kgaidis/KGHitTestingViews.git', :tag => '0.9.5' }
8 | s.homepage = 'http://github.com/kgaidis/KGHitTestingViews'
9 | s.source_files = 'KGHitTestingViews'
10 | s.platform = :ios, "6.0"
11 | s.requires_arc = true
12 |
13 | end
--------------------------------------------------------------------------------
/Example/KGHitTestingViewsExample/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/Tests/KGHitTestingViewsTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | com.kg.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/KGHitTestingViewsExample/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "minimum-system-version" : "7.0",
7 | "subtype" : "retina4",
8 | "scale" : "2x"
9 | },
10 | {
11 | "idiom" : "iphone",
12 | "scale" : "1x",
13 | "orientation" : "portrait"
14 | },
15 | {
16 | "idiom" : "iphone",
17 | "scale" : "2x",
18 | "orientation" : "portrait"
19 | },
20 | {
21 | "orientation" : "portrait",
22 | "idiom" : "iphone",
23 | "subtype" : "retina4",
24 | "scale" : "2x"
25 | },
26 | {
27 | "orientation" : "portrait",
28 | "idiom" : "iphone",
29 | "minimum-system-version" : "7.0",
30 | "scale" : "2x"
31 | }
32 | ],
33 | "info" : {
34 | "version" : 1,
35 | "author" : "xcode"
36 | }
37 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This code is distributed under the terms and conditions of the MIT license.
2 |
3 | Copyright (c) 2014-2015 Krisjanis Gaidis
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/Tests/KGHitTestingViewsTests/KGHitTestBaseTest.h:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestBaseTest.h
3 | // KGHitTestingViewsTests
4 | //
5 | // Created by Krisjanis Gaidis on 5/10/15.
6 | //
7 | //
8 |
9 | #import
10 | #import
11 | #import
12 | #import "KGHitTesting.h"
13 |
14 | static const CGFloat kWidth = 10.0;
15 | static const CGFloat kHeight = 10.0;
16 | static const CGFloat kMinimumHitTestWidth = 20.0;
17 | static const CGFloat kMinimumHitTestHeight = 20.0;
18 |
19 | static const CGFloat kWidthOffset = (kMinimumHitTestWidth - kWidth) / 2;
20 | static const CGFloat kHeightOffset = (kMinimumHitTestHeight - kHeight) / 2;
21 |
22 | @interface KGHitTestBaseTest : XCTestCase
23 |
24 | @property (strong, nonatomic) id hitTestObject;
25 |
26 | #pragma mark - Top left corner -
27 | - (void)_testTopLeftCornerInBounds;
28 | - (void)_testTopLeftCornerOutOfBounds;
29 |
30 | #pragma mark - Top right corner -
31 | - (void)_testTopRightCornerInBounds;
32 | - (void)_testTopRightCornerOutOfBounds;
33 |
34 | #pragma mark - Bottom right corner -
35 | - (void)_testBottomRightCornerInBounds;
36 | - (void)_testBottomRightCornerOutOfBounds;
37 |
38 | #pragma mark - Bottom left corner -
39 | - (void)_testBottomLeftCornerInBounds;
40 | - (void)_testBottomLeftCornerOutOfBounds;
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/Example/KGHitTestingViewsExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | com.kg.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Tests/KGHitTestingViewsTests/KGHitTestViewTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestViewTests.m
3 | // KGHitTestingViewsTests
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | //
7 | //
8 |
9 | #import
10 | #import
11 | #import "KGHitTestingView.h"
12 | #import "KGHitTestBaseTest.h"
13 |
14 | @interface KGHitTestViewTests : KGHitTestBaseTest
15 |
16 | @end
17 |
18 | @implementation KGHitTestViewTests
19 |
20 | - (void)setUp {
21 | [super setUp];
22 | // Put setup code here. This method is called before the invocation of each test method in the class.
23 | self.hitTestObject = [[KGHitTestingView alloc] initWithFrame:CGRectMake(0, 0, kWidth, kHeight)];
24 | }
25 |
26 | #pragma mark - Top left corner -
27 | - (void)testTopLeftCornerInBounds { [self _testTopLeftCornerInBounds]; }
28 | - (void)testTopLeftCornerOutOfBounds { [self _testTopLeftCornerOutOfBounds]; }
29 |
30 | #pragma mark - Top right corner -
31 | - (void)testTopRightCornerInBounds { [self _testTopRightCornerInBounds]; }
32 | - (void)testTopRightCornerOutOfBounds { [self _testTopRightCornerOutOfBounds]; }
33 |
34 | #pragma mark - Bottom right corner -
35 | - (void)testBottomRightCornerInBounds { [self _testBottomRightCornerInBounds]; }
36 | - (void)testBottomRightCornerOutOfBounds { [self _testBottomRightCornerOutOfBounds]; }
37 |
38 | #pragma mark - Bottom left corner -
39 | - (void)testBottomLeftCornerInBounds { [self _testBottomLeftCornerInBounds]; }
40 | - (void)testBottomLeftCornerOutOfBounds { [self _testBottomLeftCornerOutOfBounds]; }
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/Tests/KGHitTestingViewsTests/KGHitTestButtonTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestButtonTests.m
3 | // KGHitTestingButtonsTests
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | //
7 | //
8 |
9 | #import
10 | #import
11 | #import "KGHitTestingButton.h"
12 | #import "KGHitTestBaseTest.h"
13 |
14 | @interface KGHitTestButtonTests : KGHitTestBaseTest
15 |
16 | @end
17 |
18 | @implementation KGHitTestButtonTests
19 |
20 | - (void)setUp {
21 | [super setUp];
22 | // Put setup code here. This method is called before the invocation of each test method in the class.
23 | self.hitTestObject = [[KGHitTestingButton alloc] initWithFrame:CGRectMake(0, 0, kWidth, kHeight)];
24 | }
25 |
26 | #pragma mark - Top left corner -
27 | - (void)testTopLeftCornerInBounds { [self _testTopLeftCornerInBounds]; }
28 | - (void)testTopLeftCornerOutOfBounds { [self _testTopLeftCornerOutOfBounds]; }
29 |
30 | #pragma mark - Top right corner -
31 | - (void)testTopRightCornerInBounds { [self _testTopRightCornerInBounds]; }
32 | - (void)testTopRightCornerOutOfBounds { [self _testTopRightCornerOutOfBounds]; }
33 |
34 | #pragma mark - Bottom right corner -
35 | - (void)testBottomRightCornerInBounds { [self _testBottomRightCornerInBounds]; }
36 | - (void)testBottomRightCornerOutOfBounds { [self _testBottomRightCornerOutOfBounds]; }
37 |
38 | #pragma mark - Bottom left corner -
39 | - (void)testBottomLeftCornerInBounds { [self _testBottomLeftCornerInBounds]; }
40 | - (void)testBottomLeftCornerOutOfBounds { [self _testBottomLeftCornerOutOfBounds]; }
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/Tests/KGHitTestingViewsTests/KGHitTestControlTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestControlTests.m
3 | // KGHitTestingViewsTests
4 | //
5 | // Created by Krisjanis Gaidis on 1/9/16.
6 | //
7 | //
8 |
9 | #import
10 | #import
11 | #import "KGHitTestingControl.h"
12 | #import "KGHitTestBaseTest.h"
13 |
14 | @interface KGHitTestControlTests : KGHitTestBaseTest
15 |
16 | @end
17 |
18 | @implementation KGHitTestControlTests
19 |
20 | - (void)setUp {
21 | [super setUp];
22 | // Put setup code here. This method is called before the invocation of each test method in the class.
23 | self.hitTestObject = [[KGHitTestingControl alloc] initWithFrame:CGRectMake(0, 0, kWidth, kHeight)];
24 | }
25 |
26 | #pragma mark - Top left corner -
27 | - (void)testTopLeftCornerInBounds { [self _testTopLeftCornerInBounds]; }
28 | - (void)testTopLeftCornerOutOfBounds { [self _testTopLeftCornerOutOfBounds]; }
29 |
30 | #pragma mark - Top right corner -
31 | - (void)testTopRightCornerInBounds { [self _testTopRightCornerInBounds]; }
32 | - (void)testTopRightCornerOutOfBounds { [self _testTopRightCornerOutOfBounds]; }
33 |
34 | #pragma mark - Bottom right corner -
35 | - (void)testBottomRightCornerInBounds { [self _testBottomRightCornerInBounds]; }
36 | - (void)testBottomRightCornerOutOfBounds { [self _testBottomRightCornerOutOfBounds]; }
37 |
38 | #pragma mark - Bottom left corner -
39 | - (void)testBottomLeftCornerInBounds { [self _testBottomLeftCornerInBounds]; }
40 | - (void)testBottomLeftCornerOutOfBounds { [self _testBottomLeftCornerOutOfBounds]; }
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/KGHitTestingViews/UIView+KGHitTesting.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+KGHitTesting.h
3 | // KGHitTestingViewsExample
4 | //
5 | // Created by Krisjanis Gaidis on 5/28/16.
6 | //
7 | // This code is distributed under the terms and conditions of the MIT license.
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to
11 | // deal in the Software without restriction, including without limitation the
12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 | // sell copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 | // IN THE SOFTWARE.
26 | //
27 |
28 | #import
29 |
30 | @interface UIView (KGHitTesting)
31 |
32 | - (void)setMinimumHitTestWidth:(CGFloat)width height:(CGFloat)height;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/KGHitTestingViews/KGHitTestingHelper.h:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestingHelper.h
3 | // KGHitTestingViews
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | //
7 | // This code is distributed under the terms and conditions of the MIT license.
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to
11 | // deal in the Software without restriction, including without limitation the
12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 | // sell copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 | // IN THE SOFTWARE.
26 | //
27 |
28 | #import
29 | #import
30 |
31 | CGRect KGHitTestingBounds(CGRect bounds, CGFloat minimumHitTestWidth, CGFloat minimumHitTestHeight);
--------------------------------------------------------------------------------
/KGHitTestingViews/KGHitTestingView.m:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestingView.m
3 | // KGHitTestingViews
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | //
7 | // This code is distributed under the terms and conditions of the MIT license.
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to
11 | // deal in the Software without restriction, including without limitation the
12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 | // sell copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 | // IN THE SOFTWARE.
26 | //
27 |
28 | #import "KGHitTestingView.h"
29 | #import "KGHitTestingHelper.h"
30 |
31 | @implementation KGHitTestingView
32 |
33 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
34 | return CGRectContainsPoint(KGHitTestingBounds(self.bounds, self.minimumHitTestWidth, self.minimumHitTestHeight), point);
35 | }
36 |
37 | @end
--------------------------------------------------------------------------------
/KGHitTestingViews/KGHitTestingButton.m:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestingButton.m
3 | // KGHitTestingViews
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | //
7 | // This code is distributed under the terms and conditions of the MIT license.
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to
11 | // deal in the Software without restriction, including without limitation the
12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 | // sell copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 | // IN THE SOFTWARE.
26 | //
27 |
28 | #import "KGHitTestingButton.h"
29 | #import "KGHitTestingHelper.h"
30 |
31 | @implementation KGHitTestingButton
32 |
33 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
34 | return CGRectContainsPoint(KGHitTestingBounds(self.bounds, self.minimumHitTestWidth, self.minimumHitTestHeight), point);
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/KGHitTestingViews/KGHitTestingControl.m:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestingControl.m
3 | // KGHitTestingViewsTests
4 | //
5 | // Created by Krisjanis Gaidis on 1/9/16.
6 | //
7 | // This code is distributed under the terms and conditions of the MIT license.
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to
11 | // deal in the Software without restriction, including without limitation the
12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 | // sell copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 | // IN THE SOFTWARE.
26 | //
27 |
28 | #import "KGHitTestingControl.h"
29 | #import "KGHitTestingHelper.h"
30 |
31 | @implementation KGHitTestingControl
32 |
33 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
34 | return CGRectContainsPoint(KGHitTestingBounds(self.bounds, self.minimumHitTestWidth, self.minimumHitTestHeight), point);
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/KGHitTestingViews/KGHitTesting.h:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTesting.h
3 | // KGHitTestingViewsTests
4 | //
5 | // Created by Krisjanis Gaidis on 5/10/15.
6 | //
7 | // This code is distributed under the terms and conditions of the MIT license.
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to
11 | // deal in the Software without restriction, including without limitation the
12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 | // sell copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 | // IN THE SOFTWARE.
26 | //
27 |
28 | #import
29 | #import
30 |
31 | @protocol KGHitTesting
32 |
33 | @required
34 |
35 | @property (nonatomic) IBInspectable CGFloat minimumHitTestWidth;
36 | @property (nonatomic) IBInspectable CGFloat minimumHitTestHeight;
37 |
38 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
39 |
40 | @end
--------------------------------------------------------------------------------
/KGHitTestingViews/KGHitTestingHelper.m:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestingHelper.m
3 | // KGHitTestingViews
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | //
7 | // This code is distributed under the terms and conditions of the MIT license.
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to
11 | // deal in the Software without restriction, including without limitation the
12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 | // sell copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 | // IN THE SOFTWARE.
26 | //
27 |
28 | #import "KGHitTestingHelper.h"
29 |
30 | CGRect KGHitTestingBounds(CGRect bounds, CGFloat minimumHitTestWidth, CGFloat minimumHitTestHeight) {
31 |
32 | CGRect hitTestingBounds = bounds;
33 |
34 | if (minimumHitTestWidth > bounds.size.width) {
35 | hitTestingBounds.size.width = minimumHitTestWidth;
36 | hitTestingBounds.origin.x -= (hitTestingBounds.size.width - bounds.size.width)/2;
37 | }
38 |
39 | if (minimumHitTestHeight > bounds.size.height) {
40 | hitTestingBounds.size.height = minimumHitTestHeight;
41 | hitTestingBounds.origin.y -= (hitTestingBounds.size.height - bounds.size.height)/2;
42 | }
43 |
44 | return hitTestingBounds;
45 | }
--------------------------------------------------------------------------------
/KGHitTestingViews/KGHitTestingView.h:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestingView.h
3 | // KGHitTestingViews
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | //
7 | // This code is distributed under the terms and conditions of the MIT license.
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to
11 | // deal in the Software without restriction, including without limitation the
12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 | // sell copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 | // IN THE SOFTWARE.
26 | //
27 |
28 | #import
29 | #import "KGHitTesting.h"
30 |
31 | @interface KGHitTestingView : UIView
32 |
33 | /**
34 | @desc The minimum width that will be used when hit testing is
35 | performed.
36 |
37 | Specifying a larger value than the bounds width will
38 | increase the hit area of the view.
39 |
40 | Specifying a smaller value than the bounds width will
41 | cause no effect - the bounds width will be used for hit
42 | testing.
43 |
44 | The default value causes no effect.
45 | */
46 | @property (nonatomic) IBInspectable CGFloat minimumHitTestWidth;
47 |
48 | /**
49 | @desc The minimum height that will be used when hit testing is
50 | performed.
51 |
52 | Specifying a larger value than the bounds height will
53 | increase the hit area of the view.
54 |
55 | Specifying a smaller value than the bounds height will
56 | cause no effect - the bounds height will be used for hit
57 | testing.
58 |
59 | The default value causes no effect.
60 | */
61 | @property (nonatomic) IBInspectable CGFloat minimumHitTestHeight;
62 |
63 | @end
--------------------------------------------------------------------------------
/KGHitTestingViews/KGHitTestingButton.h:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestingButton.h
3 | // KGHitTestingViews
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | //
7 | // This code is distributed under the terms and conditions of the MIT license.
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to
11 | // deal in the Software without restriction, including without limitation the
12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 | // sell copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 | // IN THE SOFTWARE.
26 | //
27 |
28 | #import
29 | #import "KGHitTesting.h"
30 |
31 | @interface KGHitTestingButton : UIButton
32 |
33 | /**
34 | @desc The minimum width that will be used when hit testing is
35 | performed.
36 |
37 | Specifying a larger value than the bounds width will
38 | increase the hit area of the view.
39 |
40 | Specifying a smaller value than the bounds width will
41 | cause no effect - the bounds width will be used for hit
42 | testing.
43 |
44 | The default value causes no effect.
45 | */
46 | @property (nonatomic) IBInspectable CGFloat minimumHitTestWidth;
47 |
48 | /**
49 | @desc The minimum height that will be used when hit testing is
50 | performed.
51 |
52 | Specifying a larger value than the bounds height will
53 | increase the hit area of the view.
54 |
55 | Specifying a smaller value than the bounds height will
56 | cause no effect - the bounds height will be used for hit
57 | testing.
58 |
59 | The default value causes no effect.
60 | */
61 | @property (nonatomic) IBInspectable CGFloat minimumHitTestHeight;
62 |
63 | @end
--------------------------------------------------------------------------------
/KGHitTestingViews/KGHitTestingControl.h:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestingControl.h
3 | // KGHitTestingViewsTests
4 | //
5 | // Created by Krisjanis Gaidis on 1/9/16.
6 | //
7 | // This code is distributed under the terms and conditions of the MIT license.
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to
11 | // deal in the Software without restriction, including without limitation the
12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 | // sell copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 | // IN THE SOFTWARE.
26 | //
27 |
28 | #import
29 | #import "KGHitTesting.h"
30 |
31 | @interface KGHitTestingControl : UIControl
32 |
33 | /**
34 | @desc The minimum width that will be used when hit testing is
35 | performed.
36 |
37 | Specifying a larger value than the bounds width will
38 | increase the hit area of the view.
39 |
40 | Specifying a smaller value than the bounds width will
41 | cause no effect - the bounds width will be used for hit
42 | testing.
43 |
44 | The default value causes no effect.
45 | */
46 | @property (nonatomic) IBInspectable CGFloat minimumHitTestWidth;
47 |
48 | /**
49 | @desc The minimum height that will be used when hit testing is
50 | performed.
51 |
52 | Specifying a larger value than the bounds height will
53 | increase the hit area of the view.
54 |
55 | Specifying a smaller value than the bounds height will
56 | cause no effect - the bounds height will be used for hit
57 | testing.
58 |
59 | The default value causes no effect.
60 | */
61 | @property (nonatomic) IBInspectable CGFloat minimumHitTestHeight;
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/Tests/KGHitTestingViewsTests/KGHitTestBaseTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestBaseTest.m
3 | // KGHitTestingViewsTests
4 | //
5 | // Created by Krisjanis Gaidis on 5/10/15.
6 | //
7 | //
8 |
9 | #import "KGHitTestBaseTest.h"
10 |
11 | @implementation KGHitTestBaseTest
12 |
13 | - (void)setUp {
14 | [super setUp];
15 | // Override setup in each subclass.
16 | }
17 |
18 | - (void)tearDown {
19 | self.hitTestObject = nil;
20 | [super tearDown];
21 | }
22 |
23 | #pragma mark - Helpers -
24 |
25 | - (id)increaseHitTestAreaForHitTestObject:(id)hitTestObject {
26 | hitTestObject.minimumHitTestHeight = kMinimumHitTestHeight;
27 | hitTestObject.minimumHitTestWidth = kMinimumHitTestWidth;
28 | return hitTestObject;
29 | }
30 |
31 | #pragma mark - Top left corner -
32 |
33 | - (void)_testTopLeftCornerInBounds {
34 | XCTAssert([self.hitTestObject pointInside:CGPointMake(0, 0) withEvent:nil]);
35 | XCTAssert([[self increaseHitTestAreaForHitTestObject:self.hitTestObject] pointInside:CGPointMake(-kWidthOffset, -kHeightOffset) withEvent:nil]);
36 | }
37 |
38 | - (void)_testTopLeftCornerOutOfBounds {
39 | XCTAssert(![self.hitTestObject pointInside:CGPointMake(-0.1, -0.1) withEvent:nil]);
40 | XCTAssert(![[self increaseHitTestAreaForHitTestObject:self.hitTestObject] pointInside:CGPointMake(-kWidthOffset-0.1, -kHeightOffset-0.1) withEvent:nil]);
41 | }
42 |
43 | #pragma mark - Top right corner -
44 |
45 | - (void)_testTopRightCornerInBounds {
46 | XCTAssert([self.hitTestObject pointInside:CGPointMake(kWidth-0.1, 0.0) withEvent:nil]);
47 | XCTAssert([[self increaseHitTestAreaForHitTestObject:self.hitTestObject] pointInside:CGPointMake(kWidth+kWidthOffset-0.1, kHeightOffset) withEvent:nil]);
48 | }
49 |
50 | - (void)_testTopRightCornerOutOfBounds {
51 | XCTAssert(![self.hitTestObject pointInside:CGPointMake(kWidth+0.1, 0.1) withEvent:nil]);
52 | XCTAssert(![[self increaseHitTestAreaForHitTestObject:self.hitTestObject] pointInside:CGPointMake(kWidth+kWidthOffset+0.1, kHeightOffset+0.1) withEvent:nil]);
53 | }
54 |
55 | #pragma mark - Bottom right corner -
56 |
57 | - (void)_testBottomRightCornerInBounds {
58 | XCTAssert([self.hitTestObject pointInside:CGPointMake(kWidth-0.1, kHeight-0.1) withEvent:nil]);
59 | XCTAssert([[self increaseHitTestAreaForHitTestObject:self.hitTestObject] pointInside:CGPointMake(kWidth+kWidthOffset-0.1, kHeight+kHeightOffset-0.1) withEvent:nil]);
60 | }
61 |
62 | - (void)_testBottomRightCornerOutOfBounds {
63 | XCTAssert(![self.hitTestObject pointInside:CGPointMake(kWidth+0.1, kHeight+0.1) withEvent:nil]);
64 | XCTAssert(![[self increaseHitTestAreaForHitTestObject:self.hitTestObject] pointInside:CGPointMake(kWidth+kWidthOffset+0.1, kHeight+kHeightOffset+0.1) withEvent:nil]);
65 | }
66 |
67 | #pragma mark - Bottom left corner -
68 |
69 | - (void)_testBottomLeftCornerInBounds {
70 | XCTAssert([self.hitTestObject pointInside:CGPointMake(0, kHeight-0.1) withEvent:nil]);
71 | XCTAssert([[self increaseHitTestAreaForHitTestObject:self.hitTestObject] pointInside:CGPointMake(-kWidthOffset, kHeight+kHeightOffset-0.1) withEvent:nil]);
72 | }
73 |
74 | - (void)_testBottomLeftCornerOutOfBounds {
75 | XCTAssert(![self.hitTestObject pointInside:CGPointMake(0, kHeight+0.1) withEvent:nil]);
76 | XCTAssert(![[self increaseHitTestAreaForHitTestObject:self.hitTestObject] pointInside:CGPointMake(-kWidthOffset-0.1, kHeight+kHeightOffset+0.1) withEvent:nil]);
77 | }
78 |
79 | @end
80 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Overview
2 | **KGHitTestingViews** is a small helper library to **effortlessly increase the hit test area of a view**.
3 |
4 | It's common to display buttons as small as 20 x 20 points. However, [iOS User Interface Guidelines](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/LayoutandAppearance.html) recommends that all tappable controls have at least a 44 x 44 point hit area. A common solution to this problem involves making a large button containing a small image, but this solution impacts positioning constraints relative to the small image and makes the layout generally more awkward. **KGHitTestingViews** aims to solve this problem in a simple manner.
5 |
6 | ## Installation
7 |
8 | To install using [CocoaPods](https://github.com/cocoapods/cocoapods), add the following to your project Podfile:
9 |
10 | ```ruby
11 | pod 'KGHitTestingViews'
12 | ```
13 |
14 | Alternatively, drag and drop all of the files in the KGHitTestingViews folder into your Xcode project, agreeing to copy files if needed.
15 |
16 | ## How to Use
17 |
18 | ### In Code (Category):
19 | The easiest way to use **KGHitTestingViews** is to use the `UIView` category: `"UIView+KGHitTesting.h"`. No subclassing required!
20 |
21 | ```objective-c
22 | @interface UIView (KGHitTesting)
23 | - (void)setMinimumHitTestWidth:(CGFloat)width height:(CGFloat)height;
24 | @end
25 | ```
26 |
27 | ### In Code (Subclassing):
28 | Subclass `KGHitTestingView` or `KGHitTestingControl` or `KGHitTestingButton` and set `minimumHitTestHeight` and `minimumHitTestWidth` to the desired size of the hit test area:
29 |
30 | ```objective-c
31 | @interface ButtonSubclass : KGHitTestingButton
32 | @end
33 | ```
34 | ```objective-c
35 | - (void)setup {
36 | self.minimumHitTestWidth = 44.0;
37 | self.minimumHitTestHeight = 44.0;
38 | }
39 | ```
40 |
41 | ### In Interface Builder (Subclassing):
42 | Subclass `KGHitTestingView` or `KGHitTestingControl` or `KGHitTestingButton` in the "Identify Inspector" and set the width and height values in the "Attributes Inspector."
43 |
44 | 
45 |
46 | ### Important note:
47 | The height and width of the hit test area are *minimums*. If you specify a smaller hit area width or height than what the bounds specify, the bounds width or height will be used.
48 |
49 | ## Swift Support
50 | KGHitTestingViews works with Swift! Just follow the "How to Use" section.
51 |
52 | ## FAQ
53 | ###What is hit testing?
54 |
55 | "The process of determining whether a user-controlled cursor (such as a mouse cursor or touch-point on a touch-screen interface) intersects a given graphical object (such as a shape, line, or curve) drawn on the screen." - [Wikipedia](http://en.wikipedia.org/wiki/Hit-testing)
56 |
57 | ###Why override `-pointInside:`? I thought this is hit testing.
58 | Hit test (`-hitTest:`) is a more-complex algorithmic test that involves looping through subviews. Point inside (`-pointInside:`) is a simple geometric test which checks whether a `CGPoint` is within the bounds of a given view. For the purposes of increasing the touch area, we only need to modify the geometric calculation. For more, check out [this](http://smnh.me/hit-testing-in-ios/) nicely written blog about hit-testing.
59 |
60 | ## Credits
61 | Created and maintained by Krisjanis Gaidis.
62 |
63 | Contributions:
64 |
65 | * IBInspectable addition by [mailworks](https://github.com/mailworks).
66 |
67 | ## License
68 | KGHitTestingViews is released under the MIT license. See LICENSE for details.
--------------------------------------------------------------------------------
/Example/KGHitTestingViewsExample/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Example/KGHitTestingViewsExample/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // KGHitTestingViewsExample
4 | //
5 | // Created by Krisjanis Gaidis on 5/2/15.
6 | // Copyright (c) 2015 Krisjanis Gaidis. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "KGHitTestingButton.h"
11 | #import "KGHitTestingHelper.h"
12 |
13 | static NSString *const kWidthKeyPath = @"button.minimumHitTestWidth";
14 | static NSString *const kHeightKeyPath = @"button.minimumHitTestHeight";
15 |
16 | @interface ViewController ()
17 |
18 | @property (weak, nonatomic) IBOutlet KGHitTestingButton *button;
19 | @property (weak, nonatomic) IBOutlet UIView *hitTestAreaView;
20 |
21 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *hitTestAreaViewHeightConstraint;
22 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *hitTestAreaViewWidthConstraint;
23 |
24 | @property (weak, nonatomic) IBOutlet UILabel *widthLabel;
25 | @property (weak, nonatomic) IBOutlet UISlider *widthSlider;
26 | @property (weak, nonatomic) IBOutlet UILabel *heightLabel;
27 | @property (weak, nonatomic) IBOutlet UISlider *heightSlider;
28 |
29 | @property (weak, nonatomic) IBOutlet UILabel *hitTestingBoundsLabel;
30 |
31 | @end
32 |
33 | @implementation ViewController
34 |
35 | #pragma mark - Lifecycle -
36 |
37 | - (void)viewDidLoad {
38 | [super viewDidLoad];
39 | [self registerForKVO];
40 | [self setupSliders];
41 |
42 | // Important Note:
43 | // The 'minimumHitTestWidth' and 'minimumHitTestHeight' are first set as the
44 | // IBInspectable "User Defined Runtime Attributes" in "Main.storyboard" for
45 | // the UIButton.
46 |
47 | [self updateOutlets];
48 | }
49 |
50 | - (void)dealloc {
51 | [self unregisterForKVO];
52 | }
53 |
54 | - (BOOL)prefersStatusBarHidden {
55 | return YES;
56 | }
57 |
58 | #pragma mark - Helpers -
59 |
60 | - (void)setupSliders {
61 | // Autolayout doesn't seem to like height/width values of 0.
62 | self.widthSlider.minimumValue = 1.0;
63 | self.heightSlider.minimumValue = 1.0;
64 | self.widthSlider.maximumValue = 250.0;
65 | self.heightSlider.maximumValue = 250.0;
66 | }
67 |
68 | - (void)updateOutlets {
69 |
70 | // Update width
71 | self.hitTestAreaViewWidthConstraint.constant = self.button.minimumHitTestWidth;
72 | self.widthLabel.text = [NSString stringWithFormat:@"minimumHitTestWidth: %@", @(self.button.minimumHitTestWidth)];
73 |
74 | // Update height
75 | self.hitTestAreaViewHeightConstraint.constant = self.button.minimumHitTestHeight;
76 | self.heightLabel.text = [NSString stringWithFormat:@"minimumHitTestHeight: %@", @(self.button.minimumHitTestHeight)];
77 |
78 | // Update bounds
79 | self.hitTestingBoundsLabel.text = [NSString stringWithFormat:@"HitTestingBounds:\n%@", NSStringFromCGRect(KGHitTestingBounds(self.button.bounds, self.button.minimumHitTestWidth, self.button.minimumHitTestHeight))];
80 |
81 | // Update sliders
82 | self.widthSlider.value = self.button.minimumHitTestWidth;
83 | self.heightSlider.value = self.button.minimumHitTestHeight;
84 | }
85 |
86 | #pragma mark - KVO Observing -
87 |
88 | - (void)registerForKVO {
89 | [self addObserver:self forKeyPath:kWidthKeyPath options:NSKeyValueObservingOptionNew context:nil];
90 | [self addObserver:self forKeyPath:kHeightKeyPath options:NSKeyValueObservingOptionNew context:nil];
91 | }
92 |
93 | - (void)unregisterForKVO {
94 | [self removeObserver:self forKeyPath:kWidthKeyPath context:nil];
95 | [self removeObserver:self forKeyPath:kHeightKeyPath context:nil];
96 | }
97 |
98 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
99 | [self updateOutlets];
100 | }
101 |
102 | #pragma mark - Slider actions -
103 |
104 | - (IBAction)didChangeValueOfWidthSlider:(UISlider *)widthSlider {
105 | [widthSlider setValue:(NSUInteger)(widthSlider.value + 0.5) animated:NO];
106 | self.button.minimumHitTestWidth = widthSlider.value;
107 | }
108 |
109 | - (IBAction)didChangeValueOfHeightSlider:(UISlider *)heightSlider {
110 | [heightSlider setValue:(NSUInteger)(heightSlider.value + 0.5) animated:NO];
111 | self.button.minimumHitTestHeight = heightSlider.value;
112 | }
113 |
114 | @end
115 |
--------------------------------------------------------------------------------
/KGHitTestingViews/UIView+KGHitTesting.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+KGHitTesting.m
3 | // KGHitTestingViewsExample
4 | //
5 | // Created by Krisjanis Gaidis on 5/28/16.
6 | //
7 | // This code is distributed under the terms and conditions of the MIT license.
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to
11 | // deal in the Software without restriction, including without limitation the
12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 | // sell copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 | // IN THE SOFTWARE.
26 | //
27 |
28 | #import "UIView+KGHitTesting.h"
29 | #import "KGHitTestingHelper.h"
30 | #import
31 |
32 | static NSString * const kKGHitTestingClassPrefix = @"KGHitTesting_";
33 |
34 | @implementation UIView (KGHitTesting)
35 |
36 | - (void)setMinimumHitTestWidth:(CGFloat)width height:(CGFloat)height {
37 | [self kg_setMinimumHitTestWidth:width];
38 | [self kg_setMinimumHitTestHeight:height];
39 |
40 | Class currentClass = object_getClass(self);
41 |
42 | if (isKVOSubclass(self)) {
43 | // We do NOT create a special class if the object was already 'isa-swizzled' by KVO.
44 | // We just reuse the special KVO class.
45 | [UIView kg_addHitTestImplementationToClass:currentClass];
46 | }
47 | else if (![NSStringFromClass(currentClass) hasPrefix:kKGHitTestingClassPrefix]) {
48 | const char *newClassName = [[kKGHitTestingClassPrefix stringByAppendingString:NSStringFromClass(currentClass)] UTF8String];
49 | Class newClass = objc_getClass(newClassName);
50 | if (newClass == nil) { // 'KGHitTesting_[self class]' does not exist yet, so lets create it!
51 | newClass = objc_allocateClassPair(currentClass, newClassName, 0);
52 | [UIView kg_addHitTestImplementationToClass:newClass];
53 | objc_registerClassPair(newClass);
54 | }
55 | object_setClass(self, newClass);
56 | }
57 | }
58 |
59 | + (void)kg_addHitTestImplementationToClass:(Class)class {
60 | NSAssert([class isSubclassOfClass:[UIView class]], @"We should only be adding KGHitTesting implementation to a UIView subclass.");
61 |
62 | Method kg_pointInsideMethod = class_getInstanceMethod(class, @selector(kg_pointInside:withEvent:));
63 | IMP kg_pointInsideImplementation = class_getMethodImplementation(class, @selector(kg_pointInside:withEvent:));
64 |
65 | class_addMethod(class, @selector(pointInside:withEvent:), kg_pointInsideImplementation, method_getTypeEncoding(kg_pointInsideMethod));
66 | }
67 |
68 | - (BOOL)kg_pointInside:(CGPoint)point withEvent:(UIEvent *)event {
69 | if (objc_getAssociatedObject(self, @selector(kg_minimumHitTestWidth))) {
70 | return CGRectContainsPoint(KGHitTestingBounds(self.bounds, [self kg_minimumHitTestWidth], [self kg_minimumHitTestHeight]), point);
71 | }
72 |
73 | // If the Object was using KVO before using 'setMinimumHitTestWidth:height:', then
74 | // after using 'setMinimumHitTestWidth:height:', its class remains something like 'KVO_Object'.
75 | // This means that our custom 'pointInside:withEvent:' will get called for EVERY object that
76 | // has the class 'KVO_Object' - even if they never called 'setMinimumHitTestWidth:height:'
77 | // on that object. In those cases, the associated object ('kg_minimumHitTestWidth') will not be set.
78 | // When we notice that case, we make sure to call the ORIGINAL 'pointInside:withEvent:' so
79 | // there would be no surprises.
80 | NSAssert(isKVOSubclass(self), @"Logic error. The only time a custom 'pointInside:withEvent:' should get to this point is if the object is using KVO.");
81 | Class actualClass = [self class];
82 | IMP originalPointInside = class_getMethodImplementation(actualClass, @selector(pointInside:withEvent:));
83 | return ((BOOL (*)(id, SEL, CGPoint, UIEvent *))originalPointInside)(self, _cmd, point, event);
84 | }
85 |
86 | #pragma mark - Properties -
87 |
88 | - (void)kg_setMinimumHitTestWidth:(CGFloat)minimumHitTestWidth {
89 | objc_setAssociatedObject(self, @selector(kg_minimumHitTestWidth), @(minimumHitTestWidth), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
90 | }
91 |
92 | - (CGFloat)kg_minimumHitTestWidth {
93 | return [objc_getAssociatedObject(self, @selector(kg_minimumHitTestWidth)) floatValue];
94 | }
95 |
96 | - (void)kg_setMinimumHitTestHeight:(CGFloat)minimumHitTestHeight {
97 | objc_setAssociatedObject(self, @selector(kg_minimumHitTestHeight), @(minimumHitTestHeight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
98 | }
99 |
100 | - (CGFloat)kg_minimumHitTestHeight {
101 | return [objc_getAssociatedObject(self, @selector(kg_minimumHitTestHeight)) floatValue];
102 | }
103 |
104 | #pragma mark - Runtime helpers -
105 | // A lot of inspiration from:
106 | // https://github.com/mikeash/MAZeroingWeakRef
107 |
108 | static BOOL isKVOSubclass(id object) {
109 | // [self class] gets overriden by the KVO class to return the super class
110 | // However, 'class_getSuperclass' uncovers the actual class (which is 'NSKVONotifying_[self class]')
111 | return [object class] == class_getSuperclass(object_getClass(object));
112 | }
113 |
114 | @end
115 |
--------------------------------------------------------------------------------
/Tests/KGHitTestingViewsTests/KGHitTestCategoryTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // KGHitTestCategoryTests.m
3 | // KGHitTestingViewsTests
4 | //
5 | // Created by Krisjanis Gaidis on 5/29/16.
6 | //
7 | //
8 |
9 | #import
10 | #import "KGHitTestBaseTest.h"
11 | #import "UIView+KGHitTesting.h"
12 |
13 | @interface CustomViewSubclass : UIView
14 | @property (nonatomic) BOOL calledCustomPointInsideImplementation;
15 | @end
16 |
17 | @implementation CustomViewSubclass
18 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
19 | self.calledCustomPointInsideImplementation = YES;
20 | return [super pointInside:point withEvent:event];
21 | }
22 | @end
23 |
24 | @interface KGHitTestCategoryTests : KGHitTestBaseTest
25 |
26 | @end
27 |
28 | @implementation KGHitTestCategoryTests
29 |
30 | - (void)setUp {
31 | [super setUp];
32 | self.hitTestObject = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kWidth, kHeight)];
33 | }
34 |
35 | - (id)increaseHitTestAreaForHitTestObject:(id)hitTestObject {
36 | [((UIView *)hitTestObject) setMinimumHitTestWidth:kMinimumHitTestWidth height:kMinimumHitTestHeight];
37 | return hitTestObject;
38 | }
39 |
40 | #pragma mark - General tests -
41 |
42 | - (void)testView_whenSettingMinimumWidthHeight_classNameShouldChange {
43 | UIView *view = [UIView new];
44 | Class initialClass = [view class];
45 | [view setMinimumHitTestWidth:10 height:10];
46 | Class newClass = [view class];
47 | XCTAssert(initialClass != newClass);
48 | }
49 |
50 | - (void)testView_whenSettingMinimumWidthHeight_hitAreaShouldAdjust {
51 | UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
52 | XCTAssertNotNil([view hitTest:CGPointMake(9, 9) withEvent:nil]);
53 | XCTAssertNil([view hitTest:CGPointMake(20, 20) withEvent:nil]);
54 | [view setMinimumHitTestWidth:44 height:44];
55 | XCTAssertNotNil([view hitTest:CGPointMake(20, 20) withEvent:nil]);
56 | [view setMinimumHitTestWidth:10 height:10];
57 | XCTAssertNil([view hitTest:CGPointMake(20, 20) withEvent:nil]);
58 | [view setMinimumHitTestWidth:44 height:44];
59 | XCTAssertNotNil([view hitTest:CGPointMake(20, 20) withEvent:nil]);
60 | }
61 |
62 | - (void)testView_whenSettingMinimumWidthHeight_classNameShouldNotChangeMultipleTimes {
63 | UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
64 | Class initialClass = [view class];
65 | [view setMinimumHitTestWidth:10 height:10];
66 | Class newClass = [view class];
67 | XCTAssert(initialClass != newClass);
68 | [view setMinimumHitTestWidth:10 height:10];
69 | XCTAssert([NSStringFromClass(newClass) isEqualToString:NSStringFromClass([view class])]);
70 | }
71 |
72 | #pragma mark - KVO tests -
73 |
74 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { }
75 |
76 | - (void)testView_whenRegisteringForKVOAfterSettingHitTestWidthHeight_thereShouldBeNoCrashes {
77 | UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
78 | [view setMinimumHitTestWidth:20 height:20];
79 | [view addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
80 | [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
81 | [view removeObserver:self forKeyPath:@"frame"];
82 | }
83 |
84 | - (void)testView_whenRegisteringForKVOBeforeSettingHitTestWidthHeight_thereShouldBeNoCrashes {
85 | UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
86 | [view addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
87 | [view setMinimumHitTestWidth:20 height:20];
88 | [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
89 | [view removeObserver:self forKeyPath:@"frame"];
90 | }
91 |
92 | - (void)testView_whenRegisteringForKVOAndUsingSameViewMultipleTimes_thereShouldBeNoCrashes {
93 | UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
94 | [view addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
95 | [view setMinimumHitTestWidth:20 height:20];
96 |
97 | UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
98 | [view2 addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
99 | XCTAssert([view2 pointInside:CGPointMake(9, 9) withEvent:nil]);
100 | XCTAssert(![view2 pointInside:CGPointMake(19, 19) withEvent:nil]);
101 |
102 | [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
103 | [view removeObserver:self forKeyPath:@"frame"];
104 | [view2 removeObserver:self forKeyPath:@"frame"];
105 | }
106 |
107 | - (void)testView_whenRegisteringForKVOBeforeSettingMinimumWidthHeight_hitAreaShouldAdjust {
108 | UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
109 | [view addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
110 | XCTAssertNotNil([view hitTest:CGPointMake(9, 9) withEvent:nil]);
111 | XCTAssertNil([view hitTest:CGPointMake(20, 20) withEvent:nil]);
112 | [view setMinimumHitTestWidth:44 height:44];
113 | XCTAssertNotNil([view hitTest:CGPointMake(20, 20) withEvent:nil]);
114 | [view setMinimumHitTestWidth:10 height:10];
115 | XCTAssertNil([view hitTest:CGPointMake(20, 20) withEvent:nil]);
116 | [view setMinimumHitTestWidth:44 height:44];
117 | XCTAssertNotNil([view hitTest:CGPointMake(20, 20) withEvent:nil]);
118 | [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
119 | [view removeObserver:self forKeyPath:@"frame"];
120 | }
121 |
122 | - (void)testView_whenRegisteringForKVOAfterSettingMinimumWidthHeight_hitAreaShouldAdjust {
123 | UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
124 | XCTAssertNotNil([view hitTest:CGPointMake(9, 9) withEvent:nil]);
125 | XCTAssertNil([view hitTest:CGPointMake(20, 20) withEvent:nil]);
126 | [view setMinimumHitTestWidth:44 height:44];
127 | [view addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
128 | XCTAssertNotNil([view hitTest:CGPointMake(20, 20) withEvent:nil]);
129 | [view setMinimumHitTestWidth:10 height:10];
130 | XCTAssertNil([view hitTest:CGPointMake(20, 20) withEvent:nil]);
131 | [view setMinimumHitTestWidth:44 height:44];
132 | XCTAssertNotNil([view hitTest:CGPointMake(20, 20) withEvent:nil]);
133 | [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
134 | [view removeObserver:self forKeyPath:@"frame"];
135 | }
136 |
137 | - (void)testCustomViewSubclass_afterRegisteringKVOAndUsingHitTesting_customPointInsideImplementationShouldGetCalled {
138 | CustomViewSubclass *customView = [[CustomViewSubclass alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
139 | [customView addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:nil];
140 | [customView setMinimumHitTestWidth:20 height:20];
141 | [customView pointInside:CGPointZero withEvent:nil];
142 | XCTAssert(!customView.calledCustomPointInsideImplementation, @"The overriden 'pointInside:withEvent' should be called instead.");
143 |
144 | CustomViewSubclass *customView2 = [[CustomViewSubclass alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
145 | [customView2 addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:nil];
146 | [customView2 pointInside:CGPointZero withEvent:nil];
147 | XCTAssert(customView2.calledCustomPointInsideImplementation);
148 |
149 | [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
150 | [customView removeObserver:self forKeyPath:@"frame"];
151 | [customView2 removeObserver:self forKeyPath:@"frame"];
152 | }
153 |
154 | #pragma mark - Top left corner -
155 | - (void)testTopLeftCornerInBounds { [self _testTopLeftCornerInBounds]; }
156 | - (void)testTopLeftCornerOutOfBounds { [self _testTopLeftCornerOutOfBounds]; }
157 |
158 | #pragma mark - Top right corner -
159 | - (void)testTopRightCornerInBounds { [self _testTopRightCornerInBounds]; }
160 | - (void)testTopRightCornerOutOfBounds { [self _testTopRightCornerOutOfBounds]; }
161 |
162 | #pragma mark - Bottom right corner -
163 | - (void)testBottomRightCornerInBounds { [self _testBottomRightCornerInBounds]; }
164 | - (void)testBottomRightCornerOutOfBounds { [self _testBottomRightCornerOutOfBounds]; }
165 |
166 | #pragma mark - Bottom left corner -
167 | - (void)testBottomLeftCornerInBounds { [self _testBottomLeftCornerInBounds]; }
168 | - (void)testBottomLeftCornerOutOfBounds { [self _testBottomLeftCornerOutOfBounds]; }
169 |
170 | @end
171 |
--------------------------------------------------------------------------------
/Example/KGHitTestingViewsExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
74 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/Tests/KGHitTestingViewsTests.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 014191B11B002D9B00262180 /* KGHitTestBaseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 014191AD1B0025C900262180 /* KGHitTestBaseTest.m */; };
11 | 01596BDA1CFBD7D4006241B7 /* UIView+KGHitTesting.m in Sources */ = {isa = PBXBuildFile; fileRef = 01596BD91CFBD7D4006241B7 /* UIView+KGHitTesting.m */; };
12 | 01596BDC1CFBD85C006241B7 /* KGHitTestCategoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01596BDB1CFBD85C006241B7 /* KGHitTestCategoryTests.m */; };
13 | 01943F3D1AF5997A005642B0 /* KGHitTestingButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 01943F3A1AF5997A005642B0 /* KGHitTestingButton.m */; };
14 | 01943F3E1AF5997A005642B0 /* KGHitTestingHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 01943F3B1AF5997A005642B0 /* KGHitTestingHelper.m */; };
15 | 01943F3F1AF5997A005642B0 /* KGHitTestingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 01943F3C1AF5997A005642B0 /* KGHitTestingView.m */; };
16 | 01943F411AF59CE6005642B0 /* KGHitTestViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01943F401AF59CE6005642B0 /* KGHitTestViewTests.m */; };
17 | 01943F431AF5A573005642B0 /* KGHitTestButtonTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01943F421AF5A573005642B0 /* KGHitTestButtonTests.m */; };
18 | 0197EEA01C41DB1D00ACC75F /* KGHitTestingControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 0197EE9F1C41DB1D00ACC75F /* KGHitTestingControl.m */; };
19 | 0197EEA21C41DB9800ACC75F /* KGHitTestControlTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0197EEA11C41DB9800ACC75F /* KGHitTestControlTests.m */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXFileReference section */
23 | 014191AC1B0025C900262180 /* KGHitTestBaseTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGHitTestBaseTest.h; sourceTree = ""; };
24 | 014191AD1B0025C900262180 /* KGHitTestBaseTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestBaseTest.m; sourceTree = ""; };
25 | 014191B01B00298900262180 /* KGHitTesting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGHitTesting.h; sourceTree = ""; };
26 | 01596BD81CFBD7D4006241B7 /* UIView+KGHitTesting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+KGHitTesting.h"; sourceTree = ""; };
27 | 01596BD91CFBD7D4006241B7 /* UIView+KGHitTesting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+KGHitTesting.m"; sourceTree = ""; };
28 | 01596BDB1CFBD85C006241B7 /* KGHitTestCategoryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestCategoryTests.m; sourceTree = ""; };
29 | 01943F371AF5997A005642B0 /* KGHitTestingButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGHitTestingButton.h; sourceTree = ""; };
30 | 01943F381AF5997A005642B0 /* KGHitTestingHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGHitTestingHelper.h; sourceTree = ""; };
31 | 01943F391AF5997A005642B0 /* KGHitTestingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGHitTestingView.h; sourceTree = ""; };
32 | 01943F3A1AF5997A005642B0 /* KGHitTestingButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestingButton.m; sourceTree = ""; };
33 | 01943F3B1AF5997A005642B0 /* KGHitTestingHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestingHelper.m; sourceTree = ""; };
34 | 01943F3C1AF5997A005642B0 /* KGHitTestingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestingView.m; sourceTree = ""; };
35 | 01943F401AF59CE6005642B0 /* KGHitTestViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestViewTests.m; sourceTree = ""; };
36 | 01943F421AF5A573005642B0 /* KGHitTestButtonTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestButtonTests.m; sourceTree = ""; };
37 | 0197EE9E1C41DB1D00ACC75F /* KGHitTestingControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGHitTestingControl.h; sourceTree = ""; };
38 | 0197EE9F1C41DB1D00ACC75F /* KGHitTestingControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestingControl.m; sourceTree = ""; };
39 | 0197EEA11C41DB9800ACC75F /* KGHitTestControlTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestControlTests.m; sourceTree = ""; };
40 | 01B610DF1AF56269001BCC44 /* KGHitTestingViewsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KGHitTestingViewsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 01B610E31AF56269001BCC44 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
42 | /* End PBXFileReference section */
43 |
44 | /* Begin PBXFrameworksBuildPhase section */
45 | 01B610DC1AF56269001BCC44 /* Frameworks */ = {
46 | isa = PBXFrameworksBuildPhase;
47 | buildActionMask = 2147483647;
48 | files = (
49 | );
50 | runOnlyForDeploymentPostprocessing = 0;
51 | };
52 | /* End PBXFrameworksBuildPhase section */
53 |
54 | /* Begin PBXGroup section */
55 | 01943F361AF59950005642B0 /* KGHitTestingViews */ = {
56 | isa = PBXGroup;
57 | children = (
58 | 014191B01B00298900262180 /* KGHitTesting.h */,
59 | 01943F381AF5997A005642B0 /* KGHitTestingHelper.h */,
60 | 01943F3B1AF5997A005642B0 /* KGHitTestingHelper.m */,
61 | 01943F391AF5997A005642B0 /* KGHitTestingView.h */,
62 | 01943F3C1AF5997A005642B0 /* KGHitTestingView.m */,
63 | 01943F371AF5997A005642B0 /* KGHitTestingButton.h */,
64 | 01943F3A1AF5997A005642B0 /* KGHitTestingButton.m */,
65 | 0197EE9E1C41DB1D00ACC75F /* KGHitTestingControl.h */,
66 | 0197EE9F1C41DB1D00ACC75F /* KGHitTestingControl.m */,
67 | 01596BD81CFBD7D4006241B7 /* UIView+KGHitTesting.h */,
68 | 01596BD91CFBD7D4006241B7 /* UIView+KGHitTesting.m */,
69 | );
70 | name = KGHitTestingViews;
71 | path = ../../KGHitTestingViews;
72 | sourceTree = "";
73 | };
74 | 01B610D41AF5622B001BCC44 = {
75 | isa = PBXGroup;
76 | children = (
77 | 01B610E11AF56269001BCC44 /* KGHitTestingViewsTests */,
78 | 01B610E01AF56269001BCC44 /* Products */,
79 | );
80 | sourceTree = "";
81 | };
82 | 01B610E01AF56269001BCC44 /* Products */ = {
83 | isa = PBXGroup;
84 | children = (
85 | 01B610DF1AF56269001BCC44 /* KGHitTestingViewsTests.xctest */,
86 | );
87 | name = Products;
88 | sourceTree = "";
89 | };
90 | 01B610E11AF56269001BCC44 /* KGHitTestingViewsTests */ = {
91 | isa = PBXGroup;
92 | children = (
93 | 014191AC1B0025C900262180 /* KGHitTestBaseTest.h */,
94 | 014191AD1B0025C900262180 /* KGHitTestBaseTest.m */,
95 | 01943F401AF59CE6005642B0 /* KGHitTestViewTests.m */,
96 | 01943F421AF5A573005642B0 /* KGHitTestButtonTests.m */,
97 | 0197EEA11C41DB9800ACC75F /* KGHitTestControlTests.m */,
98 | 01596BDB1CFBD85C006241B7 /* KGHitTestCategoryTests.m */,
99 | 01943F361AF59950005642B0 /* KGHitTestingViews */,
100 | 01B610E21AF56269001BCC44 /* Supporting Files */,
101 | );
102 | path = KGHitTestingViewsTests;
103 | sourceTree = "";
104 | };
105 | 01B610E21AF56269001BCC44 /* Supporting Files */ = {
106 | isa = PBXGroup;
107 | children = (
108 | 01B610E31AF56269001BCC44 /* Info.plist */,
109 | );
110 | name = "Supporting Files";
111 | sourceTree = "";
112 | };
113 | /* End PBXGroup section */
114 |
115 | /* Begin PBXNativeTarget section */
116 | 01B610DE1AF56269001BCC44 /* KGHitTestingViewsTests */ = {
117 | isa = PBXNativeTarget;
118 | buildConfigurationList = 01B610E61AF56269001BCC44 /* Build configuration list for PBXNativeTarget "KGHitTestingViewsTests" */;
119 | buildPhases = (
120 | 01B610DB1AF56269001BCC44 /* Sources */,
121 | 01B610DC1AF56269001BCC44 /* Frameworks */,
122 | 01B610DD1AF56269001BCC44 /* Resources */,
123 | );
124 | buildRules = (
125 | );
126 | dependencies = (
127 | );
128 | name = KGHitTestingViewsTests;
129 | productName = KGHitTestingViewsTests;
130 | productReference = 01B610DF1AF56269001BCC44 /* KGHitTestingViewsTests.xctest */;
131 | productType = "com.apple.product-type.bundle.unit-test";
132 | };
133 | /* End PBXNativeTarget section */
134 |
135 | /* Begin PBXProject section */
136 | 01B610D51AF5622B001BCC44 /* Project object */ = {
137 | isa = PBXProject;
138 | attributes = {
139 | LastUpgradeCheck = 0630;
140 | TargetAttributes = {
141 | 01B610DE1AF56269001BCC44 = {
142 | CreatedOnToolsVersion = 6.3.1;
143 | };
144 | };
145 | };
146 | buildConfigurationList = 01B610D81AF5622B001BCC44 /* Build configuration list for PBXProject "KGHitTestingViewsTests" */;
147 | compatibilityVersion = "Xcode 3.2";
148 | developmentRegion = English;
149 | hasScannedForEncodings = 0;
150 | knownRegions = (
151 | en,
152 | );
153 | mainGroup = 01B610D41AF5622B001BCC44;
154 | productRefGroup = 01B610E01AF56269001BCC44 /* Products */;
155 | projectDirPath = "";
156 | projectRoot = "";
157 | targets = (
158 | 01B610DE1AF56269001BCC44 /* KGHitTestingViewsTests */,
159 | );
160 | };
161 | /* End PBXProject section */
162 |
163 | /* Begin PBXResourcesBuildPhase section */
164 | 01B610DD1AF56269001BCC44 /* Resources */ = {
165 | isa = PBXResourcesBuildPhase;
166 | buildActionMask = 2147483647;
167 | files = (
168 | );
169 | runOnlyForDeploymentPostprocessing = 0;
170 | };
171 | /* End PBXResourcesBuildPhase section */
172 |
173 | /* Begin PBXSourcesBuildPhase section */
174 | 01B610DB1AF56269001BCC44 /* Sources */ = {
175 | isa = PBXSourcesBuildPhase;
176 | buildActionMask = 2147483647;
177 | files = (
178 | 01943F411AF59CE6005642B0 /* KGHitTestViewTests.m in Sources */,
179 | 01596BDC1CFBD85C006241B7 /* KGHitTestCategoryTests.m in Sources */,
180 | 0197EEA01C41DB1D00ACC75F /* KGHitTestingControl.m in Sources */,
181 | 01943F3D1AF5997A005642B0 /* KGHitTestingButton.m in Sources */,
182 | 01943F3F1AF5997A005642B0 /* KGHitTestingView.m in Sources */,
183 | 01943F431AF5A573005642B0 /* KGHitTestButtonTests.m in Sources */,
184 | 0197EEA21C41DB9800ACC75F /* KGHitTestControlTests.m in Sources */,
185 | 014191B11B002D9B00262180 /* KGHitTestBaseTest.m in Sources */,
186 | 01596BDA1CFBD7D4006241B7 /* UIView+KGHitTesting.m in Sources */,
187 | 01943F3E1AF5997A005642B0 /* KGHitTestingHelper.m in Sources */,
188 | );
189 | runOnlyForDeploymentPostprocessing = 0;
190 | };
191 | /* End PBXSourcesBuildPhase section */
192 |
193 | /* Begin XCBuildConfiguration section */
194 | 01B610D91AF5622B001BCC44 /* Debug */ = {
195 | isa = XCBuildConfiguration;
196 | buildSettings = {
197 | };
198 | name = Debug;
199 | };
200 | 01B610DA1AF5622B001BCC44 /* Release */ = {
201 | isa = XCBuildConfiguration;
202 | buildSettings = {
203 | };
204 | name = Release;
205 | };
206 | 01B610E71AF56269001BCC44 /* Debug */ = {
207 | isa = XCBuildConfiguration;
208 | buildSettings = {
209 | ALWAYS_SEARCH_USER_PATHS = NO;
210 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
211 | CLANG_CXX_LIBRARY = "libc++";
212 | CLANG_ENABLE_MODULES = YES;
213 | CLANG_ENABLE_OBJC_ARC = YES;
214 | CLANG_WARN_BOOL_CONVERSION = YES;
215 | CLANG_WARN_CONSTANT_CONVERSION = YES;
216 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
217 | CLANG_WARN_EMPTY_BODY = YES;
218 | CLANG_WARN_ENUM_CONVERSION = YES;
219 | CLANG_WARN_INT_CONVERSION = YES;
220 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
221 | CLANG_WARN_UNREACHABLE_CODE = YES;
222 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
223 | COPY_PHASE_STRIP = NO;
224 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
225 | ENABLE_STRICT_OBJC_MSGSEND = YES;
226 | FRAMEWORK_SEARCH_PATHS = (
227 | "$(SDKROOT)/Developer/Library/Frameworks",
228 | "$(inherited)",
229 | );
230 | GCC_C_LANGUAGE_STANDARD = gnu99;
231 | GCC_DYNAMIC_NO_PIC = NO;
232 | GCC_NO_COMMON_BLOCKS = YES;
233 | GCC_OPTIMIZATION_LEVEL = 0;
234 | GCC_PREPROCESSOR_DEFINITIONS = (
235 | "DEBUG=1",
236 | "$(inherited)",
237 | );
238 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
239 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
240 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
241 | GCC_WARN_UNDECLARED_SELECTOR = YES;
242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
243 | GCC_WARN_UNUSED_FUNCTION = YES;
244 | GCC_WARN_UNUSED_VARIABLE = YES;
245 | INFOPLIST_FILE = KGHitTestingViewsTests/Info.plist;
246 | IPHONEOS_DEPLOYMENT_TARGET = 8.3;
247 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
248 | MTL_ENABLE_DEBUG_INFO = YES;
249 | ONLY_ACTIVE_ARCH = YES;
250 | PRODUCT_NAME = "$(TARGET_NAME)";
251 | SDKROOT = iphoneos;
252 | };
253 | name = Debug;
254 | };
255 | 01B610E81AF56269001BCC44 /* Release */ = {
256 | isa = XCBuildConfiguration;
257 | buildSettings = {
258 | ALWAYS_SEARCH_USER_PATHS = NO;
259 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
260 | CLANG_CXX_LIBRARY = "libc++";
261 | CLANG_ENABLE_MODULES = YES;
262 | CLANG_ENABLE_OBJC_ARC = YES;
263 | CLANG_WARN_BOOL_CONVERSION = YES;
264 | CLANG_WARN_CONSTANT_CONVERSION = YES;
265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
266 | CLANG_WARN_EMPTY_BODY = YES;
267 | CLANG_WARN_ENUM_CONVERSION = YES;
268 | CLANG_WARN_INT_CONVERSION = YES;
269 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
270 | CLANG_WARN_UNREACHABLE_CODE = YES;
271 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
272 | COPY_PHASE_STRIP = NO;
273 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
274 | ENABLE_NS_ASSERTIONS = NO;
275 | ENABLE_STRICT_OBJC_MSGSEND = YES;
276 | FRAMEWORK_SEARCH_PATHS = (
277 | "$(SDKROOT)/Developer/Library/Frameworks",
278 | "$(inherited)",
279 | );
280 | GCC_C_LANGUAGE_STANDARD = gnu99;
281 | GCC_NO_COMMON_BLOCKS = YES;
282 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
283 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
284 | GCC_WARN_UNDECLARED_SELECTOR = YES;
285 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
286 | GCC_WARN_UNUSED_FUNCTION = YES;
287 | GCC_WARN_UNUSED_VARIABLE = YES;
288 | INFOPLIST_FILE = KGHitTestingViewsTests/Info.plist;
289 | IPHONEOS_DEPLOYMENT_TARGET = 8.3;
290 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
291 | MTL_ENABLE_DEBUG_INFO = NO;
292 | PRODUCT_NAME = "$(TARGET_NAME)";
293 | SDKROOT = iphoneos;
294 | VALIDATE_PRODUCT = YES;
295 | };
296 | name = Release;
297 | };
298 | /* End XCBuildConfiguration section */
299 |
300 | /* Begin XCConfigurationList section */
301 | 01B610D81AF5622B001BCC44 /* Build configuration list for PBXProject "KGHitTestingViewsTests" */ = {
302 | isa = XCConfigurationList;
303 | buildConfigurations = (
304 | 01B610D91AF5622B001BCC44 /* Debug */,
305 | 01B610DA1AF5622B001BCC44 /* Release */,
306 | );
307 | defaultConfigurationIsVisible = 0;
308 | defaultConfigurationName = Release;
309 | };
310 | 01B610E61AF56269001BCC44 /* Build configuration list for PBXNativeTarget "KGHitTestingViewsTests" */ = {
311 | isa = XCConfigurationList;
312 | buildConfigurations = (
313 | 01B610E71AF56269001BCC44 /* Debug */,
314 | 01B610E81AF56269001BCC44 /* Release */,
315 | );
316 | defaultConfigurationIsVisible = 0;
317 | defaultConfigurationName = Release;
318 | };
319 | /* End XCConfigurationList section */
320 | };
321 | rootObject = 01B610D51AF5622B001BCC44 /* Project object */;
322 | }
323 |
--------------------------------------------------------------------------------
/Example/KGHitTestingViewsExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 0134810D1AF563560085731A /* KGHitTestingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0134810C1AF563560085731A /* KGHitTestingView.m */; };
11 | 013481101AF5636F0085731A /* KGHitTestingButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 0134810F1AF5636F0085731A /* KGHitTestingButton.m */; };
12 | 013481131AF564260085731A /* KGHitTestingHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 013481121AF564260085731A /* KGHitTestingHelper.m */; };
13 | 01596BD71CFBD6AE006241B7 /* UIView+KGHitTesting.m in Sources */ = {isa = PBXBuildFile; fileRef = 01596BD61CFBD6AE006241B7 /* UIView+KGHitTesting.m */; };
14 | 019A13EE1C41DEDB00AF7461 /* KGHitTestingControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 019A13ED1C41DEDB00AF7461 /* KGHitTestingControl.m */; };
15 | 01B610B11AF561C6001BCC44 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 01B610B01AF561C6001BCC44 /* main.m */; };
16 | 01B610B41AF561C6001BCC44 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 01B610B31AF561C6001BCC44 /* AppDelegate.m */; };
17 | 01B610B71AF561C6001BCC44 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 01B610B61AF561C6001BCC44 /* ViewController.m */; };
18 | 01B610BA1AF561C6001BCC44 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 01B610B81AF561C6001BCC44 /* Main.storyboard */; };
19 | 01B610BC1AF561C6001BCC44 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 01B610BB1AF561C6001BCC44 /* Images.xcassets */; };
20 | 01B610BF1AF561C6001BCC44 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 01B610BD1AF561C6001BCC44 /* LaunchScreen.xib */; };
21 | /* End PBXBuildFile section */
22 |
23 | /* Begin PBXFileReference section */
24 | 0124079D1B0056F300B377D8 /* KGHitTesting.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KGHitTesting.h; sourceTree = ""; };
25 | 0134810B1AF563560085731A /* KGHitTestingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGHitTestingView.h; sourceTree = ""; };
26 | 0134810C1AF563560085731A /* KGHitTestingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestingView.m; sourceTree = ""; };
27 | 0134810E1AF5636F0085731A /* KGHitTestingButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGHitTestingButton.h; sourceTree = ""; };
28 | 0134810F1AF5636F0085731A /* KGHitTestingButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestingButton.m; sourceTree = ""; };
29 | 013481111AF564260085731A /* KGHitTestingHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGHitTestingHelper.h; sourceTree = ""; };
30 | 013481121AF564260085731A /* KGHitTestingHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestingHelper.m; sourceTree = ""; };
31 | 01596BD51CFBD6AE006241B7 /* UIView+KGHitTesting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+KGHitTesting.h"; sourceTree = ""; };
32 | 01596BD61CFBD6AE006241B7 /* UIView+KGHitTesting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+KGHitTesting.m"; sourceTree = ""; };
33 | 019A13EC1C41DEDB00AF7461 /* KGHitTestingControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGHitTestingControl.h; sourceTree = ""; };
34 | 019A13ED1C41DEDB00AF7461 /* KGHitTestingControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGHitTestingControl.m; sourceTree = ""; };
35 | 01B610AB1AF561C6001BCC44 /* KGHitTestingViewsExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KGHitTestingViewsExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
36 | 01B610AF1AF561C6001BCC44 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
37 | 01B610B01AF561C6001BCC44 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
38 | 01B610B21AF561C6001BCC44 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
39 | 01B610B31AF561C6001BCC44 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
40 | 01B610B51AF561C6001BCC44 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
41 | 01B610B61AF561C6001BCC44 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
42 | 01B610B91AF561C6001BCC44 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
43 | 01B610BB1AF561C6001BCC44 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
44 | 01B610BE1AF561C6001BCC44 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
45 | /* End PBXFileReference section */
46 |
47 | /* Begin PBXFrameworksBuildPhase section */
48 | 01B610A81AF561C6001BCC44 /* Frameworks */ = {
49 | isa = PBXFrameworksBuildPhase;
50 | buildActionMask = 2147483647;
51 | files = (
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXFrameworksBuildPhase section */
56 |
57 | /* Begin PBXGroup section */
58 | 0134810A1AF563210085731A /* KGHitTestingViews */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 0124079D1B0056F300B377D8 /* KGHitTesting.h */,
62 | 0134810B1AF563560085731A /* KGHitTestingView.h */,
63 | 0134810C1AF563560085731A /* KGHitTestingView.m */,
64 | 0134810E1AF5636F0085731A /* KGHitTestingButton.h */,
65 | 0134810F1AF5636F0085731A /* KGHitTestingButton.m */,
66 | 019A13EC1C41DEDB00AF7461 /* KGHitTestingControl.h */,
67 | 019A13ED1C41DEDB00AF7461 /* KGHitTestingControl.m */,
68 | 013481111AF564260085731A /* KGHitTestingHelper.h */,
69 | 013481121AF564260085731A /* KGHitTestingHelper.m */,
70 | 01596BD51CFBD6AE006241B7 /* UIView+KGHitTesting.h */,
71 | 01596BD61CFBD6AE006241B7 /* UIView+KGHitTesting.m */,
72 | );
73 | name = KGHitTestingViews;
74 | path = ../../KGHitTestingViews;
75 | sourceTree = "";
76 | };
77 | 01B610A21AF561C6001BCC44 = {
78 | isa = PBXGroup;
79 | children = (
80 | 01B610AD1AF561C6001BCC44 /* KGHitTestingViewsExample */,
81 | 01B610AC1AF561C6001BCC44 /* Products */,
82 | );
83 | sourceTree = "";
84 | };
85 | 01B610AC1AF561C6001BCC44 /* Products */ = {
86 | isa = PBXGroup;
87 | children = (
88 | 01B610AB1AF561C6001BCC44 /* KGHitTestingViewsExample.app */,
89 | );
90 | name = Products;
91 | sourceTree = "";
92 | };
93 | 01B610AD1AF561C6001BCC44 /* KGHitTestingViewsExample */ = {
94 | isa = PBXGroup;
95 | children = (
96 | 01B610B21AF561C6001BCC44 /* AppDelegate.h */,
97 | 01B610B31AF561C6001BCC44 /* AppDelegate.m */,
98 | 01B610B81AF561C6001BCC44 /* Main.storyboard */,
99 | 01B610B51AF561C6001BCC44 /* ViewController.h */,
100 | 01B610B61AF561C6001BCC44 /* ViewController.m */,
101 | 01B610BB1AF561C6001BCC44 /* Images.xcassets */,
102 | 01B610BD1AF561C6001BCC44 /* LaunchScreen.xib */,
103 | 0134810A1AF563210085731A /* KGHitTestingViews */,
104 | 01B610AE1AF561C6001BCC44 /* Supporting Files */,
105 | );
106 | path = KGHitTestingViewsExample;
107 | sourceTree = "";
108 | };
109 | 01B610AE1AF561C6001BCC44 /* Supporting Files */ = {
110 | isa = PBXGroup;
111 | children = (
112 | 01B610AF1AF561C6001BCC44 /* Info.plist */,
113 | 01B610B01AF561C6001BCC44 /* main.m */,
114 | );
115 | name = "Supporting Files";
116 | sourceTree = "";
117 | };
118 | /* End PBXGroup section */
119 |
120 | /* Begin PBXNativeTarget section */
121 | 01B610AA1AF561C6001BCC44 /* KGHitTestingViewsExample */ = {
122 | isa = PBXNativeTarget;
123 | buildConfigurationList = 01B610CE1AF561C6001BCC44 /* Build configuration list for PBXNativeTarget "KGHitTestingViewsExample" */;
124 | buildPhases = (
125 | 01B610A71AF561C6001BCC44 /* Sources */,
126 | 01B610A81AF561C6001BCC44 /* Frameworks */,
127 | 01B610A91AF561C6001BCC44 /* Resources */,
128 | );
129 | buildRules = (
130 | );
131 | dependencies = (
132 | );
133 | name = KGHitTestingViewsExample;
134 | productName = KGHitTestingViewsExample;
135 | productReference = 01B610AB1AF561C6001BCC44 /* KGHitTestingViewsExample.app */;
136 | productType = "com.apple.product-type.application";
137 | };
138 | /* End PBXNativeTarget section */
139 |
140 | /* Begin PBXProject section */
141 | 01B610A31AF561C6001BCC44 /* Project object */ = {
142 | isa = PBXProject;
143 | attributes = {
144 | LastUpgradeCheck = 0630;
145 | ORGANIZATIONNAME = "Krisjanis Gaidis";
146 | TargetAttributes = {
147 | 01B610AA1AF561C6001BCC44 = {
148 | CreatedOnToolsVersion = 6.3.1;
149 | };
150 | };
151 | };
152 | buildConfigurationList = 01B610A61AF561C6001BCC44 /* Build configuration list for PBXProject "KGHitTestingViewsExample" */;
153 | compatibilityVersion = "Xcode 3.2";
154 | developmentRegion = English;
155 | hasScannedForEncodings = 0;
156 | knownRegions = (
157 | en,
158 | Base,
159 | );
160 | mainGroup = 01B610A21AF561C6001BCC44;
161 | productRefGroup = 01B610AC1AF561C6001BCC44 /* Products */;
162 | projectDirPath = "";
163 | projectRoot = "";
164 | targets = (
165 | 01B610AA1AF561C6001BCC44 /* KGHitTestingViewsExample */,
166 | );
167 | };
168 | /* End PBXProject section */
169 |
170 | /* Begin PBXResourcesBuildPhase section */
171 | 01B610A91AF561C6001BCC44 /* Resources */ = {
172 | isa = PBXResourcesBuildPhase;
173 | buildActionMask = 2147483647;
174 | files = (
175 | 01B610BA1AF561C6001BCC44 /* Main.storyboard in Resources */,
176 | 01B610BF1AF561C6001BCC44 /* LaunchScreen.xib in Resources */,
177 | 01B610BC1AF561C6001BCC44 /* Images.xcassets in Resources */,
178 | );
179 | runOnlyForDeploymentPostprocessing = 0;
180 | };
181 | /* End PBXResourcesBuildPhase section */
182 |
183 | /* Begin PBXSourcesBuildPhase section */
184 | 01B610A71AF561C6001BCC44 /* Sources */ = {
185 | isa = PBXSourcesBuildPhase;
186 | buildActionMask = 2147483647;
187 | files = (
188 | 01B610B71AF561C6001BCC44 /* ViewController.m in Sources */,
189 | 01596BD71CFBD6AE006241B7 /* UIView+KGHitTesting.m in Sources */,
190 | 019A13EE1C41DEDB00AF7461 /* KGHitTestingControl.m in Sources */,
191 | 0134810D1AF563560085731A /* KGHitTestingView.m in Sources */,
192 | 013481131AF564260085731A /* KGHitTestingHelper.m in Sources */,
193 | 01B610B41AF561C6001BCC44 /* AppDelegate.m in Sources */,
194 | 01B610B11AF561C6001BCC44 /* main.m in Sources */,
195 | 013481101AF5636F0085731A /* KGHitTestingButton.m in Sources */,
196 | );
197 | runOnlyForDeploymentPostprocessing = 0;
198 | };
199 | /* End PBXSourcesBuildPhase section */
200 |
201 | /* Begin PBXVariantGroup section */
202 | 01B610B81AF561C6001BCC44 /* Main.storyboard */ = {
203 | isa = PBXVariantGroup;
204 | children = (
205 | 01B610B91AF561C6001BCC44 /* Base */,
206 | );
207 | name = Main.storyboard;
208 | sourceTree = "";
209 | };
210 | 01B610BD1AF561C6001BCC44 /* LaunchScreen.xib */ = {
211 | isa = PBXVariantGroup;
212 | children = (
213 | 01B610BE1AF561C6001BCC44 /* Base */,
214 | );
215 | name = LaunchScreen.xib;
216 | sourceTree = "";
217 | };
218 | /* End PBXVariantGroup section */
219 |
220 | /* Begin XCBuildConfiguration section */
221 | 01B610CC1AF561C6001BCC44 /* Debug */ = {
222 | isa = XCBuildConfiguration;
223 | buildSettings = {
224 | ALWAYS_SEARCH_USER_PATHS = NO;
225 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
226 | CLANG_CXX_LIBRARY = "libc++";
227 | CLANG_ENABLE_MODULES = YES;
228 | CLANG_ENABLE_OBJC_ARC = YES;
229 | CLANG_WARN_BOOL_CONVERSION = YES;
230 | CLANG_WARN_CONSTANT_CONVERSION = YES;
231 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
232 | CLANG_WARN_EMPTY_BODY = YES;
233 | CLANG_WARN_ENUM_CONVERSION = YES;
234 | CLANG_WARN_INT_CONVERSION = YES;
235 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
236 | CLANG_WARN_UNREACHABLE_CODE = YES;
237 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
238 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
239 | COPY_PHASE_STRIP = NO;
240 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
241 | ENABLE_STRICT_OBJC_MSGSEND = YES;
242 | GCC_C_LANGUAGE_STANDARD = gnu99;
243 | GCC_DYNAMIC_NO_PIC = NO;
244 | GCC_NO_COMMON_BLOCKS = YES;
245 | GCC_OPTIMIZATION_LEVEL = 0;
246 | GCC_PREPROCESSOR_DEFINITIONS = (
247 | "DEBUG=1",
248 | "$(inherited)",
249 | );
250 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
251 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
252 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
253 | GCC_WARN_UNDECLARED_SELECTOR = YES;
254 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
255 | GCC_WARN_UNUSED_FUNCTION = YES;
256 | GCC_WARN_UNUSED_VARIABLE = YES;
257 | IPHONEOS_DEPLOYMENT_TARGET = 8.3;
258 | MTL_ENABLE_DEBUG_INFO = YES;
259 | ONLY_ACTIVE_ARCH = YES;
260 | SDKROOT = iphoneos;
261 | };
262 | name = Debug;
263 | };
264 | 01B610CD1AF561C6001BCC44 /* Release */ = {
265 | isa = XCBuildConfiguration;
266 | buildSettings = {
267 | ALWAYS_SEARCH_USER_PATHS = NO;
268 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
269 | CLANG_CXX_LIBRARY = "libc++";
270 | CLANG_ENABLE_MODULES = YES;
271 | CLANG_ENABLE_OBJC_ARC = YES;
272 | CLANG_WARN_BOOL_CONVERSION = YES;
273 | CLANG_WARN_CONSTANT_CONVERSION = YES;
274 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
275 | CLANG_WARN_EMPTY_BODY = YES;
276 | CLANG_WARN_ENUM_CONVERSION = YES;
277 | CLANG_WARN_INT_CONVERSION = YES;
278 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
279 | CLANG_WARN_UNREACHABLE_CODE = YES;
280 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
281 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
282 | COPY_PHASE_STRIP = NO;
283 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
284 | ENABLE_NS_ASSERTIONS = NO;
285 | ENABLE_STRICT_OBJC_MSGSEND = YES;
286 | GCC_C_LANGUAGE_STANDARD = gnu99;
287 | GCC_NO_COMMON_BLOCKS = YES;
288 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
289 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
290 | GCC_WARN_UNDECLARED_SELECTOR = YES;
291 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
292 | GCC_WARN_UNUSED_FUNCTION = YES;
293 | GCC_WARN_UNUSED_VARIABLE = YES;
294 | IPHONEOS_DEPLOYMENT_TARGET = 8.3;
295 | MTL_ENABLE_DEBUG_INFO = NO;
296 | SDKROOT = iphoneos;
297 | VALIDATE_PRODUCT = YES;
298 | };
299 | name = Release;
300 | };
301 | 01B610CF1AF561C6001BCC44 /* Debug */ = {
302 | isa = XCBuildConfiguration;
303 | buildSettings = {
304 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
305 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
306 | INFOPLIST_FILE = KGHitTestingViewsExample/Info.plist;
307 | IPHONEOS_DEPLOYMENT_TARGET = 6.0;
308 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
309 | PRODUCT_NAME = "$(TARGET_NAME)";
310 | };
311 | name = Debug;
312 | };
313 | 01B610D01AF561C6001BCC44 /* Release */ = {
314 | isa = XCBuildConfiguration;
315 | buildSettings = {
316 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
317 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
318 | INFOPLIST_FILE = KGHitTestingViewsExample/Info.plist;
319 | IPHONEOS_DEPLOYMENT_TARGET = 6.0;
320 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
321 | PRODUCT_NAME = "$(TARGET_NAME)";
322 | };
323 | name = Release;
324 | };
325 | /* End XCBuildConfiguration section */
326 |
327 | /* Begin XCConfigurationList section */
328 | 01B610A61AF561C6001BCC44 /* Build configuration list for PBXProject "KGHitTestingViewsExample" */ = {
329 | isa = XCConfigurationList;
330 | buildConfigurations = (
331 | 01B610CC1AF561C6001BCC44 /* Debug */,
332 | 01B610CD1AF561C6001BCC44 /* Release */,
333 | );
334 | defaultConfigurationIsVisible = 0;
335 | defaultConfigurationName = Release;
336 | };
337 | 01B610CE1AF561C6001BCC44 /* Build configuration list for PBXNativeTarget "KGHitTestingViewsExample" */ = {
338 | isa = XCConfigurationList;
339 | buildConfigurations = (
340 | 01B610CF1AF561C6001BCC44 /* Debug */,
341 | 01B610D01AF561C6001BCC44 /* Release */,
342 | );
343 | defaultConfigurationIsVisible = 0;
344 | defaultConfigurationName = Release;
345 | };
346 | /* End XCConfigurationList section */
347 | };
348 | rootObject = 01B610A31AF561C6001BCC44 /* Project object */;
349 | }
350 |
--------------------------------------------------------------------------------