| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- //
- // FLEXViewExplorerViewController.m
- // Flipboard
- //
- // Created by Ryan Olson on 6/11/14.
- // Copyright (c) 2014 Flipboard. All rights reserved.
- //
- #import "FLEXViewExplorerViewController.h"
- #import "FLEXRuntimeUtility.h"
- #import "FLEXUtility.h"
- #import "FLEXObjectExplorerFactory.h"
- #import "FLEXImagePreviewViewController.h"
- #import "FLEXPropertyEditorViewController.h"
- typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
- FLEXViewExplorerRowViewController,
- FLEXViewExplorerRowPreview
- };
- @interface FLEXViewExplorerViewController ()
- // Don't clash with UIViewController's view property
- @property (nonatomic, readonly) UIView *viewToExplore;
- @end
- @implementation FLEXViewExplorerViewController
- - (UIView *)viewToExplore
- {
- return [self.object isKindOfClass:[UIView class]] ? self.object : nil;
- }
- #pragma mark - Superclass Overrides
- - (NSString *)customSectionTitle
- {
- return @"Shortcuts";
- }
- - (NSArray *)customSectionRowCookies
- {
- NSMutableArray *rowCookies = [NSMutableArray array];
-
- if ([FLEXUtility viewControllerForView:self.viewToExplore]) {
- [rowCookies addObject:@(FLEXViewExplorerRowViewController)];
- }
-
- [rowCookies addObject:@(FLEXViewExplorerRowPreview)];
- [rowCookies addObjectsFromArray:[self shortcutPropertyNames]];
-
- return rowCookies;
- }
- - (NSArray *)shortcutPropertyNames
- {
- NSArray *propertyNames = @[@"frame", @"bounds", @"center", @"transform", @"backgroundColor", @"alpha", @"opaque", @"hidden", @"clipsToBounds", @"userInteractionEnabled", @"layer"];
-
- if ([self.viewToExplore isKindOfClass:[UILabel class]]) {
- propertyNames = [@[@"text", @"font", @"textColor"] arrayByAddingObjectsFromArray:propertyNames];
- }
-
- return propertyNames;
- }
- - (NSString *)customSectionTitleForRowCookie:(id)rowCookie
- {
- NSString *title = nil;
-
- if ([rowCookie isKindOfClass:[NSNumber class]]) {
- FLEXViewExplorerRow row = [rowCookie unsignedIntegerValue];
- switch (row) {
- case FLEXViewExplorerRowViewController:
- title = @"View Controller";
- break;
-
- case FLEXViewExplorerRowPreview:
- title = @"Preview Image";
- break;
- }
- } else if ([rowCookie isKindOfClass:[NSString class]]) {
- objc_property_t property = [self viewPropertyForName:rowCookie];
- if (property) {
- NSString *prettyPropertyName = [FLEXRuntimeUtility prettyNameForProperty:property];
- // Since we're outside of the "properties" section, prepend @property for clarity.
- title = [NSString stringWithFormat:@"@property %@", prettyPropertyName];
- }
- }
-
- return title;
- }
- - (NSString *)customSectionSubtitleForRowCookie:(id)rowCookie
- {
- NSString *subtitle = nil;
-
- if ([rowCookie isKindOfClass:[NSNumber class]]) {
- FLEXViewExplorerRow row = [rowCookie unsignedIntegerValue];
- switch (row) {
- case FLEXViewExplorerRowViewController:
- subtitle = [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:[FLEXUtility viewControllerForView:self.viewToExplore]];
- break;
-
- case FLEXViewExplorerRowPreview:
- break;
- }
- } else if ([rowCookie isKindOfClass:[NSString class]]) {
- objc_property_t property = [self viewPropertyForName:rowCookie];
- if (property) {
- id value = [FLEXRuntimeUtility valueForProperty:property onObject:self.viewToExplore];
- subtitle = [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:value];
- }
- }
-
- return subtitle;
- }
- - (objc_property_t)viewPropertyForName:(NSString *)propertyName
- {
- return class_getProperty([self.viewToExplore class], [propertyName UTF8String]);
- }
- - (BOOL)customSectionCanDrillIntoRowWithCookie:(id)rowCookie
- {
- return YES;
- }
- - (UIViewController *)customSectionDrillInViewControllerForRowCookie:(id)rowCookie
- {
- UIViewController *drillInViewController = nil;
-
- if ([rowCookie isKindOfClass:[NSNumber class]]) {
- FLEXViewExplorerRow row = [rowCookie unsignedIntegerValue];
- switch (row) {
- case FLEXViewExplorerRowViewController:
- drillInViewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:[FLEXUtility viewControllerForView:self.viewToExplore]];
- break;
-
- case FLEXViewExplorerRowPreview:
- drillInViewController = [[self class] imagePreviewViewControllerForView:self.viewToExplore];
- break;
- }
- } else if ([rowCookie isKindOfClass:[NSString class]]) {
- objc_property_t property = [self viewPropertyForName:rowCookie];
- if (property) {
- id currentValue = [FLEXRuntimeUtility valueForProperty:property onObject:self.viewToExplore];
- if ([FLEXPropertyEditorViewController canEditProperty:property currentValue:currentValue]) {
- drillInViewController = [[FLEXPropertyEditorViewController alloc] initWithTarget:self.object property:property];
- } else {
- drillInViewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:currentValue];
- }
- }
- }
- return drillInViewController;
- }
- + (UIViewController *)imagePreviewViewControllerForView:(UIView *)view
- {
- UIViewController *imagePreviewViewController = nil;
- if (!CGRectIsEmpty(view.bounds)) {
- CGSize viewSize = view.bounds.size;
- UIGraphicsBeginImageContextWithOptions(viewSize, NO, 0.0);
- [view drawViewHierarchyInRect:CGRectMake(0, 0, viewSize.width, viewSize.height) afterScreenUpdates:YES];
- UIImage *previewImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- imagePreviewViewController = [[FLEXImagePreviewViewController alloc] initWithImage:previewImage];
- }
- return imagePreviewViewController;
- }
- #pragma mark - Runtime Adjustment
- + (void)initialize
- {
- // A quirk of UIView: a lot of the "@property"s are not actually properties from the perspective of the runtime.
- // We add these properties to the class at runtime if they haven't been added yet.
- // This way, we can use our property editor to access and change them.
- // The property attributes match the declared attributes in UIView.h
- NSDictionary *frameAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(CGRect)), kFLEXUtilityAttributeNonAtomic : @""};
- [FLEXRuntimeUtility tryAddPropertyWithName:"frame" attributes:frameAttributes toClass:[UIView class]];
-
- NSDictionary *alphaAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(CGFloat)), kFLEXUtilityAttributeNonAtomic : @""};
- [FLEXRuntimeUtility tryAddPropertyWithName:"alpha" attributes:alphaAttributes toClass:[UIView class]];
-
- NSDictionary *clipsAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(BOOL)), kFLEXUtilityAttributeNonAtomic : @""};
- [FLEXRuntimeUtility tryAddPropertyWithName:"clipsToBounds" attributes:clipsAttributes toClass:[UIView class]];
-
- NSDictionary *opaqueAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(BOOL)), kFLEXUtilityAttributeNonAtomic : @"", kFLEXUtilityAttributeCustomGetter : @"isOpaque"};
- [FLEXRuntimeUtility tryAddPropertyWithName:"opaque" attributes:opaqueAttributes toClass:[UIView class]];
-
- NSDictionary *hiddenAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(BOOL)), kFLEXUtilityAttributeNonAtomic : @"", kFLEXUtilityAttributeCustomGetter : @"isHidden"};
- [FLEXRuntimeUtility tryAddPropertyWithName:"hidden" attributes:hiddenAttributes toClass:[UIView class]];
-
- NSDictionary *backgroundColorAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(FLEXEncodeClass(UIColor)), kFLEXUtilityAttributeNonAtomic : @"", kFLEXUtilityAttributeCopy : @""};
- [FLEXRuntimeUtility tryAddPropertyWithName:"backgroundColor" attributes:backgroundColorAttributes toClass:[UIView class]];
- }
- @end
|