如何使UIAnimation一次执行一次(遍历for循环),而不是一次执行全部?

时间:2019-09-26 07:23:56

标签: ios objective-c swift xcode mobile

我目前正在为一个应用创建一个视图控制器,以帮助可视化Bubble Sort算法。但是,当用户按下排序按钮时,不是一次接一个地进行交换(给用户一些时间来查看算法的工作原理),而是数字一次全部排序,并且它们一次都转到各自的位置。我希望让UIAnimation遍历for循环,并使元素一次一交换,而不是一次全部交换。

我已经尝试过将延迟作为参数传递给UIView.animate方法。它所做的只是在将它们全部排序之前暂停指定的时间(我不想要)。

//IBOutlets for the images (containing numbers) and the sort button
@IBOutlet weak var sortButton: UIButton!

@IBOutlet weak var firstImage: UIImageView!
@IBOutlet weak var secondImage: UIImageView!
@IBOutlet weak var thirdImage: UIImageView!
@IBOutlet weak var fourthImage: UIImageView!
@IBOutlet weak var fifthImage: UIImageView!
@IBOutlet weak var sixthImage: UIImageView!
@IBOutlet weak var seventhImage: UIImageView!
@IBOutlet weak var eighthImage: UIImageView!
@IBOutlet weak var ninthImage: UIImageView!
@IBOutlet weak var tenthImage: UIImageView!


//Create an array of UIImageViews
var elements : [UIImageView] = [UIImageView]()
var numberArray : [Int] = [Int]()

//Function when the view loads
override func viewDidLoad() {

    super.viewDidLoad()

    //Add the UIImageViews to the array
    elements += [firstImage, secondImage, thirdImage, fourthImage, fifthImage, sixthImage, seventhImage, eighthImage, ninthImage, tenthImage]

    //Create a variable that will indicate whether there is a duplicate number in the array
    var duplicate = true;

    //Assign each element in the array a random number between 1 and 10
    for index in elements {
        //Repeat-while loop to avoid duplicate numbers in the array
        repeat {
            //Create a random number
            let randNumber = Int.random(in: 1 ... 10)
            //Display the appropriate numbered image
            index.image = UIImage(named: "\(randNumber)")
            //Check to see if the number is already a duplicate
            if numberArray.contains(randNumber) {
                duplicate = true
            } else {
                duplicate = false
                //Add the number to the list of used numbers in the array
                numberArray.append(randNumber)
            }
        } while duplicate == true
    }
} //End of viewDidLoad




@IBAction func sortButtonPressed(_ sender: Any) {

    //Bubble Sort algorithm
    for i in (0..<elements.count) {
        for j in (1..<elements.count) {
            if numberArray[j]<numberArray[j-1] {

                let temp = numberArray[j-1]
                numberArray[j-1] = numberArray[j]
                numberArray[j] = temp

                let tempElement = elements[j-1]
                elements[j-1] = elements[j]
                elements[j] = tempElement

                //Swap the corresponding UIImageViews on screen
                let tempView : CGRect = elements[j-1].frame

                UIView.animate(withDuration: 0.75, delay: 0, animations: {
                    self.elements[j-1].frame = CGRect(x: self.elements[j].frame.minX, y: self.elements[j].frame.minY, width: tempView.width, height: tempView.height)
                    self.elements[j].frame = CGRect(x: tempView.minX, y: tempView.minY, width: self.elements[j].frame.width, height: self.elements[j].frame.width)
                    self.view.layoutIfNeeded()
                })
            }
        }
    }
}

有人知道如何使图像交换(动画)一次(每次迭代)而不是一次全部发生吗? (焦点区域位于sortButtonPressed函数的底部...)任何帮助将不胜感激。感谢您的提前帮助!

1 个答案:

答案 0 :(得分:0)

要手动执行此操作,您需要在当前动画完成后开始一个新动画。这样做的方法很少,但其中一种方法是将动画所需的所有数据打包到一个类中,然后创建此类数组。然后,您可以创建一个递归调用的方法。像这样:

- (void)performAllAnimations:(NSArray *)allAnimations
{
    NSMutableArray *duplicate = [allAnimations mutableCopy];
    AnimationDescription *currentAnimation = duplicate.firstObject;
    [duplicate removeObjectAtIndex:0];

    [UIView animateWithDuration:currentAnimation.duration animations:^{
        // Use currentAnimation to do the animation
    } completion:^(BOOL finished) {
        if(duplicate.count > 0) [self performAllAnimations:duplicate];
    }];
}

您不一定总是需要AnimationDescription作为自定义类。在您的情况下,仅使用索引数组就足够了。例如,您将这样做:

- (void)performAllAnimations:(NSArray *)allAnimations
{
    NSMutableArray *duplicate = [allAnimations mutableCopy];
    int currentAnimationIndex = [duplicate.firstObject integerValue];
    [duplicate removeObjectAtIndex:0];

    [UIView animateWithDuration:0.3 animations:^{
        // Use currentAnimation to do the animation
    } completion:^(BOOL finished) {
        if(duplicate.count > 0) [self performAllAnimations:duplicate];
    }];
}

然后您可以执行以下操作:

NSMutableArray *indexArray = [[NSMutableArray alloc] init];
for(int i=0; i<10; i++) {
    [indexArray addObject:@(i)];
}
[self performAllAnimations: indexArray];

自然使用您自己的数据。

另一种方法是使用延迟。在某些情况下,这可能会更好,因为您可以更好地控制下一个动画的开始时间。请参见以下示例:

- (void)performAllAnimations:(NSArray *)allAnimations withAnimationExecution:(void (^)(id animationObject, int index))execution
{
    NSTimeInterval duration = 0.3;

    for(int i=0; i<allAnimations.count; i++) {
        [UIView animateWithDuration:duration delay:(duration*0.5)*i options:UIViewAnimationOptionCurveEaseInOut animations:^{
            execution(allAnimations[i], i);
        } completion:^(BOOL finished) {

        }];
    }
}

- (void)testAnimation
{
    NSMutableArray *views = [[NSMutableArray alloc] init];
    for(int i=0; i<10; i++) {
        UIView *aView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 50.0, 100.0, 100.0)];
        [self.view addSubview:aView];
        aView.backgroundColor = [UIColor blackColor];
        aView.layer.borderWidth = 2.0;
        aView.layer.borderColor = [UIColor yellowColor].CGColor;
        [views addObject:aView];
    }
    [self performAllAnimations:views withAnimationExecution:^(id animationObject, int index) {
        UIView *view = animationObject;
        view.frame = CGRectMake(75.0*index, 100.0, 100.0, 100.0);
    }];
}