简体   繁体   English

iOS视图动画允许用户交互

[英]iOS view animation allow user interaction

I am making a game similar to Piano Tiles https://itunes.apple.com/us/app/piano-tiles-dont-tap-white/id848160327?mt=8 我正在制作类似于Piano Tiles的游戏https://itunes.apple.com/us/app/piano-tiles-dont-tap-white/id848160327?mt=8

you can tap a tile even when the earlier animation is not finished. 即使较早的动画尚未完成,您也可以点击图块。

Here is my implementation 这是我的实现

- (void)moveDown {


    [UIView animateWithDuration:DURATION_MOVE_DOWN delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{

        for (Tile *t in self.tiles) {
            if (t.y == NUM_TILES_Y - 1) {
                t.y = 0;
            }
            else {
                t.y++;
            }

            if (t.y == 0) {
                //move down
                //then place it to the top (in the completion handler)
                t.frame = [Tile frameWithX:t.x y:NUM_TILES_Y];
            }
            else {
                //move down
                t.frame = [Tile frameWithX:t.x y:t.y];
            }

        }

    } completion:^(BOOL finished) {

        for (Tile *t in self.tiles) {
            //if user tap while animating, just place the tile at its final position first, (then continue the new animation)
            t.frame = [Tile frameWithX:t.x y:t.y];
        }

        [self assignTouchDontTouchWithRowY:0];

    }];

}

the assignTouchDontTouchWithRowY method is to randomly pick a tile of a row to be TileTypeTouch(black tile) and the rest of the row to be TileTypeDontTouch (white tile) AssignTouchDontTouchWithRowY方法是随机选择一行的一个磁贴为TileTypeTouch(黑色磁贴),该行的其余部分为TileTypeDontTouch(白磁贴)

- (void)assignTouchDontTouchWithRowY:(int)y {
    int touchX = [Helper randomIntInclusiveBetweenLow:0 High:NUM_TILES_X -1];
    for (int x = 0; x < NUM_TILES_X; x++) {
        Tile *t = [self tileWithX:x y:y];
        if (x == touchX) {
            t.type = TileTypeTouch;
        }
        else {
            t.type = TileTypeDontTouch;
        }
    }

}

The problem is that, when I press a tile before the earlier animation is completed, some of the code is not executed (eg coloring a new row, moving down a row, and sometimes the bottom row gets translated above to the top instead of sliding down first, then place at the top) 问题是,当我在较早的动画完成之前按一个图块时,某些代码未执行(例如,为新行着色,向下移动一行,有时底部的行会从上方翻译到顶部而不是滑动首先向下,然后放在顶部)

When I use the option UIViewAnimationOptionBeginFromCurrentState , the user interaction gets canceled when the earlier one is animating. 当我使用选项UIViewAnimationOptionBeginFromCurrentState ,当较早的一个动画时,用户交互将被取消。 So it's not working either. 因此它也不起作用。

Edit: 编辑:

在此处输入图片说明

In the screenshot, the (0, 1) tile is the second last one tapped, it got translated to the top (without sliding down and being updated its color) 在屏幕截图中,(0,1)磁贴是倒数第二个,它被平移到顶部(不向下滑动并更新其颜色)

also note that above the (y=1) row, there is another row (y=0) outside the screen. 还请注意,在(y = 1)行上方,屏幕外还有另一行(y = 0)。 ie there are 5 rows, 4 of which are on screen and the first row (y=0) is at the top outside the screen. 即有5行,其中4行在屏幕上,第一行(y = 0)在屏幕外部的顶部。 When sliding down, the last row (y=4) slide down first, then place it at the top (y=0) in the completion handler 向下滑动时,最后一行(y = 4)首先向下滑动,然后将其放在完成处理程序的顶部(y = 0)

EDIT 3: just in case my logic is not clear: 编辑3:以防万一我的逻辑不清楚:

  1. When tap on the black tile, all tiles move down 点按黑色图块时,所有图块都向下移动
  2. for the last row (y=4), I move it down first, then place it at the top(outside screen) in completion handler 对于最后一行(y = 4),我先将其向下移动,然后将其放置在完成处理程序的顶部(外部屏幕)
  3. if user tap a tile during animation, I firstly immediately place the tiles at the correct position (ie the final state of the old animation), then I start the new animation. 如果用户在动画过程中轻触图块,我首先会立即将图块放置在正确的位置(即旧动画的最终状态),然后开始新的动画。

EDIT 4: error is illustrated in the video here 编辑4:此处的视频说明了错误

https://drive.google.com/file/d/0B-iP0P7UfFj0Q01neEhaZmtBY2c/edit?usp=sharing https://drive.google.com/file/d/0B-iP0P7UfFj0Q01neEhaZmtBY2c/edit?usp=sharing

the completion block is executed after the new animation (which happens immediately when you call -moveDown 完成块是在新动画之后执行的(调用-moveDown时会立即发生

when will the completion block get executed? 完工块什么时候执行? we don't know! 我们不知道! it's in the queue/future! 它在排队/未来!

so move the clean-up code for the previous animation to the beginning of moveDown (outside animiation, and dont forget to check if (finished) to save some unnecessary work 因此,将上一个动画的清理代码移到moveDown的开头(动画之外),并且不要忘记检查(完成)是否省去了一些不必要的工作

- (void)moveDown {

    Tile *t = self.tiles[0];
    if (t.layer.animationKeys.count) {
        for (Tile *t in self.tiles) {
            t.frame = [Tile frameWithX:t.x y:t.y];
        }
        [self assignTouchDontTouchWithRowY:0];

    }


    [UIView animateWithDuration:DURATION_MOVE_DOWN delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{

        NSLog(@"anim");
        for (Tile *t in self.tiles) {
            if (t.y == NUM_TILES_Y - 1) {
                t.y = 0;
            }
            else {
                t.y++;
            }

            if (t.y == 0) {
                //move down
                //then place it to the top (in the completion handler)
                t.frame = [Tile frameWithX:t.x y:NUM_TILES_Y];
            }
            else {
                //move down
                t.frame = [Tile frameWithX:t.x y:t.y];
            }

        }

    } completion:^(BOOL finished) {

        if (finished) {

            for (Tile *t in self.tiles) {
                if (t.y == 0) {
                    t.frame = [Tile frameWithX:t.x y:t.y];
                }
            }
            [self assignTouchDontTouchWithRowY:0];


        }


    }];

}

Try this: 尝试这个:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint touchPoint = [touch locationInView:self.view];
    if ([[movingView.layer presentationLayer] hitTest:touchPoint])
    {
        //Do stuff here
    }
}

I got this from here 我从这里得到的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM