UIView animateWithDuration在iOS 8中的行为有所不同

rat*_*p99 0 iphone animation uiview ios ios8.1

我刚刚从iOS 7.1切换到iOS 8.1.我遇到了以下问题UIView animateWithDuration.图片胜过千言万语,我制作了每个iOS下的行为视频:

iOS 7.1:

https://vimeo.com/113887812

iOS 8.1:

https://vimeo.com/113887814

这是一款iPhone应用程序.

我应该注意到,在发布之前我已经搜索了SO和其他地方.这似乎是一个公认的问题,但我发现的是一些参考"使用基于约束的动画"(我不明白)并关闭自动布局,但没有真正的共识.

我已经尝试了几次刺伤,但没有任何进展.如果有人能指出(或指导我)一个明确的解决方案,我真的很感激.

我应该提一下,该应用程序只能在纵向位置工作,所以我没有考虑在开发过程中自动布局.

所有涉及的视图都是以编程方式创建的,除了滚动条本身.

这是代码.我包括整个方法,这很长,但我真的不明白新iOS中发生了什么变化,所以我是安全的.这个animateWithDuration电话非常深入到这个块中:


-(void) displayDayChart
{
    [self.scroller setBackgroundColor:[UIColor clearColor]];

    UIImage *image = [UIImage imageNamed:@"GrayPaper.png"];
    self.chartView.backgroundColor = [UIColor colorWithPatternImage:image];

    [self.view addSubview:self.scroller];
    [self.scroller setScrollEnabled:YES];

    [self.scroller setContentSize:CGSizeMake(320, 1800)];
    [self.scroller setContentOffset:CGPointMake(0.0, 0.0) animated:YES];

    dayBarArray = [[NSMutableArray alloc]init];
    infoLabelArray = [[NSMutableArray alloc]init];
    timeLabelArray = [[NSMutableArray alloc]init];

    timeFrameDC = - 86400; // 24 hours for this test, selectable in real life

    [self.scroller.subviews makeObjectsPerformSelector: @selector(removeFromSuperview)];

    timeframeDCStart = [NSDate dateWithTimeIntervalSinceNow:timeFrameDC];
    timeframeDCEnd = [timeframeDCStart dateByAddingTimeInterval:abs(timeFrameDC)];

    actPredicate = [NSPredicate predicateWithFormat:@"(startTime >= %@ AND stopTime <= %@) OR ((startTime <= %@ AND stopTime >= %@) OR (startTime <= %@ AND stopTime == NULL))",timeframeDCStart,timeframeDCEnd,timeframeDCStart,timeframeDCStart,timeframeDCEnd];

    NSFetchedResultsController *dayActivityFRC = [TimedActivity MR_fetchAllSortedBy:@"startTime" ascending:YES withPredicate:actPredicate groupBy:nil delegate:nil];


    double taDuration;
    double activityPercent;
    int barHeight;
    int lastHeight = 0;
    int tickerCount = 1;
    int barY;
    int lastBarY = 0;
    CGRect lastBarFrame;



#pragma mark DisplayDayChart setup

    for (TimedActivity *activity in dayActivityFRC.fetchedObjects)
    {
        // Create bar and associated labels

        thisBar = [[DayChartBar alloc] initWithFrame:CGRectZero];

        thisInfoLabel = [[UILabel alloc]initWithFrame:CGRectZero];
        thisTimeLabel = [[UILabel alloc]initWithFrame:CGRectZero];
        arrowView = [[UIView alloc]initWithFrame:CGRectZero];

        thisBar.tag = tickerCount;

        thisInfoLabel.tag = thisBar.tag + 100;
        thisTimeLabel.tag = thisBar.tag + 200;

        arrowView.tag = thisBar.tag + 300;
        UIImage *image = [UIImage imageNamed:@"LeftArrowRed.png"];


        // Add them to the scroller

        [self.scroller addSubview:thisBar];
        [self.scroller addSubview:thisInfoLabel];
        [self.scroller addSubview:thisTimeLabel];
        [self.scroller addSubview:arrowView];



        NSCalendar *calendar = [NSCalendar currentCalendar];


        if (!activity.stopTime) // Currently running
        {
            if ([activity.startTime timeIntervalSinceDate:timeframeDCStart] < 0)
            {
                dayBarDurationString = @"24:00:00";
                taDuration = (fabs([timeframeDCStart timeIntervalSinceDate:timeframeDCEnd]));
            }

            else
            {
                NSDateComponents *components= [calendar components:NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit fromDate:activity.startTime toDate:timeframeDCEnd options:0];
                NSInteger hours = [components hour];
                NSInteger minutes = [components minute];
                NSInteger seconds =[components second];
                dayBarDurationString = [NSString stringWithFormat:@"%02li:%02li:%02li",(long)hours,(long)minutes,(long)seconds];

                taDuration = (fabs([activity.startTime timeIntervalSinceDate:timeframeDCEnd]));
            }
        }

        else // Either early edge case or fully encapsulated
        {
            if ([activity.startTime timeIntervalSinceDate:timeframeDCStart] < 0) // Early edge case
            {
                NSDateComponents *components= [calendar components:NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit fromDate:timeframeDCStart toDate:activity.stopTime options:0];
                NSInteger hours = [components hour];
                NSInteger minutes = [components minute];
                NSInteger seconds =[components second];
                dayBarDurationString = [NSString stringWithFormat:@"%02li:%02li:%02li",(long)hours,(long)minutes,(long)seconds];

                taDuration = (fabs([activity.stopTime timeIntervalSinceDate:timeframeDCStart]));
            }

            else if ([activity.startTime  timeIntervalSinceDate:timeframeDCStart] > 0) // Encapsulated
            {
                NSDateComponents *components= [calendar components:NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit fromDate:activity.startTime toDate:activity.stopTime options:0];
                NSInteger hours = [components hour];
                NSInteger minutes = [components minute];
                NSInteger seconds =[components second];
                dayBarDurationString = [NSString stringWithFormat:@"%02li:%02li:%02li",(long)hours,(long)minutes,(long)seconds];

                taDuration = [activity.duration doubleValue];
            }

        }


        NSDateFormatter *localDateFormatter = [[NSDateFormatter alloc] init];
        [localDateFormatter setDateFormat:@"MMM dd"];

        NSDateFormatter *localTimeFormatter = [[NSDateFormatter alloc] init];
        [localTimeFormatter setDateFormat:@"hh:mm a"];



        NSString * timeLabelDateString = [[NSString alloc]init];

        NSString * timeLabelTimeString = [[NSString alloc]init];

        NSString * timeLabelString = [[NSString alloc]init];


        if (([activity.startTime timeIntervalSinceDate:timeframeDCStart] < 0))
        {
            timeLabelDateString = [localDateFormatter stringFromDate:timeframeDCStart];
            timeLabelTimeString = [localTimeFormatter stringFromDate:timeframeDCStart];
        }

        else
        {
            timeLabelDateString = [localDateFormatter stringFromDate:activity.startTime];
            timeLabelTimeString = [localTimeFormatter stringFromDate:activity.startTime];
        }


        timeLabelString = [NSString stringWithFormat:@"%@ - %@",timeLabelDateString,timeLabelTimeString];

        thisBar.endColor = activity.color;

        activityPercent = fabs((taDuration / timeFrameDC) * 100);

        if (activityPercent > 100)
        {
            activityPercent = 100;
        }

        if (activityPercent < 1.9)
        {
            activityPercent = 1.9;
        }


        barHeight = abs((self.scroller.contentSize.height - 100) * (activityPercent / 100));

        if (tickerCount == 1)
        {
            barY = self.scroller.contentSize.height -10;
        }

        else
        {
            barY = (lastBarY - lastHeight);
        }



#pragma mark DisplayDayChart animation


        [UIView animateWithDuration:.8
                              delay:0.0
                            options: UIViewAnimationCurveEaseInOut // Deprecated, but still works
                         animations:^
         {
             // Starting state *************************************

             thisBar.frame = CGRectMake(20, self.scroller.contentSize.height, 130, 0);
             thisBar.backgroundColor = [UIColor blackColor];

             thisInfoLabel.frame = CGRectMake(20, self.scroller.contentSize.height, thisBar.frame.size.width, 30);

             thisTimeLabel.frame = CGRectMake((thisBar.frame.origin.x) + (thisBar.frame.size.width + 35), self.scroller.contentSize.height, 150, 15);

             thisTimeLabel.textColor = [UIColor blueColor];

             arrowView.frame = CGRectMake(thisTimeLabel.frame.origin.x - 20, thisTimeLabel.frame.origin.y, 16, 16);


             thisInfoLabel.textColor = [UIColor clearColor];


             // End state *************************************

             thisBar.frame = CGRectMake(20, barY, 130, - barHeight);
             thisBar.backgroundColor = thisBar.endColor;

             thisBar.layer.shadowColor = [[UIColor blackColor] CGColor];
             thisBar.layer.frame = CGRectInset(thisBar.layer.frame, 0.0, 3.0);

             thisBar.layer.shadowOpacity = 0.7;
             thisBar.layer.shadowRadius = 4.0;
             thisBar.layer.shadowOffset = CGSizeMake(5.0f, 5.0f);


             // Position infoLabel

             thisInfoLabel.frame = CGRectMake(20, self.scroller.contentSize.height + ((thisBar.frame.size.height / 2) - 30), thisBar.frame.size.width, 30);


             thisTimeLabel.frame = CGRectMake((thisBar.frame.origin.x) + (thisBar.frame.size.width + 35), (thisBar.frame.origin.y) + (thisBar.frame.size.height) - 5, 150, 15);

             thisInfoLabel.textColor = [UIColor blackColor];

             dayBarNameString = activity.name;

             [thisInfoLabel setFont:[UIFont fontWithName:@"Noteworthy-Bold" size:16.0]];

             thisInfoLabel.numberOfLines = 0;

             thisInfoLabel.textAlignment = NSTextAlignmentCenter;
//             thisInfoLabel.layer.borderWidth = 1;


             thisInfoLabel.text = [NSString stringWithFormat:@"%@\n%@",dayBarNameString,dayBarDurationString];

             [thisInfoLabel sizeToFit];


             if ( thisInfoLabel.frame.size.height >= thisBar.frame.size.height)
             {
                 thisInfoLabel.text = [NSString stringWithFormat:@"%@",dayBarNameString];
             }

             else
             {
                 thisInfoLabel.text = [NSString stringWithFormat:@"%@\n%@",dayBarNameString,dayBarDurationString];
             }

             [thisInfoLabel sizeToFit];
             [thisInfoLabel setHidden:NO];

             thisInfoLabel.center = thisBar.center;

             arrowView.frame = CGRectMake(thisTimeLabel.frame.origin.x - 20, thisTimeLabel.frame.origin.y, 16, 16);
             arrowView.backgroundColor = [UIColor colorWithPatternImage:image];

             thisTimeLabel.textColor = [UIColor blueColor];
             [thisTimeLabel setFont:[UIFont boldSystemFontOfSize:13]];
             thisTimeLabel.numberOfLines = 0;

             thisTimeLabel.textAlignment = NSTextAlignmentLeft;

             thisTimeLabel.text = timeLabelString;

             [thisTimeLabel sizeToFit];


         }
                         completion:^(BOOL finished)
         {

             [self repositionLabels];

         }];


        [dayBarArray addObject:thisBar];
        [infoLabelArray addObject:thisInfoLabel];
        [timeLabelArray addObject:thisTimeLabel];
        taDuration = 0;
        tickerCount ++;


        lastBarY = barY;
        lastHeight = barHeight;
        lastBarFrame = thisBar.frame;

        [self positionInitialDayBarView];

    }
}
Run Code Online (Sandbox Code Playgroud)

Fog*_*ter 5

好的,先关闭.拒绝使用Interface Builder会丢失很多便利.这就像是说"我只使用Xcode 3,因为它曾经为我工作所以我只是保留它." Interface Builder是一个非常棒的工具,可以轻松创建UI.

实际问题

你说你没有使用AutoLayout.这是不正确的.

默认行为(在iOS8中肯定也是iOS7我认为)是当您创建UIView(或任何UI元素)并将其添加到视图时,系统将采用auto resizing mask视图并应用自动布局约束以匹配调整大小蒙版.

这意味着,当你这样做......

UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 100, 21)];
[self.view addSubView:label];
Run Code Online (Sandbox Code Playgroud)

然后标签添加了自动布局约束,以将其固定到位置(10,10)和尺寸(100,21).

你不能通过做...改变框架

label.frame = CGRectMake(10, 50, 100, 21);
Run Code Online (Sandbox Code Playgroud)

因为自动布局约束只会将其放回到它开始的位置.

解决方案

有两种解决方案.

正确的解决方法是学习如何使用自动版式.它已经存在了3年,并且对iOS开发变得越来越重要(即使只是在肖像iPhone应用程序上,您现在有4种不同的设备尺寸可以处理).如果你没有开始学习AutoLayout,你将被抛在后面.它现在几乎是所有iOS开发的必需品.

不正确的,非常非常糟糕的解决方案是从添加这些限制停止系统.您可以通过添加行来完成此操作...

label.translatesAutoresizingMaskIntoConstraints = NO;
Run Code Online (Sandbox Code Playgroud)

在创建标签(以及所有其他界面元素)之后.

这将阻止添加这些自动约束并阻止它们干扰您的布局内容.

但这是错误的解决方案.如果你这样做,你只是推迟了你必须学习自动布局的点.