Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 在循环中为UIView设置动画_Objective C_Ios_Animation_Bubble Sort - Fatal编程技术网

Objective c 在循环中为UIView设置动画

Objective c 在循环中为UIView设置动画,objective-c,ios,animation,bubble-sort,Objective C,Ios,Animation,Bubble Sort,我正在创建一个应用程序来展示冒泡排序是如何工作的。我遇到的一个问题是动画。它似乎正在跳过,动画正在同时启动。在if语句中,我希望交换两个图像并设置交换动画。然后我需要一个延迟,这样一旦他们交换了,它就会回到循环中,交换接下来的两个图像。下面是我的代码。我试过很多方法,比如睡眠,但似乎不起作用。图像是四个框,我将它们从左到右,从最小到最大进行交换 for (int i = 0; i < 3; i++) { UIImageView *temp1 = [imagesArray obj

我正在创建一个应用程序来展示冒泡排序是如何工作的。我遇到的一个问题是动画。它似乎正在跳过,动画正在同时启动。在if语句中,我希望交换两个图像并设置交换动画。然后我需要一个延迟,这样一旦他们交换了,它就会回到循环中,交换接下来的两个图像。下面是我的代码。我试过很多方法,比如睡眠,但似乎不起作用。图像是四个框,我将它们从左到右,从最小到最大进行交换

for (int i = 0; i < 3; i++)
{
    UIImageView *temp1 =   [imagesArray objectAtIndex:i];
    UIImageView *temp2 =  [imagesArray objectAtIndex:i+1];
    temp1Width = temp1.frame.size.width;
    temp2Width = temp2.frame.size.width;
    if (temp1Width > temp2Width)
    {
        CGPoint tempPoint = temp1.center;

        [UIView animateWithDuration:1.0
                              delay: 1.0
                            options: nil
                         animations:^{
                            temp1.center = temp2.center;

                         }
                         completion:^(BOOL finished){
                             [UIView animateWithDuration:1.0
                                                   delay: 0.0
                                                 options: nil
                                              animations:^{
                                                  temp2.center = tempPoint;
                                              }
                                              completion:^(BOOL finished){
                                              }];
                         }];
        [imagesArray exchangeObjectAtIndex:i+1 withObjectAtIndex:i];
    }
}
for(int i=0;i<3;i++)
{
UIImageView*temp1=[imagesArray对象索引:i];
UIImageView*temp2=[imagesArray对象索引:i+1];
temp1Width=temp1.frame.size.width;
temp2Width=temp2.frame.size.width;
如果(temp1Width>temp2Width)
{
CGPoint tempPoint=temp1.center;
[UIView animateWithDuration:1.0
延迟:1.0
选项:无
动画:^{
temp1.center=temp2.center;
}
完成:^(布尔完成){
[UIView animateWithDuration:1.0
延迟:0.0
选项:无
动画:^{
temp2.center=tempPoint;
}
完成:^(布尔完成){
}];
}];
[图像光线交换对象索引:i+1与对象索引:i];
}
}

如果有任何帮助,我们将不胜感激。

尝试使用计时器隐式执行,而不是使用循环和延迟。例如,可以使用持续时间等于或大于动画时间的计划的
NSTimer
,来触发此方法:

- (void)performNextAnimation:(NSTimer *)timer
{
    BOOL didSwap = NO;

    for(NSInteger i = 0; i < [self.imageViews count] - 1; ++i)
    {
        UIImageView *image1 = [self.imageViews objectAtIndex:i];
        UIImageView *image2 = [self.imageViews objectAtIndex:(i + 1)];

        if(image1.frame.size.width <= image2.frame.size.width)
            continue;

        CGPoint center1 = image1.center;
        CGPoint center2 = image2.center;

        [UIView animateWithDuration:AnimationDuration
                              delay:0
                            options:UIViewAnimationOptionCurveEaseInOut
                         animations:^
        {
            image1.center = center2;
            image2.center = center1;
        }
                         completion:nil];

        [self.imageViews exchangeObjectAtIndex:(i + 1) withObjectAtIndex:i];

        didSwap = YES;
        break;
    }

    if(!didSwap)
    {
        [self.animationTimer invalidate];
        self.animationTimer = nil;
        NSLog(@"Done!");
    }
}
-(void)PerformExtAnimation:(NSTimer*)计时器
{
BOOL-didSwap=NO;
对于(NSInteger i=0;i<[self.imageViews count]-1;++i)
{
UIImageView*image1=[self.imageViews对象索引:i];
UIImageView*image2=[self.imageViews对象索引:(i+1)];

如果(image1.frame.size.width即使调用animateWithDuration:delay:不同的时间,它们也几乎在同一时间被调用(“for”时间)。由于它们都具有相同的延迟,因此您看不到动画

一个简单的解决方法是使用动态延迟:

 [UIView animateWithDuration:AnimationDuration
                              delay:i
                            ...

如果将动画应用于已设置动画的视图,则新动画将替换现有动画。它不仅仅是附加到最后。这就是为什么您的版本无法按您希望的方式工作

即使在新动画上设置延迟,也会发生这种情况。现有动画将被删除,新动画将在指定的延迟后启动。这会阻止k20的简单答案工作。(太糟糕了,因为这将是一个非常简单的解决方案。)

因此,一个非常简单的替代方法是推迟添加每个附加动画。使用
dispatch\u after
函数非常简单。首先,让我们考虑一下将视图的Y原点交换为辅助函数的代码:

static void swapViewYOrigins(UIView *a, UIView *b) {
    CGRect aFrame = a.frame;
    CGRect bFrame = b.frame;
    CGFloat t = aFrame.origin.y;
    aFrame.origin.y = bFrame.origin.y;
    bFrame.origin.y = t;
    a.frame = aFrame;
    b.frame = bFrame;
}
现在我们可以编写排序函数,使用
dispatch\u after
延迟每个后续动画:

- (IBAction)sortButtonWasTapped {
    NSTimeInterval duration = 1;
    dispatch_time_t time = DISPATCH_TIME_NOW;
    for (int i = imagesArray.count - 1; i > 0; --i) {
        for (int j = 0; j < i; ++j) {
            UIView *a = imagesArray[j];
            UIView *b = imagesArray[j+1];
            if (a.frame.size.width > b.frame.size.width) {
                imagesArray[j] = b;
                imagesArray[j+1] = a;
                dispatch_after(time, dispatch_get_main_queue(), ^{
                    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
                        swapViewYOrigins(a, b);
                    } completion:nil];
                });
                time = dispatch_time(time, duration * NSEC_PER_SEC);
            }
        }
    }
}
然后,我们修改
sortbuttonwasttapped
,将块添加到队列中,而不是在
之后调用
dispatch\u,并使其在完成排序后开始运行队列:

- (IBAction)sortButtonWasTapped {
    pendingSwaps = [NSMutableArray array];
    for (int i = imagesArray.count - 1; i > 0; --i) {
        for (int j = 0; j < i; ++j) {
            UIView *a = imagesArray[j];
            UIView *b = imagesArray[j+1];
            if (a.frame.size.width > b.frame.size.width) {
                imagesArray[j] = b;
                imagesArray[j+1] = a;
                [pendingSwaps addObject:^{
                    swapViewYOrigins(a, b);
                }];
            }
        }
    }

    [self runPendingSwaps];
}
因此,如果队列为空,我们就停止。否则,我们从队列中取出第一个块,并将其用作
UIView
动画的动画块。我们给动画一个完成块,再次调用
runPendingSwaps
,在当前动画完成后启动下一个挂起的动画(如果有)

要取消,我们可以将
pendingSwaps
设置为零:

- (IBAction)cancelButtonWasTapped {
    pendingSwaps = nil;
}
请注意,如果用户点击取消,视图在屏幕上的顺序不一定与在
imagesArray
中的顺序相同,因为
imagesArray
sortbuttonwasttapped
返回时是完全排序的。我们可以通过按Y原点排序
imagesArray
来解决这个问题(使用内置排序)在开始气泡排序之前:

- (IBAction)sortButtonWasTapped {
    [self sortImagesArrayByY];
    // etc. same as previous version
}

- (void)sortImagesArrayByY {
    [imagesArray sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        CGFloat d = [obj1 frame].origin.y - [obj2 frame].origin.y;
        return
        d < 0 ? NSOrderedAscending
        : d > 0 ? NSOrderedDescending
        : NSOrderedSame;
    }];
}
-(iAction)排序按钮被点击{
[自我排序搜索];
//等。与前一版本相同
}
-(无效)sortImagesArrayByY{
[图像阵列排序器:^n比较结果(id obj1,id obj2){
CGD=[obj1帧].origin.y-[obj2帧].origin.y;
返回
d<0?去感测
:d>0?取消降级
:下载名称;
}];
}

有了这个选项,您可以单击“排序”按钮,然后在视图在屏幕上完全排序之前单击“取消”,然后再次单击“排序”,它将恢复(通过再次执行气泡排序)。

是否可以使用完成块来完成此操作?
- (void)runPendingSwaps {
    if (pendingSwaps.count == 0)
        return;

    void (^swapBlock)(void) = pendingSwaps[0];
    [pendingSwaps removeObjectAtIndex:0];
    [UIView animateWithDuration:1 animations:swapBlock completion:^(BOOL finished) {
        [self runPendingSwaps];
    }];
}
- (IBAction)cancelButtonWasTapped {
    pendingSwaps = nil;
}
- (IBAction)sortButtonWasTapped {
    [self sortImagesArrayByY];
    // etc. same as previous version
}

- (void)sortImagesArrayByY {
    [imagesArray sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        CGFloat d = [obj1 frame].origin.y - [obj2 frame].origin.y;
        return
        d < 0 ? NSOrderedAscending
        : d > 0 ? NSOrderedDescending
        : NSOrderedSame;
    }];
}