19

UIPageViewControllerトランジション アニメーションよりも速く移動するUnbalanced calls to begin/end appearance transitions for <MyDataViewController>と、「 」が表示され、ページをめくるまで横向きの 2 つのビューの 1 つが表示されません。

誰でもこのバグを解決するアイデアを持っていますか?

4

10 に答える 10

29

上記の答えは正しかったですが、必要以上に手の込んだものだと思います。クックブックは役に立ちます。だからここに私のために働いているように見えるものがあります:

pageViewController を設定して呼び出すビュー コントローラで、次のように宣言します。

@property (assign)              BOOL pageIsAnimating;

そしてviewDidLoadで:

    pageIsAnimating = NO;

これを追加:

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers {
    pageIsAnimating = YES;
}

そして、次の行を数行追加します。

- (void)pageViewController:(UIPageViewController *)pageViewController
    didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers
   transitionCompleted:(BOOL)completed {
    if (completed || finished)   // Turn is either finished or aborted
        pageIsAnimating = NO;
    ...
}

ジェスチャーは、ビュー コントローラー情報の提供を拒否することで抑制されます。

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
   viewControllerAfterViewController:(UIViewController *)viewController {
    if (pageIsAnimating)
        return nil;
    ...
    return after;
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
  viewControllerBeforeViewController:(UIViewController *)viewController {
    if (pageIsAnimating)
        return nil;
    ...
    return before;
}

ああ、向きを変更するとフラグがリセットされます。

- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
               spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation {
    pageIsAnimating = NO;
    ...
}
于 2013-02-11T22:44:45.820 に答える
9

次の手順に従って解決します。1-
アニメーションが終了したかどうかを示すフラグを宣言します。

BOOL pageAnimationFinished;

2- viewDidLoadでこのフラグをtrueに設定します:

pageAnimationFinished = YES;

3- pageViewControllerのtapGestureを無効にし、panGestureRecognizerデリゲートに「self」を割り当てます。

for (UIGestureRecognizer * gesRecog in self.pageViewController.gestureRecognizers)
{
    if ([gesRecog isKindOfClass:[UITapGestureRecognizer class]])
        gesRecog.enabled = NO;
    else if ([gesRecog isKindOfClass:[UIPanGestureRecognizer class]])
        gesRecog.delegate = self;
}

4-次のジェスチャレコグナイザーデリゲートメソッドを使用してpanGestureRecognizerを許可/禁止します。

-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && ([gestureRecognizer.view isEqual:self.view] || [gestureRecognizer.view isEqual:self.pageViewController.view]))
    {
        UIPanGestureRecognizer * panGes = (UIPanGestureRecognizer *)gestureRecognizer;
        if(!pageAnimationFinished || (currentPage < minimumPage && [panGes velocityInView:self.view].x < 0) || (currentPage > maximumPage && [panGes velocityInView:self.view].x > 0))
            return NO;
        pageAnimationFinished = NO;
    }
    return YES;
}

5-次のpageViewControllerデリゲートメソッドを追加します。

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
    pageAnimationFinished = YES;
}
于 2013-01-13T15:43:50.950 に答える
6

Basem Saadawy からの 良い回答ですが、いくつかの欠陥があります。

実際には、デリゲートのgestureRecognizerShouldBegin:は、それ以上アニメーションを開始せずに呼び出すことができました。これは、垂直方向の指の動きによってジェスチャを開始し、その水平方向のオフセットがアニメーションを開始するのに十分でない場合に可能です (しかし、gestureRecognizerShouldBegin:を起動するには十分です)。したがって、変数pageAnimationFinishedは、実際のアニメーションなしでNOに設定されます。したがって、pageViewController: didFinishAnimating:が呼び出されることはなく、現在のページは変更できずにフリーズします。

そのため、この変数にNOを割り当てるのに適した場所は、ジェスチャ認識エンジンのアクション メソッドで、その速度と平行移動を調べることです (水平方向のみに関心があります)。

したがって、最終的な手順は次のとおりです。

1) インスタンス変数 (フラグ) を宣言します。

BOOL pageAnimationFinished;

2) 初期値を設定する

- (void)viewDidLoad
{
    [super viewDidLoad];
    ...
    pageAnimationFinished = YES;
}

3) デリゲートとカスタム アクションをパン ジェスチャ レコグナイザーに割り当てる

for (UIGestureRecognizer * gesRecog in self.pageViewController.gestureRecognizers)
{
    if ([gesRecog isKindOfClass:[UIPanGestureRecognizer class]])
    {
        gesRecog.delegate = self;
        [gr addTarget:self action:@selector(handlePan:)];
    }
}

3') ジェスチャの平行移動が水平方向に大きく、指が瞬間的に水平に移動しているときに、アニメーションが実際に開始されます。UIPageViewController
によって割り当てられた内部認識エンジンのアクションでも同じロジックが使用されていると思います。

- (void) handlePan:(UIPanGestureRecognizer *)gestureRecognizer
{
    if (pageAnimationFinished && gestureRecognizer.state == UIGestureRecognizerStateChanged)
    {
        CGPoint vel = [gestureRecognizer velocityInView:self.view];
        CGPoint tr = [gestureRecognizer translationInView:self.view];
        if (ABS(vel.x) > ABS(vel.y) && ABS(tr.x) > ABS(tr.y))
            pageAnimationFinished = NO; // correct place
    }
}

4) アニメーションが終了していない場合のジェスチャーの禁止。

-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && ([gestureRecognizer.view isEqual:self.view] || [gestureRecognizer.view isEqual:self.pageViewController.view]))
    {
        UIPanGestureRecognizer * panGes = (UIPanGestureRecognizer *)gestureRecognizer;
        if(!pageAnimationFinished || (currentPage < minimumPage && [panGes velocityInView:self.view].x < 0) || (currentPage > maximumPage && [panGes velocityInView:self.view].x > 0))
            return NO;
    }
    return YES;
}

5) アニメーションが完成

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
    pageAnimationFinished = YES;
}

私はそれで遊びすぎましたが、これはうまく機能する素晴らしい解決策のようです。

于 2013-05-06T10:03:18.217 に答える
6

デリゲートを使用した QUICK バージョンを次に示します。

このコードを追加します (ヘッダーまたはクラス拡張に UIPageViewControllerDelegate が含まれていることを確認し、 を割り当てますself.pageViewController.delegate = self;):

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers {
   self.pageAnimationFinished = NO;
}

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
    self.pageAnimationFinished = YES;
}

self.pageAnimationFinished== の場合はチェックして nil を返しNOます。

より長い説明:

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed

このデリゲート メソッドを使用しUIPageViewControllerDelegateて、ページをめくったりスワイプしたりするアニメーションがいつ終了するかを知ることができます。これを使用すると、次のように実装できます。

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
    pageAnimationFinished = YES;
}

次に、nilあなたの

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(PageViewController *)viewController

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(PageViewController *)viewController

いつ

pageAnimationFinished == NO. pageAnimationFinishedアニメートするNOときは必ず に設定してください。いつアニメーション化するかを知る最良の方法は、の反対を使用することです

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed

すなわち:

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers

それ以来、その警告は表示されていません。これは、他のソリューションの 1/3 の行で実行できます。そして、従うのははるかに簡単です。

于 2014-04-04T17:20:58.927 に答える
4

Bill Cheswickの回答のSwiftバージョンは次のとおりです(現在、トップの回答):

現在の状態を保持する変数を追加します。

var pageIsAnimating = false

アニメーション状態を設定します。

func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [UIViewController]) {
    self.pageIsAnimating = true
}

func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    if finished || completed {
        self.pageIsAnimating = false
    }
}

現在アニメーション化されている場合は、トランジションをブロックします。

func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
    if self.pageIsAnimating {
        return nil
    }

    // Your code here
}

func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
    if self.pageIsAnimating {
        return nil
    }

    // Your code here
}

ありがとうビル・チェスウィック!

于 2016-05-31T10:06:36.910 に答える
0

UIPageViewControllerDelegate メソッドを利用し、ガードを設定して、過剰なページ ターンが検出されたときに新しいページ ビューが作成されないようにします。

  1. ジェスチャーレコグナイザーを無効にすることができます
  2. UIView で「userInteraction」を無効に設定します
  3. アニメーションが発生しているときにそれ以上の入力を無視するために、UIPageViewController にフラグを維持します。(このオプションに関する警告..ios5 と ios6 では、アニメーションの開始時期を決定する方法が異なります..)
于 2013-01-09T17:53:00.343 に答える
0

viewDidAppear: に追加して機能させる必要がありました

    - (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    self.pageAnimationFinished = YES;
}
于 2013-10-22T15:10:03.760 に答える
-2

移行中はUIPageViewControllersのジェスチャーを無視しようとします。

于 2012-11-06T14:17:51.563 に答える