Очень похоже на UIRfreshControl, я пытаюсь поместить UIView поверх UITableView. Перетаскивание табличного представления должно открыть представление и оставить его там. Перетаскивание вверх должно снова скрыть его, а затем прокрутить представление таблицы. Когда скрытый вид таблицы должен прокручиваться нормально. Прокрутка вверх должна либо снова показать скрытый вид, либо привязаться к скрытому состоянию. В конечном итоге отображаемое представление должно содержать несколько кнопок или сегментированный элемент управления. Оно должно выглядеть и вести себя очень похоже на приложение OmniFocus.
Скрытый вид в OmniFocus
Открытое представление в OmniFocus
Вот как далеко я зашел. Особенно не работает возврат к скрытому состоянию, когда прокручивается табличное представление. Если вы правильно рассчитаете время, вы застрянете в середине вида сверху, а это совсем не то, чего я хочу.
static CGFloat const kTopViewHeight = 40;
@interface ViewController ()
@property (nonatomic, weak) UIView *topView;
@property (nonatomic, assign) CGFloat dragStartY;
@end
@implementation ViewController
#pragma mark - View Lifecycle
- (void)viewDidLoad
{
CGRect topViewFrame = CGRectMake(0.0, -kTopViewHeight, 320, kTopViewHeight);
UIView *myView = [[UIView alloc] initWithFrame:topViewFrame];
myView.backgroundColor = [UIColor greenColor]; // DEBUG
self.topView = myView;
[self.tableView addSubview:myView];
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
NSLog(@"scrollViewWillBeginDragging %@", NSStringFromCGPoint(scrollView.contentOffset));
self.dragStartY = scrollView.contentOffset.y;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSLog(@"scrollViewDidScroll %@", NSStringFromCGPoint(scrollView.contentOffset));
if (scrollView.contentOffset.y > 0) {
// reset the inset
scrollView.contentInset = UIEdgeInsetsZero;
} else if (scrollView.contentOffset.y >= -kTopViewHeight) {
// set the inset for the section headers
scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
} else if (scrollView.contentOffset.y < -kTopViewHeight) {
// don't scroll further when the topView's height is reached
scrollView.contentInset = UIEdgeInsetsMake(-kTopViewHeight, 0, 0, 0);
scrollView.contentOffset = CGPointMake(0, -kTopViewHeight);
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
NSLog(@"scrollViewDidEndDragging %@", NSStringFromCGPoint(scrollView.contentOffset));
CGFloat yOffset = scrollView.contentOffset.y;
if (yOffset < 0) {
BOOL dragDown = self.dragStartY > yOffset;
CGFloat dragThreshold = 10;
if (dragDown) {
if (yOffset <= -dragThreshold) {
[self snapDown:YES scrollView:scrollView];
} else {
[self snapDown:NO scrollView:scrollView];
}
} else if (!dragDown) {
if (yOffset >= dragThreshold - kTopViewHeight) {
[self snapDown:NO scrollView:scrollView];
} else {
[self snapDown:YES scrollView:scrollView];
}
}
}
}
- (void)snapDown:(BOOL)down scrollView:(UIScrollView *)scrollView
{
[UIView animateWithDuration:0.3
delay:0
options:UIViewAnimationOptionAllowUserInteraction|UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionBeginFromCurrentState
animations:^{
if (down) {
// snap down
scrollView.contentOffset = CGPointMake(0, -kTopViewHeight);
scrollView.contentInset = UIEdgeInsetsMake(kTopViewHeight, 0, 0, 0);
} else {
// snap up
scrollView.contentOffset = CGPointMake(0, 0);
scrollView.contentInset = UIEdgeInsetsZero;
}
}
completion:nil];
}