UIViewController 转换在使用下拉手势解雇时闪烁
UIViewController transition flickers on dismissal with pull-down gesture
当用户使用自定义转换单击 MKMapView
中的注释时,我将呈现一个视图控制器。过渡动画呈现的视图控制器的框架从注释的框架开始到它的最终全屏外观。
当关闭呈现的视图控制器时,用户有两个选择:她可以单击右上角的关闭按钮,关闭过渡将使视图动画回到注释框架。这部分工作正常。
但用户也可以将视图向下拖动至少 200 点,当她抬起手指时,我希望同样的关闭过渡到 运行,但从 "dragged down" 状态开始。
更详细一点,我呈现的视图控制器的根视图有两个子视图:一个我称之为 contentView
,它包含所有实际内容,并且是一个具有 UIPanGestureRecognizer
在其上定义并根据用户的手势向下移动;我称之为 pullProgressView
的一个位于 contentView
下方,并在用户拖动时保持原位。它显示一个圆圈,该圆圈填满用户已经拖动的更下方,以指示松开手指将关闭视图控制器的位置。
手势识别器的基本部分如下所示:
let progress = sender.translation(in: contentView).y
let screen = UIScreen.main.bounds
if sender.state == .began || sender.state == .changed {
if progress > 0 {
// Dragged down -> allow movement of the view
contentView.center = CGPoint(x: contentView.center.x,
y: screen.size.height / 2 + progress)
}
} else if sender.state == .ended {
if contentView.frame.origin.y > threshold {
// Dragged down far enough to dismiss the view controller
print("contentView frame right before dismissing: \(contentView.frame)")
self.dismissView()
} else {
// Not dragged down far enough, animate the view back
// to its original position
UIView.animate(withDuration: 0.3) {
self.contentView.frame = screen
}
}
}
我调用 dismissView()
时接管的 animateTransition
方法包含以下代码:
let contentView = (transitionContext.viewController(forKey: .from) as! PresentedViewController).contentView!
print("contentView frame going into animateTransition: \(contentView.frame)")
问题是,当我在向下拖动视图控制器后抬起手指将其关闭时,视图 "flickers" 回到其原始的未拖动状态。上述代码片段中的两个 print
语句产生以下输出:
contentView frame right before dismissing: (0.0, 330.0, 375.0, 667.0)
contentView frame going into animateTransition: (0.0, 0.0, 375.0, 667.0)
因此 contentView
的框架不会 "survive" 进入 animateTransition
方法(注意 y
参数)。我可以通过询问 UIPanGestureRecognizer
的进度从 animateTransition
中手动设置它,这有效,但是在 contentView
移回其拖下的框架之前仍然存在难看的闪烁。
有没有人知道如何解决这个问题?或者更好的方法来解决这个问题?我读过 UIPercentDrivenInteractiveTransition
,但它适用于我的情况吗?向下拖动手势不会真正产生任何百分比的实际关闭动画(这会将帧变形回地图注释之一),所以我不知道如何使用 UIPercentDrivenInteractiveTransition
解决问题。
我找到了一个使用视图控制器包含的不同解决方案。基本上,我将一个子视图控制器及其视图作为子视图添加到呈现视图控制器。此外,我将 pullProgressView
添加为子视图控制器视图下方的子视图。
这样我就不必依赖过渡委托,而是可以在完成所有动画后自行处理子视图控制器的关闭。
当用户使用自定义转换单击 MKMapView
中的注释时,我将呈现一个视图控制器。过渡动画呈现的视图控制器的框架从注释的框架开始到它的最终全屏外观。
当关闭呈现的视图控制器时,用户有两个选择:她可以单击右上角的关闭按钮,关闭过渡将使视图动画回到注释框架。这部分工作正常。
但用户也可以将视图向下拖动至少 200 点,当她抬起手指时,我希望同样的关闭过渡到 运行,但从 "dragged down" 状态开始。
更详细一点,我呈现的视图控制器的根视图有两个子视图:一个我称之为 contentView
,它包含所有实际内容,并且是一个具有 UIPanGestureRecognizer
在其上定义并根据用户的手势向下移动;我称之为 pullProgressView
的一个位于 contentView
下方,并在用户拖动时保持原位。它显示一个圆圈,该圆圈填满用户已经拖动的更下方,以指示松开手指将关闭视图控制器的位置。
手势识别器的基本部分如下所示:
let progress = sender.translation(in: contentView).y
let screen = UIScreen.main.bounds
if sender.state == .began || sender.state == .changed {
if progress > 0 {
// Dragged down -> allow movement of the view
contentView.center = CGPoint(x: contentView.center.x,
y: screen.size.height / 2 + progress)
}
} else if sender.state == .ended {
if contentView.frame.origin.y > threshold {
// Dragged down far enough to dismiss the view controller
print("contentView frame right before dismissing: \(contentView.frame)")
self.dismissView()
} else {
// Not dragged down far enough, animate the view back
// to its original position
UIView.animate(withDuration: 0.3) {
self.contentView.frame = screen
}
}
}
我调用 dismissView()
时接管的 animateTransition
方法包含以下代码:
let contentView = (transitionContext.viewController(forKey: .from) as! PresentedViewController).contentView!
print("contentView frame going into animateTransition: \(contentView.frame)")
问题是,当我在向下拖动视图控制器后抬起手指将其关闭时,视图 "flickers" 回到其原始的未拖动状态。上述代码片段中的两个 print
语句产生以下输出:
contentView frame right before dismissing: (0.0, 330.0, 375.0, 667.0)
contentView frame going into animateTransition: (0.0, 0.0, 375.0, 667.0)
因此 contentView
的框架不会 "survive" 进入 animateTransition
方法(注意 y
参数)。我可以通过询问 UIPanGestureRecognizer
的进度从 animateTransition
中手动设置它,这有效,但是在 contentView
移回其拖下的框架之前仍然存在难看的闪烁。
有没有人知道如何解决这个问题?或者更好的方法来解决这个问题?我读过 UIPercentDrivenInteractiveTransition
,但它适用于我的情况吗?向下拖动手势不会真正产生任何百分比的实际关闭动画(这会将帧变形回地图注释之一),所以我不知道如何使用 UIPercentDrivenInteractiveTransition
解决问题。
我找到了一个使用视图控制器包含的不同解决方案。基本上,我将一个子视图控制器及其视图作为子视图添加到呈现视图控制器。此外,我将 pullProgressView
添加为子视图控制器视图下方的子视图。
这样我就不必依赖过渡委托,而是可以在完成所有动画后自行处理子视图控制器的关闭。