只是试图围绕某些情况下的 ReactiveCocoa 方法。
我有一个段 Controller 换出 subview Controller 的情况。我需要在这里完成几件事:
contentInset
的tableView
因为 iOS7 没有为我处理自定义容器 View 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
创建一个 RACSubject . top
我的 tableView.contentInset
的值(value)成信号sendNext:@(YES)
至currentlySearchingSignal
当searchBarShouldBeginEditing
被调用(以及何时返回 YES)sendNext:@(NO)
至currentlySearchingSignal
当searchBarShouldEndEditing
被调用(以及何时返回 YES)好吧,我被困住了。我知道我需要以某种方式组合/订阅这些,但试图以非状态方式考虑它。
contentInset.top
尚未正确设置( topLayoutGuide
),我需要在没有动画的情况下设置它。 contentInset.top
时设置不正确(状态栏框架)我需要执行动画(然后在我的动画完成之前不要再次更新)contentInset.top
设置不正确(topLayoutGuide
)我需要执行动画(在动画完成之前不要再次更新)试图解决它
这是我的开始。试图解决#1,但它还没有工作。
- (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;
}
}];
}
最佳答案
这是我从 GitHub 问题中复制的答案:
我没用过ReactiveCocoaLayout ,但我怀疑您可能会发现除了 RAC 之外,还可以使用 RCL 来改进其中的一些代码。我相信其他人会提供更多详细信息。
我建议的第一件事是阅读 -rac_signalForSelector:
.它对于在委托(delegate)回调和 RAC 信号之间架起桥梁非常有值(value)。
例如,以下是获取代表所需回调的信号的方式:
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:)];
现在,假设您有一个更新 View 的方法:
- (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:
的信号.这些信号中的每一个都映射到适当的父 View Controller ,并与指示是否执行动画的 bool 值配对。这对值被打包成 RACTuple
.接下来,使用
-reduceEach:
, (UIViewController *, BOOL)
元组映射到 (UIEdgeInsets, BOOL)
元组。此映射从父 View Controller 计算边缘插入,但不会更改 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];
IMO,这两种方法都不是另一种方法的明显赢家。然而,指南推荐avoiding explicit subscription .
关于reactive-cocoa - 用副作用 react 委托(delegate)方法的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19170122/