You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
8.2 KiB
222 lines
8.2 KiB
//
|
|
// FLEXHierarchyTableViewController.m
|
|
// Flipboard
|
|
//
|
|
// Created by Ryan Olson on 2014-05-01.
|
|
// Copyright (c) 2014 Flipboard. All rights reserved.
|
|
//
|
|
|
|
#import "FLEXHierarchyTableViewController.h"
|
|
#import "FLEXUtility.h"
|
|
#import "FLEXHierarchyTableViewCell.h"
|
|
#import "FLEXObjectExplorerViewController.h"
|
|
#import "FLEXObjectExplorerFactory.h"
|
|
#import "FLEXResources.h"
|
|
|
|
static const NSInteger kFLEXHierarchyScopeViewsAtTapIndex = 0;
|
|
static const NSInteger kFLEXHierarchyScopeFullHierarchyIndex = 1;
|
|
|
|
@interface FLEXHierarchyTableViewController () <UISearchBarDelegate>
|
|
|
|
@property (nonatomic, strong) NSArray<UIView *> *allViews;
|
|
@property (nonatomic, strong) NSDictionary<NSValue *, NSNumber *> *depthsForViews;
|
|
@property (nonatomic, strong) NSArray<UIView *> *viewsAtTap;
|
|
@property (nonatomic, strong) UIView *selectedView;
|
|
@property (nonatomic, strong) NSArray<UIView *> *displayedViews;
|
|
|
|
@property (nonatomic, strong) UISearchBar *searchBar;
|
|
|
|
@end
|
|
|
|
@implementation FLEXHierarchyTableViewController
|
|
|
|
- (instancetype)initWithViews:(NSArray<UIView *> *)allViews viewsAtTap:(NSArray<UIView *> *)viewsAtTap selectedView:(UIView *)selectedView depths:(NSDictionary<NSValue *, NSNumber *> *)depthsForViews
|
|
{
|
|
self = [super initWithStyle:UITableViewStylePlain];
|
|
if (self) {
|
|
self.allViews = allViews;
|
|
self.depthsForViews = depthsForViews;
|
|
self.viewsAtTap = viewsAtTap;
|
|
self.selectedView = selectedView;
|
|
|
|
self.title = @"View Hierarchy";
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)viewDidLoad
|
|
{
|
|
[super viewDidLoad];
|
|
|
|
// Preserve selection between presentations.
|
|
self.clearsSelectionOnViewWillAppear = NO;
|
|
// Done button.
|
|
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(donePressed:)];
|
|
|
|
// A little more breathing room.
|
|
self.tableView.rowHeight = 50.0;
|
|
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
|
// Separator inset clashes with persistent cell selection.
|
|
[self.tableView setSeparatorInset:UIEdgeInsetsZero];
|
|
|
|
self.searchBar = [[UISearchBar alloc] init];
|
|
self.searchBar.placeholder = [FLEXUtility searchBarPlaceholderText];
|
|
self.searchBar.delegate = self;
|
|
if ([self showScopeBar]) {
|
|
self.searchBar.showsScopeBar = YES;
|
|
self.searchBar.scopeButtonTitles = @[@"Views at Tap", @"Full Hierarchy"];
|
|
}
|
|
[self.searchBar sizeToFit];
|
|
self.tableView.tableHeaderView = self.searchBar;
|
|
|
|
[self updateDisplayedViews];
|
|
}
|
|
|
|
- (void)viewDidAppear:(BOOL)animated
|
|
{
|
|
[super viewDidAppear:animated];
|
|
|
|
[self trySelectCellForSelectedViewWithScrollPosition:UITableViewScrollPositionMiddle];
|
|
}
|
|
|
|
|
|
#pragma mark Selection and Filtering Helpers
|
|
|
|
- (void)trySelectCellForSelectedViewWithScrollPosition:(UITableViewScrollPosition)scrollPosition
|
|
{
|
|
NSUInteger selectedViewIndex = [self.displayedViews indexOfObject:self.selectedView];
|
|
if (selectedViewIndex != NSNotFound) {
|
|
NSIndexPath *selectedViewIndexPath = [NSIndexPath indexPathForRow:selectedViewIndex inSection:0];
|
|
[self.tableView selectRowAtIndexPath:selectedViewIndexPath animated:YES scrollPosition:scrollPosition];
|
|
}
|
|
}
|
|
|
|
- (void)updateDisplayedViews
|
|
{
|
|
NSArray<UIView *> *candidateViews = nil;
|
|
if ([self showScopeBar]) {
|
|
if (self.searchBar.selectedScopeButtonIndex == kFLEXHierarchyScopeViewsAtTapIndex) {
|
|
candidateViews = self.viewsAtTap;
|
|
} else if (self.searchBar.selectedScopeButtonIndex == kFLEXHierarchyScopeFullHierarchyIndex) {
|
|
candidateViews = self.allViews;
|
|
}
|
|
} else {
|
|
candidateViews = self.allViews;
|
|
}
|
|
|
|
if ([self.searchBar.text length] > 0) {
|
|
self.displayedViews = [candidateViews filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *candidateView, NSDictionary<NSString *, id> *bindings) {
|
|
NSString *title = [FLEXUtility descriptionForView:candidateView includingFrame:NO];
|
|
NSString *candidateViewPointerAddress = [NSString stringWithFormat:@"%p", candidateView];
|
|
BOOL matchedViewPointerAddress = [candidateViewPointerAddress rangeOfString:self.searchBar.text options:NSCaseInsensitiveSearch].location != NSNotFound;
|
|
BOOL matchedViewTitle = [title rangeOfString:self.searchBar.text options:NSCaseInsensitiveSearch].location != NSNotFound;
|
|
return matchedViewPointerAddress || matchedViewTitle;
|
|
}]];
|
|
} else {
|
|
self.displayedViews = candidateViews;
|
|
}
|
|
|
|
[self.tableView reloadData];
|
|
}
|
|
|
|
- (BOOL)showScopeBar
|
|
{
|
|
return [self.viewsAtTap count] > 0;
|
|
}
|
|
|
|
- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope
|
|
{
|
|
[self updateDisplayedViews];
|
|
|
|
// If the search bar text field is active, don't scroll on selection because we may want to continue typing.
|
|
// Otherwise, scroll so that the selected cell is visible.
|
|
UITableViewScrollPosition scrollPosition = self.searchBar.isFirstResponder ? UITableViewScrollPositionNone : UITableViewScrollPositionMiddle;
|
|
[self trySelectCellForSelectedViewWithScrollPosition:scrollPosition];
|
|
}
|
|
|
|
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
|
|
{
|
|
[self updateDisplayedViews];
|
|
[self trySelectCellForSelectedViewWithScrollPosition:UITableViewScrollPositionNone];
|
|
}
|
|
|
|
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
|
|
{
|
|
[searchBar resignFirstResponder];
|
|
}
|
|
|
|
|
|
#pragma mark - Table View Data Source
|
|
|
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
|
{
|
|
return [self.displayedViews count];
|
|
}
|
|
|
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
static NSString *CellIdentifier = @"Cell";
|
|
FLEXHierarchyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
|
|
if (!cell) {
|
|
cell = [[FLEXHierarchyTableViewCell alloc] initWithReuseIdentifier:CellIdentifier];
|
|
}
|
|
|
|
UIView *view = self.displayedViews[indexPath.row];
|
|
NSNumber *depth = [self.depthsForViews objectForKey:[NSValue valueWithNonretainedObject:view]];
|
|
UIColor *viewColor = [FLEXUtility consistentRandomColorForObject:view];
|
|
cell.textLabel.text = [FLEXUtility descriptionForView:view includingFrame:NO];
|
|
cell.detailTextLabel.text = [FLEXUtility detailDescriptionForView:view];
|
|
cell.viewColor = viewColor;
|
|
cell.viewDepth = [depth integerValue];
|
|
if (view.isHidden || view.alpha < 0.01) {
|
|
cell.textLabel.textColor = [UIColor lightGrayColor];
|
|
cell.detailTextLabel.textColor = [UIColor lightGrayColor];
|
|
} else {
|
|
cell.textLabel.textColor = [UIColor blackColor];
|
|
cell.detailTextLabel.textColor = [UIColor blackColor];
|
|
}
|
|
|
|
// Use a pattern-based colour to simplify application of the checker pattern.
|
|
static UIColor *checkerPatternColour = nil;
|
|
static dispatch_once_t once;
|
|
dispatch_once(&once, ^{
|
|
checkerPatternColour = [UIColor colorWithPatternImage:[FLEXResources checkerPattern]];
|
|
});
|
|
|
|
UIColor *viewColour = view.backgroundColor;
|
|
if (!viewColour || [viewColour isEqual:[UIColor clearColor]]) {
|
|
cell.viewBackgroundColorView.backgroundColor = checkerPatternColour;
|
|
} else {
|
|
cell.viewBackgroundColorView.backgroundColor = viewColour;
|
|
}
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
self.selectedView = self.displayedViews[indexPath.row];
|
|
[self.delegate hierarchyViewController:self didFinishWithSelectedView:self.selectedView];
|
|
}
|
|
|
|
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
UIView *drillInView = self.displayedViews[indexPath.row];
|
|
FLEXObjectExplorerViewController *viewExplorer = [FLEXObjectExplorerFactory explorerViewControllerForObject:drillInView];
|
|
[self.navigationController pushViewController:viewExplorer animated:YES];
|
|
}
|
|
|
|
|
|
#pragma mark - Button Actions
|
|
|
|
- (void)donePressed:(id)sender
|
|
{
|
|
[self.delegate hierarchyViewController:self didFinishWithSelectedView:self.selectedView];
|
|
}
|
|
|
|
@end
|