Just trying to wrap my head around the ReactiveCocoa approach to certain situations.
I have a situation where a segment controller swaps out children view controllers. I need to accomplish a couple things here:
- When moved to the parent controller, I must update the
contentInset
of thetableView
because iOS7 doesn't handle it for me with custom container views - When search is initiated, I need to fade the navigation bar, and update the
contentInset
with animation - When search ends, I need to fade the
navigationBar
back in and reset thecontentInset
in an animation
Here is the current code that accomplishes this in an imperative style:
- (void)didMoveToParentViewController:(UIViewController *)parent
{
[super didMoveToParentViewController:parent];
if (parent) {
CGFloat top = parent.topLayoutGuide.length;
CGFloat bottom = parent.bottomLayoutGuide.length;
if (self.tableView.contentInset.top != top) {
UIEdgeInsets newInsets = UIEdgeInsetsMake(top, 0, bottom, 0);
self.tableView.contentInset = newInsets;
self.tableView.scrollIndicatorInsets = newInsets;
}
}
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
[UIView animateWithDuration:.25 animations:^{
self.navigationController.navigationBar.alpha=0;
self.tableView.contentInset = UIEdgeInsetsMake([UIApplication sharedApplication].statusBarFrame.size.height, 0, 0, 0);
}];
return YES;
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {
[UIView animateWithDuration:.25 animations:^{
self.navigationController.navigationBar.alpha=1;
CGFloat top = self.parentViewController.topLayoutGuide.length;
CGFloat bottom = self.parentViewController.bottomLayoutGuide.length;
if (self.tableView.contentInset.top != top) {
UIEdgeInsets newInsets = UIEdgeInsetsMake(top, 0, bottom, 0);
self.tableView.contentInset = newInsets;
self.tableView.scrollIndicatorInsets = newInsets;
}
}];
return YES;
}
It could be refactored to pull some of the inset stuff out, but keeping it flat for this exercise.
Going to post my 'very little idea what I'm doing' approach as an answer below.
Partial Answer
Ok so I'm trying to pull out streams of information into relevant signals.
Basically I need to know:
- Am I currently searching
- The current value of my
contentInset
(top) in this case
So my approach would be
- Create a RACSubject for whether or not I am currently searching
self.currentlySearchingSignal
. - Turn the
top
value of mytableView.contentInset
into a signal sendNext:@(YES)
tocurrentlySearchingSignal
whensearchBarShouldBeginEditing
is called (and when it will return YES)sendNext:@(NO)
tocurrentlySearchingSignal
whensearchBarShouldEndEditing
is called (and when it will return YES)- ...
Ok I'm stuck. I know I need to combine/subscribe to these somehow, but trying to think of it in a non-state way.
- When added to the parent VC AND when my
contentInset.top
isn't yet set properly (topLayoutGuide
), I need to set it without an animation. - When searching AND my
contentInset.top
isn't set properly (status bar frame) I need to perform the animation (and then not update this again until my animation is done) - When not searching AND my
contentInset.top
isn't set properly (topLayoutGuide
) I need to perform the animation (and not update again until the animation is done)
Trying to solve it
Here's my start. Trying to solve for #1, but it's not working yet.
- (void)viewDidLoad
{
[super viewDidLoad];
@weakify(self);
self.currentlyInSearchMode = [RACSubject subject];
self.contentInsetTop = RACObserve(self.tableView, contentInset);
RACSignal *parentViewControllerSignal = RACObserve(self, parentViewController);
// setup the insets when added to parent and not correctly set yet
[[[RACSignal combineLatest:@[self.contentInsetTop, parentViewControllerSignal]] filter:^BOOL(RACTuple *value) {
return !((NSValue *)value.first).UIEdgeInsetsValue.top == ((UIViewController *)value.second).topLayoutGuide.length;
}]doNext:^(id x) {
@strongify(self);
CGFloat top = self.parentViewController.topLayoutGuide.length;
CGFloat bottom = self.parentViewController.bottomLayoutGuide.length;
if (self.tableView.contentInset.top != top) {
UIEdgeInsets newInsets = UIEdgeInsetsMake(top, 0, bottom, 0);
self.tableView.contentInset = newInsets;
self.tableView.scrollIndicatorInsets = newInsets;
}
}];
}