在某些情况下,只想尝试将ReactiveCocoa方法包围起来。
我有一种情况,即分段控制器交换子视图控制器。我需要在这里完成一些事情:
contentInset
的{{1}},因为iOS7不会使用自定义容器视图处理它tableView
contentInset
并重置动画中的navigationBar
以下是以命令式方式实现此目的的当前代码:
contentInset
可以重构一些插入的东西,但要保持这个练习。
要发布我的'非常小的想法,我正在做什么'的方法作为下面的答案。
好的,我正试图将信息流提取到相关信号中。
基本上我需要知道:
- (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;
}
(顶部)的当前值所以我的方法是
contentInset
。self.currentlySearchingSignal
的{{1}}值转换为信号top
时tableView.contentInset
到sendNext:@(YES)
(当它返回YES时)currentlySearchingSignal
时searchBarShouldBeginEditing
到sendNext:@(NO)
(当它返回YES时)好的,我被卡住了。我知道我需要以某种方式组合/订阅这些,但试图以非状态的方式来考虑它。
currentlySearchingSignal
尚未正确设置(searchBarShouldEndEditing
)时,我需要在没有动画的情况下进行设置。contentInset.top
未正确设置(状态栏框)我需要执行动画(然后在动画完成之前不再更新)topLayoutGuide
设置不正确(contentInset.top
)我需要执行动画(并且在动画完成之前不再更新)这是我的开始。试图解决#1,但它还没有工作。
contentInset.top
答案 0 :(得分:12)
这是我从GitHub问题中复制的答案:
我还没有使用ReactiveCocoaLayout,但我怀疑你可能会发现除了RAC之外,还可以通过使用RCL来改进这些代码。我确定其他人会提供更多相关细节。
我建议的第一件事是阅读-rac_signalForSelector:
。它对于委托回调和RAC信号之间的桥接非常有价值。
例如,您可以获得代表所需回调的信号:
RACSignal *movedToParentController = [[self
rac_signalForSelector:@selector(didMoveToParentViewController:)]
filter:^(RACTuple *arguments) {
return arguments.first != nil; // Ignores when parent is `nil`
}];
RACSignal *beginSearch = [self rac_signalForSelector:@selector(searchBarShouldBeginEditing:)];
RACSignal *endSearch = [self rac_signalForSelector:@selector(searchBarShouldEndEditing:)];
现在,让我们假设你有一个更新视图的方法:
- (void)updateViewInsets:(UIEdgeInsets)insets navigationBarAlpha:(CGFloat)alpha animated:(BOOL)animated {
void (^updates)(void) = ^{
if (self.tableView.contentInset.top != insets.top) {
self.tableView.contentInset = insets;
self.tableView.scrollIndicatorInsets = insets;
}
self.navigationController.navigationBar.alpha = alpha;
};
animated ? [UIView animateWithDuration:0.25 animations:updates] : updates();
}
现在,您可以使用start将一些内容组合在一起。
首先,因为-searchBarShouldBeginEditing:
是最短的:
[beginSearch subscribeNext:^(id _) {
UIEdgeInsets insets = UIEdgeInsetsMake(UIApplication.sharedApplication.statusBarFrame.size.height, 0, 0, 0);
[self updateViewInsets:insets navigationBarAlpha:0 animated:YES];
}];
现在,对于更复杂的一块。该信号组合以+merge
两个信号开始,即-didMoveToParentViewController:
的信号和searchBarShouldEndEditing:
的信号。这些信号中的每一个都映射到适当的父视图控制器,并与指示是否执行动画的布尔值配对。这对值打包成RACTuple
。
接下来,使用-reduceEach:
,(UIViewController *, BOOL)
元组将映射到(UIEdgeInsets, BOOL)
元组。此映射计算来自父视图控制器的边缘插入,但不会更改animated
标记。
最后,订阅了这个信号组合,其中调用了辅助方法。
[[[RACSignal
merge:@[
[movedToParentController reduceEach:^(UIViewController *parent) {
return RACTuplePack(parent, @NO); // Unanimated
}],
[endSearch reduceEach:^(id _) {
return RACTuplePack(self.parentViewController, @YES); // Animated
}]
]]
reduceEach:^(UIViewController *parent, NSNumber *animated) {
CGFloat top = parent.topLayoutGuide.length;
CGFloat bottom = parent.bottomLayoutGuide.length;
UIEdgeInsets newInsets = UIEdgeInsetsMake(top, 0, bottom, 0);
return RACTuplePack(([NSValue valueWithUIEdgeInsets:newInsets]), animated);
}]
subscribeNext:^(RACTuple *tuple) {
RACTupleUnpack(NSValue *insets, NSNumber *animated) = tuple;
[self updateViewInsets:insets.UIEdgeInsetsValue navigationBarAlpha:1 animated:animated.boolValue];
}];
您可以通过RAC找到经常采用的替代方法。实验越多,你发现什么有效,什么不起作用,细微差别等等。
PS。适当的@weakify
/ @strongify
留作练习。
追问
另一种方法是使用-rac_liftSelector:
。以下是它如何用于您提供的代码。它与上面的代码非常相似,除了你将animated
标志提取到它自己的信号中,而不是将它嵌套到计算插入的信号中。
RACSignal *insets = [RACSignal
merge:@[
[movedToParentController reduceEach:^(UIViewController *parent) {
return parent;
}],
[endSearch reduceEach:^(id _) {
return self.parentViewController;
}]
]]
map:^(UIViewController *parent) {
CGFloat top = parent.topLayoutGuide.length;
CGFloat bottom = parent.bottomLayoutGuide.length;
UIEdgeInsets newInsets = UIEdgeInsetsMake(top, 0, bottom, 0);
return [NSValue valueWithUIEdgeInsets:newInsets];
}];
RACSignal *animated = [RACSignal merge:@[
[movedToParentController mapReplace:@NO],
[endSearch mapReplace:@YES],
];
RACSignal *alpha = [RACSignal return:@1];
[self rac_liftSelector:@selector(updateViewInsets:navigationBarAlpha:animated:) withSignals:insets, alpha, animated, nil];
国际海事组织,这两种做法都不是明显胜过对方。但是,指南建议avoiding explicit subscription。