如何使表滚动工作:UIControl中的UITonView内的UIControl

时间:2013-12-02 18:39:15

标签: ios objective-c uitableview uicontrol

这是设置:我在表格单元格中有UIControls,允许从右向左滑动以获取删除功能(如清除)

表格单元格位于UITableView内。

TableView位于另一个UIControl中,允许从左到右或从右到左滑动以更改天数。当发生这种情况时,新的TableView被创建到主要的一个右侧或左侧,并且新的一个从左或右拉入,直到满足阈值并且动画接管然后将旧的替换为新的。

在某些情况下,所有这些互动实际上都能正常运作。问题是,经过几次互动(表格幻灯片似乎有问题)后,滚动表格变得困难/不可能。

这是TableViewSlider的代码(包含TableViews的顶级UIControl)。任何想法将不胜感激!

 @implementation OSETableViewSlider


- (void) initialize {
    self.backgroundColor = [UIColor backgroundFlatColor];
    self.mainTableView = [self createUITableView];
    self.mainTableView.frame = CGRectMake(0,0, self.frame.size.width, self.frame.size.height);
    self.mainTableView.hidden = NO;
    [self addSubview:self.mainTableView];
    self.transitionInProgress = NO;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self initialize];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if(self) {
        [self initialize];
    }
    return self;
}

- (UITableView *)createUITableView {
    UITableView *newTable = [[UITableView alloc] init];
    newTable.hidden = YES;
    newTable.separatorStyle = UITableViewCellSeparatorStyleNone;
    newTable.scrollEnabled = YES;
    newTable.bounces = YES;
    newTable.dataSource = self;
    newTable.delegate = self;
    newTable.backgroundColor = [UIColor backgroundFlatColor];

    return newTable;
}

- (void)setFrame:(CGRect)frame {
    super.frame = frame;
    self.mainTableView.frame = CGRectMake(0,0, frame.size.width, frame.size.height);
}

- (void)transitionToDate:(NSDate *)date fromRight:(BOOL)rightToLeft {
    [self.viewController beginTransitionToDate:date];

    self.transitionTableView = [self createUITableView];
    self.transitionTableView.frame = CGRectMake( rightToLeft ? self.frame.size.width : (-1 * self.frame.size.width), 0,
                                                 self.frame.size.width, self.frame.size.height );
    self.transitionTableView.hidden = NO;
    [self addSubview:self.transitionTableView];

    self.transitionInProgress = YES;

    [UIView animateWithDuration:0.2f animations:^{
        self.transitionTableView.frame = CGRectMake(0,0, self.frame.size.width, self.frame.size.height);

        self.mainTableView.frame = CGRectMake( rightToLeft ? (-1 * self.frame.size.width) : self.frame.size.width, 0,
                                              self.frame.size.width, self.frame.size.height);
    } completion:^(BOOL completed){
        [self.viewController endTransitionDidChange:YES];
        [self.mainTableView removeFromSuperview];
        self.mainTableView = self.transitionTableView;

        self.transitionInProgress = NO;

    }];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.viewController activityCountForTransition:(tableView!=self.mainTableView)];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    return [self.viewController cellNumber:indexPath.item forTransition:(tableView!=self.mainTableView)];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return [self.viewController cellNumber:indexPath.item forTransition:(tableView!=self.mainTableView)].frame.size.height;
}

- (void)layoutSubviews {
    if(!self.transitionInProgress) {
        [self.mainTableView setFrame:CGRectMake(0,0, self.frame.size.width, self.frame.size.height)];
    }
}

- (BOOL) beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    NSLog(@"begin track");

    self.locationInView = [touch locationInView:self.superview];
    self.fingerTracking = YES;
    self.fingerMoved = NO;
    self.transitionTableView = nil;

    return YES;
}

- (CGFloat) calcOffsetForTouch:(UITouch *)touch {
    CGFloat fingerOffset = [touch locationInView:self.superview].x - self.locationInView.x;
    return fingerOffset + self.startingOffset;
}

- (BOOL) continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    self.fingerMoved = YES;
    CGFloat offset = [self calcOffsetForTouch:touch];

    //NSLog(@"offset is: %f    flarb: %f", offset, fabs(offset));

    if(offset < 0 && (!self.transitioningLeft || [OSEUtils isNull:self.transitionTableView])) {
        [self.viewController beginTransitionToDate:[OSEUtils daysOffset:1 fromDate:self.viewController.selectedDate withTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]]];
        [self.transitionTableView removeFromSuperview];
        self.transitionTableView = [self createUITableView];
        self.transitioningLeft = YES;
        NSLog(@"going left");
        [self addSubview:self.transitionTableView];
        [self.transitionTableView reloadData];
    }
    if(offset > 0 && (self.transitioningLeft || [OSEUtils isNull:self.transitionTableView])) {
        [self.viewController beginTransitionToDate:[OSEUtils daysOffset:-1 fromDate:self.viewController.selectedDate withTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]]];
        [self.transitionTableView removeFromSuperview];
        self.transitionTableView = [self createUITableView];
        self.transitioningLeft = NO;
        NSLog(@"going right");
        [self addSubview:self.transitionTableView];
        [self.transitionTableView reloadData];
    }

    CGFloat mult = self.transitioningLeft ? 1 : -1;

    if(fabs(offset) > (self.frame.size.width / 3.0f)) {
        if(self.transitioningLeft) {
            offset = -1 * self.frame.size.width;
        } else {
            offset = self.frame.size.width;
        }

        [UIView animateWithDuration:0.2f animations:^{
            self.mainTableView.frame = CGRectMake(offset, 0, self.frame.size.width, self.frame.size.height);
            self.transitionTableView.frame = CGRectMake(offset + (mult * self.frame.size.width), 0,
                                                        self.frame.size.width, self.frame.size.height);
        } completion:^(BOOL finished) {
            [self.mainTableView removeFromSuperview];

            if(self.transitioningLeft) {
                [self.viewController.daySelector jumpToNext];
            } else {
                [self.viewController.daySelector jumpToPrevious];
            }

            self.mainTableView = self.transitionTableView;
            self.transitionTableView = nil;

            [self.viewController endTransitionDidChange:YES];
        }];

        return NO;
    }

    self.mainTableView.frame = CGRectMake(offset, 0, self.frame.size.width, self.frame.size.height);
    self.transitionTableView.frame = CGRectMake(offset + (mult * self.frame.size.width), 0, self.frame.size.width, self.frame.size.height);
    self.transitionTableView.hidden = NO;

    return YES;
}



- (void) endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    NSLog(@"end tableslide track");
    [UIView animateWithDuration:0.2f animations:^{
        self.mainTableView.frame = CGRectMake(0,0,self.frame.size.width, self.frame.size.height);
        self.transitionTableView.frame = CGRectMake(((self.transitioningLeft ? 1 : -1 ) * self.frame.size.width), 0, self.frame.size.width, self.frame.size.height);
    } completion:^(BOOL completion){
        [self.transitionTableView removeFromSuperview];
        self.transitionTableView = nil;
        [self.viewController endTransitionDidChange:NO];
    }];



    self.fingerTracking = NO;
}


- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *tableHitTest = [self.mainTableView hitTest:point withEvent:event];
    if([tableHitTest isKindOfClass:[OSECellPanelControl class]]) {
        return tableHitTest;
    } else {
        return self;
    }
}

@end

4 个答案:

答案 0 :(得分:1)

当用户向左或向右滑动时,为什么要创建新的UITableView?使用内置的deleteRowsAtIndexPath:insertRowsAtIndexPath:方法为滑入和滑出的行设置动画效果会更加高效,而无需滑入和滑出整个UITableView

您可以在浏览日期时查看tableview内容更改动画,以便at this for a reference

我不知道您当前的设置,但是当我尝试使用可滑动的UITableViewCell这个完全相同的东西并且它的超级视图可以刷卡时,我遇到了获得我想要的交互的问题。如果这有助于解决您的问题,您可以查看检测用户滑动的位置。如果用户在UITableViewCell的左右边缘的特定偏移内滑动,则它会滑动单元格,该偏移之外的任何内容(单元格的中心)都会刷过UITableView本身。然后,您可以设置删除和插入新行的动画。

此外,通过每次重新实例化一个新的UITableView,您每次都强制重新实例化UITableViewCell。通过使用删除和插入方法,您可以通过dequeueReusableCellWithIdentifier方法继续使用现有单元格。每次重新实例化UITableView时,您的单元格都将设置为nil并丢弃,需要新的tableview创建单元格的完整新实例。这是非常低效的。

答案 1 :(得分:1)

您正在深入了解触摸跟踪和点击检测。请使用更高级别的API - 手势识别器。使用手势,您可以设置优先级(在此之前必须先失败)。

因此,您需要在容器视图上进行几个自定义手势(不再需要作为控件)。如果初始触摸点不在视图的边缘(在某个边界内),则这些失败。这些会触发整个表视图的更改。

表格单元格具有滑动手势,每个手势都需要自定义手势失败。这些会触发您的细胞删除逻辑。

答案 2 :(得分:1)

您的想法与iOS7解锁屏幕和日历的构建方式有一些相似之处。在解锁屏幕中,您可以滑动通知,上下移动通知列表,然后滑动以解锁。在日历应用中,您可以滑动以更改当前日期,或者滑动标题以更改周。因此,我建议观看 WWDC 2013会话视频#217“探索iOS 7上的滚动视图”,它解释并演示了他们是如何完成的,以及如何复制功能。

基本上,你可以做的(以及他们为解锁屏幕和日历屏幕做了什么)是:(A)在UITableView中嵌套UIScrollViews或(B)在每个单元格上使用滑动/平移手势委托,(C)嵌套UITableView以及其他UITableViews,表示启用了分页控制的UIScrollView中的天数。

(A)将允许您在单元格中公开删除按钮。您可以将删除按钮放在单元格中的UIScrollView下,以滑动内容的方式显示它。

(B)将允许您跟踪单元格中的手势,如果需要可以取消它,并使用单元格的contentView来显示删除按钮。

(C)将允许您轻松地从一个UITableView滑动到另一个UITableView,并且通过分页启用,您将获得免费的“卡入到位或反弹”动画PLUS您可以轻松地重复使用两个UITableViews而不是每天分配一个。

就个人而言,我会选择(B)(C)

答案 3 :(得分:0)

原来我的hitTest方法存在问题。用[super hitTest ...]替换[self.mainTableView hitTest ...]解决了我的问题。我想我弄乱了一些坐标,导致这个方法在返回视图时返回nil。我并不是100%确定它究竟出了什么问题,但它现在确实有效。