iOS - Swift : 在UITableView中展开用户头像
iOS - Swift : Expand user profile picture in UITableView
我正在尝试从 UITableViewCell
获取动画(保存有关用户的信息,带有个人资料图片),方法是扩展用户的个人资料图片:
///////////////
对此
//////////////
在此处输入代码
它有效,但问题是动画以某种方式从屏幕的角落开始,而不是从 UITableViewCell
中的圆形图像开始。
func handlePictureTap(conversationTableCell: ConversationTableCell) {
guard let cellIndexPath = self.conversationsTableView.indexPath(for: conversationTableCell) else { return }
transitionDelegate.openingFrame = self.frameForCellAtIndexPath(cellIndexPath)
let userProfileViewController = UserViewController(nibName: "UserViewController", bundle: nil)
userProfileViewController.recentProfileProtocol = self
userProfileViewController.transitioningDelegate = transitionDelegate
userProfileViewController.modalPresentationStyle = .overCurrentContext
userProfileViewController.userProfileName = conversationTableCell.conversationName.text!
userProfileViewController.userProfileImage = conversationTableCell.conversationPicture.image
self.present(navEditorViewController, animated: true, completion: nil)
}
以及 frameForCellAtIndexPath 的函数。
func frameForCellAtIndexPath(_ indexPath: IndexPath) -> CGRect {
let cell = self.conversationsTableView.cellForRow(at: indexPath) as! ConversationTableCell
let profileImageFrame = cell.conversationPicture.frame
return profileImageFrame
}
我无法为它获取与整个屏幕相关的正确帧,以便我的动画从单元格的个人资料图片开始。
欢迎提出任何建议
您正在从相对于 table 视图单元格坐标系的图像帧开始动画,它位于左上角。
要确定单元格相对于 table 视图的当前位置,您可以使用如下内容:
let rect = tableView.rectForRow(at: indexPath)
如果您需要相对于另一个视图的矩形,您可以使用 UIViews
convert(_ rect: NSRect, from view: NSView?) -> NSRect
更新
假设您需要屏幕坐标中的 openingRect,要将其应用于您的特定情况,您可以执行类似以下操作:
let cellOrigin = tableView.rectForRow(at: indexPath).origin
let rectRelativeToTable = CGRect(x: imageFrame.origin.x + cellOrigin.x,
y: imageFrame.origin.y + cellOrigin.y,
width: imageFrame.size.width,
height: imageFrame.size.height)
let openingRect = tableView.convert(rectRelativeToTable, to: nil)
以防万一其他人正在寻找相同的动画,这里是过渡 类:
DismissalAnimator
import UIKit
class DismissalAnimator: NSObject, UIViewControllerAnimatedTransitioning {
var openingFrame: CGRect?
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.6
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
let containerView = transitionContext.containerView
let animationDuration = self .transitionDuration(using: transitionContext)
let snapshotView = fromViewController.view.snapshotView(afterScreenUpdates: true)
containerView.addSubview(snapshotView!)
fromViewController.view.alpha = 0.0
UIView.animate(
withDuration: animationDuration,
animations: { () -> Void in
snapshotView!.frame = self.openingFrame!
snapshotView!.alpha = 0.0
},
completion: { (finished) -> Void in
snapshotView!.removeFromSuperview()
fromViewController.view.removeFromSuperview()
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
}
}
PresentationAnimator
import UIKit
class PresentationAnimator: NSObject, UIViewControllerAnimatedTransitioning {
var openingFrame: CGRect?
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.6
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
let containerView = transitionContext.containerView
let animationDuration = self.transitionDuration(using: transitionContext)
containerView.addSubview(toViewController.view)
let snapshotView = toViewController.view.snapshotView(afterScreenUpdates: true)
snapshotView!.frame = openingFrame!
toViewController.view.alpha = 0.0
snapshotView!.alpha = 0
containerView.addSubview(snapshotView!)
UIView.animate(
withDuration: animationDuration,
delay: 0.0,
usingSpringWithDamping: 2.0,
initialSpringVelocity: 5.0,
options: UIViewAnimationOptions.curveEaseOut,
animations: { () -> Void in
snapshotView!.frame = fromViewController.view.frame
snapshotView!.alpha = 1
},
completion: { (finished) -> Void in
snapshotView!.removeFromSuperview()
toViewController.view.alpha = 1.0
transitionContext.completeTransition(finished)
})
}
}
过渡委托
import UIKit
class TransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
var openingFrame: CGRect?
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
let presentationAnimator = PresentationAnimator()
presentationAnimator.openingFrame = openingFrame
return presentationAnimator
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
let dismissAnimator = DismissalAnimator()
dismissAnimator.openingFrame = openingFrame!
return dismissAnimator
}
}
- @Stephan Schlecht 提供的上述代码将为您提供相同的动画。
我正在尝试从 UITableViewCell
获取动画(保存有关用户的信息,带有个人资料图片),方法是扩展用户的个人资料图片:
///////////////
对此
//////////////
它有效,但问题是动画以某种方式从屏幕的角落开始,而不是从 UITableViewCell
中的圆形图像开始。
func handlePictureTap(conversationTableCell: ConversationTableCell) {
guard let cellIndexPath = self.conversationsTableView.indexPath(for: conversationTableCell) else { return }
transitionDelegate.openingFrame = self.frameForCellAtIndexPath(cellIndexPath)
let userProfileViewController = UserViewController(nibName: "UserViewController", bundle: nil)
userProfileViewController.recentProfileProtocol = self
userProfileViewController.transitioningDelegate = transitionDelegate
userProfileViewController.modalPresentationStyle = .overCurrentContext
userProfileViewController.userProfileName = conversationTableCell.conversationName.text!
userProfileViewController.userProfileImage = conversationTableCell.conversationPicture.image
self.present(navEditorViewController, animated: true, completion: nil)
}
以及 frameForCellAtIndexPath 的函数。
func frameForCellAtIndexPath(_ indexPath: IndexPath) -> CGRect {
let cell = self.conversationsTableView.cellForRow(at: indexPath) as! ConversationTableCell
let profileImageFrame = cell.conversationPicture.frame
return profileImageFrame
}
我无法为它获取与整个屏幕相关的正确帧,以便我的动画从单元格的个人资料图片开始。
欢迎提出任何建议
您正在从相对于 table 视图单元格坐标系的图像帧开始动画,它位于左上角。
要确定单元格相对于 table 视图的当前位置,您可以使用如下内容:
let rect = tableView.rectForRow(at: indexPath)
如果您需要相对于另一个视图的矩形,您可以使用 UIViews
convert(_ rect: NSRect, from view: NSView?) -> NSRect
更新
假设您需要屏幕坐标中的 openingRect,要将其应用于您的特定情况,您可以执行类似以下操作:
let cellOrigin = tableView.rectForRow(at: indexPath).origin
let rectRelativeToTable = CGRect(x: imageFrame.origin.x + cellOrigin.x,
y: imageFrame.origin.y + cellOrigin.y,
width: imageFrame.size.width,
height: imageFrame.size.height)
let openingRect = tableView.convert(rectRelativeToTable, to: nil)
以防万一其他人正在寻找相同的动画,这里是过渡 类:
DismissalAnimator
import UIKit
class DismissalAnimator: NSObject, UIViewControllerAnimatedTransitioning {
var openingFrame: CGRect?
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.6
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
let containerView = transitionContext.containerView
let animationDuration = self .transitionDuration(using: transitionContext)
let snapshotView = fromViewController.view.snapshotView(afterScreenUpdates: true)
containerView.addSubview(snapshotView!)
fromViewController.view.alpha = 0.0
UIView.animate(
withDuration: animationDuration,
animations: { () -> Void in
snapshotView!.frame = self.openingFrame!
snapshotView!.alpha = 0.0
},
completion: { (finished) -> Void in
snapshotView!.removeFromSuperview()
fromViewController.view.removeFromSuperview()
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
}
}
PresentationAnimator
import UIKit
class PresentationAnimator: NSObject, UIViewControllerAnimatedTransitioning {
var openingFrame: CGRect?
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.6
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
let containerView = transitionContext.containerView
let animationDuration = self.transitionDuration(using: transitionContext)
containerView.addSubview(toViewController.view)
let snapshotView = toViewController.view.snapshotView(afterScreenUpdates: true)
snapshotView!.frame = openingFrame!
toViewController.view.alpha = 0.0
snapshotView!.alpha = 0
containerView.addSubview(snapshotView!)
UIView.animate(
withDuration: animationDuration,
delay: 0.0,
usingSpringWithDamping: 2.0,
initialSpringVelocity: 5.0,
options: UIViewAnimationOptions.curveEaseOut,
animations: { () -> Void in
snapshotView!.frame = fromViewController.view.frame
snapshotView!.alpha = 1
},
completion: { (finished) -> Void in
snapshotView!.removeFromSuperview()
toViewController.view.alpha = 1.0
transitionContext.completeTransition(finished)
})
}
}
过渡委托
import UIKit
class TransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
var openingFrame: CGRect?
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
let presentationAnimator = PresentationAnimator()
presentationAnimator.openingFrame = openingFrame
return presentationAnimator
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
let dismissAnimator = DismissalAnimator()
dismissAnimator.openingFrame = openingFrame!
return dismissAnimator
}
}
- @Stephan Schlecht 提供的上述代码将为您提供相同的动画。