| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- //
- // FLEXFieldEditorViewController.m
- // Flipboard
- //
- // Created by Ryan Olson on 5/16/14.
- // Copyright (c) 2014 Flipboard. All rights reserved.
- //
- #import "FLEXFieldEditorViewController.h"
- #import "FLEXFieldEditorView.h"
- #import "FLEXRuntimeUtility.h"
- #import "FLEXUtility.h"
- #import "FLEXArgumentInputView.h"
- #import "FLEXArgumentInputViewFactory.h"
- @interface FLEXFieldEditorViewController () <UIScrollViewDelegate>
- @property (nonatomic, strong) UIScrollView *scrollView;
- @property (nonatomic, strong, readwrite) id target;
- @property (nonatomic, strong, readwrite) FLEXFieldEditorView *fieldEditorView;
- @property (nonatomic, strong, readwrite) UIBarButtonItem *setterButton;
- @end
- @implementation FLEXFieldEditorViewController
- - (id)initWithTarget:(id)target
- {
- self = [super initWithNibName:nil bundle:nil];
- if (self) {
- self.target = target;
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
- }
- return self;
- }
- - (void)dealloc
- {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
- - (void)keyboardDidShow:(NSNotification *)notification
- {
- CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
- UIEdgeInsets scrollInsets = self.scrollView.contentInset;
- scrollInsets.bottom = keyboardSize.height;
- self.scrollView.contentInset = scrollInsets;
- self.scrollView.scrollIndicatorInsets = scrollInsets;
-
- // Find the active input view and scroll to make sure it's visible.
- for (FLEXArgumentInputView *argumentInputView in self.fieldEditorView.argumentInputViews) {
- if (argumentInputView.inputViewIsFirstResponder) {
- CGRect scrollToVisibleRect = [self.scrollView convertRect:argumentInputView.bounds fromView:argumentInputView];
- [self.scrollView scrollRectToVisible:scrollToVisibleRect animated:YES];
- break;
- }
- }
- }
- - (void)keyboardWillHide:(NSNotification *)notification
- {
- UIEdgeInsets scrollInsets = self.scrollView.contentInset;
- scrollInsets.bottom = 0.0;
- self.scrollView.contentInset = scrollInsets;
- self.scrollView.scrollIndicatorInsets = scrollInsets;
- }
- - (BOOL)prefersStatusBarHidden
- {
- return YES;
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
- self.view.backgroundColor = [FLEXUtility scrollViewGrayColor];
-
- self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
- self.scrollView.backgroundColor = self.view.backgroundColor;
- self.scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- self.scrollView.delegate = self;
- [self.view addSubview:self.scrollView];
-
- self.fieldEditorView = [[FLEXFieldEditorView alloc] init];
- self.fieldEditorView.backgroundColor = self.view.backgroundColor;
- self.fieldEditorView.targetDescription = [NSString stringWithFormat:@"%@ %p", [self.target class], self.target];
- [self.scrollView addSubview:self.fieldEditorView];
-
- // One argument input view by default. Subclasses can configure the field editor view with more/different argument input views if needed.
- FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:NULL];
- inputView.backgroundColor = self.view.backgroundColor;
- inputView.targetSize = FLEXArgumentInputViewSizeLarge;
- self.fieldEditorView.argumentInputViews = @[inputView];
-
- self.setterButton = [[UIBarButtonItem alloc] initWithTitle:[self titleForActionButton] style:UIBarButtonItemStyleDone target:self action:@selector(actionButtonPressed:)];
- self.navigationItem.rightBarButtonItem = self.setterButton;
- }
- - (void)viewWillLayoutSubviews
- {
- CGSize constrainSize = CGSizeMake(self.scrollView.bounds.size.width, CGFLOAT_MAX);
- CGSize fieldEditorSize = [self.fieldEditorView sizeThatFits:constrainSize];
- self.fieldEditorView.frame = CGRectMake(0, 0, fieldEditorSize.width, fieldEditorSize.height);
- self.scrollView.contentSize = fieldEditorSize;
- }
- - (FLEXArgumentInputView *)firstInputView
- {
- return [[self.fieldEditorView argumentInputViews] firstObject];
- }
- - (void)actionButtonPressed:(id)sender
- {
- // Subclasses can override
- [self.fieldEditorView endEditing:YES];
- }
- - (NSString *)titleForActionButton
- {
- // Subclasses can override.
- return @"Set";
- }
- + (BOOL)canEditType:(NSString *)typeEncoding currentObjectValue:(id)value
- {
- // Many primitive types can always be edited (numbers and supported structs).
- static NSArray *primitiveTypes = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- primitiveTypes = @[@(@encode(char)),
- @(@encode(int)),
- @(@encode(short)),
- @(@encode(long)),
- @(@encode(long long)),
- @(@encode(unsigned char)),
- @(@encode(unsigned int)),
- @(@encode(unsigned short)),
- @(@encode(unsigned long)),
- @(@encode(unsigned long long)),
- @(@encode(float)),
- @(@encode(double)),
- @(@encode(CGRect)),
- @(@encode(CGSize)),
- @(@encode(CGPoint)),
- @(@encode(CGAffineTransform)),
- @(@encode(NSRange)),
- @(@encode(UIEdgeInsets)),
- @(@encode(UIOffset))];
- });
-
- BOOL canEdit = [primitiveTypes containsObject:typeEncoding];
-
- // Object types may be
- if (!canEdit) {
- if (value) {
- // If the current value is non-nil and we can represent it with an editable string, then we can suppor editing.
- canEdit = canEdit || [FLEXRuntimeUtility editiableDescriptionForObject:value] != nil;
- } else {
- // Also always edit types that are explicitly typed NSString, NSNumber, NSArray, or NSDictionary and are nil.
- // This kind of type encoding is only kept by ivars and properties. Method agruments and return types drop the class from the type encoding.
- // The editor supports populating these types through NSJSONSerilization parsing of the input string.
- canEdit = canEdit || [typeEncoding isEqual:[self stringTypeEncoding]];
- canEdit = canEdit || [typeEncoding isEqual:[self numberTypeEncoding]];
- canEdit = canEdit || [typeEncoding isEqual:[self arrayTypeEncoding]];
- canEdit = canEdit || [typeEncoding isEqual:[self dictionaryTypeEncoding]];
- }
- }
-
- return canEdit;
- }
- + (NSString *)stringTypeEncoding
- {
- return @"@\"NSString\"";
- }
- + (NSString *)numberTypeEncoding
- {
- return @"@\"NSNumber\"";
- }
- + (NSString *)arrayTypeEncoding
- {
- return @"@\"NSArray\"";
- }
- + (NSString *)dictionaryTypeEncoding
- {
- return @"@\"NSDictionary\"";
- }
- @end
|