hinge

Dating apps use many different profile transitions, and I find Hinge’s most interesting. When opening the app, a profile’s presented from the bottom-up with a slight spring animation. Disliking/liking a profile will dismiss it the same way it came.

约会应用程序使用许多不同的配置文件转换,我发现Hinge最有趣。 打开应用程序时,会从下至上显示配置文件,并带有轻微的Spring动画。 不喜欢/喜欢个人资料将以相同的方式将其关闭。

Seems complex? Nope! This is nothing more than a push/pop action within a UINavigationController using a custom transition. So let’s get started!

看起来复杂吗? 不! 这只不过是使用自定义过渡的UINavigationController中的push / pop操作。 因此,让我们开始吧!

Source code: https://github.com/micahbenn/HingeTransitions

源代码: https : //github.com/micahbenn/HingeTransitions

入门 (Getting started)

Create a new project, then two UIViewController subclasses called ProfileListViewController and ProfileViewController.

创建一个新项目,然后创建两个名为ProfileListViewController和ProfileViewController的UIViewController子类。

In our SceneDelegate’s scene(_:willConnectTo:options:), make a navigation controller and initialize it with ProfileListViewController as the rootViewController. Then make a window, and set its rootViewController to be the navigation controller.

在SceneDelegate的scene(_:willConnectTo:options:),制作一个导航控制器,并以ProfileListViewController作为rootViewController对其进行初始化。 然后创建一个窗口,并将其rootViewController设置为导航控制器。

SceneDelegate.swift
SceneDelegate.swift

ProfileListViewController (ProfileListViewController)

This class will be responsible for loading/presenting profiles, and showing any intermittent loading animations. Let’s create a protocol we can conform to, so ProfileViewController can let us know when we need to show the next profile:

此类将负责加载/呈现配置文件,并显示任何间歇性加载动画。 让我们创建一个我们可以遵循的协议,以便ProfileViewController可以让我们知道何时需要显示下一个配置文件:

protocol ProfileListDelegate: class {    func showNextProfile()}

Make ProfileListViewController conform to this protocol, which has to be class-bound so classes can keep a weak reference to it. For this example, we want to simulate profiles. Declare an array of strings in ProfileListViewController:

使ProfileListViewController符合此协议,该协议必须是类绑定的,以便类可以对其进行弱引用。 对于此示例,我们要模拟配置文件。 在ProfileListViewController中声明一个字符串数组:

var profiles: [String] = ["Apple", "Microsoft", "Google"]

Create a button with the title “Show Profile”, add an action that calls showNextProfile, and add it to the view.

创建一个标题为“ Show Profile”的按钮,添加一个调用showNextProfile的操作,并将其添加到视图中。

Note: remember to expose showNextProfile to objc

注意:记得将showNextProfile公开给objc

In showNextProfile, we need to:

showNextProfile ,我们需要:

  1. Check if there’re any more profiles to show. If so, remove the first profile from profiles. Else, don’t do anything.

    检查是否还有其他个人资料要显示。 如果是这样,请从profiles资料中删除第一个个人profiles 。 否则,什么也不要做。

  2. Create the ProfileViewController using that profile使用该配置文件创建ProfileViewController
  3. Enable/disable the “Show Profile” button启用/禁用“显示个人资料”按钮

If we were downloading profiles, we could have this method show a neat loading animation on this view like Hinge does!

如果要下载配置文件,则可以像Hinge一样,使该方法在此视图上显示整洁的加载动画!

@objc func showNextProfile() {  guard !profiles.isEmpty else { return }  let profile = profiles.removeFirst()  let vc = ProfileViewController(title: profile, delegate: self)  navigationController?.pushViewController(vc, animated: true)  button.isEnabled = !profiles.isEmpty}

Expect to get an error with the initializer for ProfileViewController; we’ll implement that in the next section.

可能会出现ProfileViewController的初始化程序错误; 我们将在下一节中实现。

ProfileViewController (ProfileViewController)

This class will be responsible for displaying a given profile, and notifying the ProfileListDelegate that it can show the next profile. In ProfileViewController, declare a weak delegate of type ProfileListDelegate:

此类将负责显示给定的配置文件,并通知ProfileListDelegate它可以显示下一个配置文件。 在ProfileViewController中,声明ProfileListDelegate类型的弱委托:

weak var delegate: ProfileListDelegate?

Make a label to show the current profile name, and a button to load the next profile that calls dismissAndShowNextProfile. Then create the initializer:

创建一个标签以显示当前配置文件名称,并单击一个按钮以加载下一个调用dismissAndShowNextProfile的配置文件。 然后创建初始化程序:

init(title: String, delegate: ProfileListDelegate) {  super.init(nibName: nil, bundle: nil)  label.text = title  self.delegate = delegate}

In the method dismissAndShowNextProfile, we need to pop the view controller from the navigation stack, and on completion, tell the delegate that we’re ready to show the next profile:

在方法dismissAndShowNextProfile中 ,我们需要从导航堆栈中弹出视图控制器,完成后,告诉委托我们已经准备好显示下一个配置文件:

@objc func dismissAndShowNextProfile() {  CATransaction.begin()  CATransaction.setCompletionBlock { [weak self] in    self?.delegate?.showNextProfile()  }  navigationController?.popViewController(animated: true)  CATransaction.commit()}

到目前为止我们所拥有的... (What we have so far…)

If you build and run, pressing “Show Profile” and “Next” on their respective view controllers should push/pop each with the standard boring animations. Let’s change this with UIViewControllerAnimatedTransitioning!

如果您生成并运行,请在其各自的视图控制器上按“显示配置文件”和“下一步”,以标准的无聊动画分别推送/弹出。 让我们用UIViewControllerAnimatedTransitioning改变它!

铰链过渡 (HingeTransition)

UIViewControllerAnimatedTransitioning allows us to define the animations and duration for a transition. Go ahead and create a subclass of NSObject called HingeTransition implementing the UIViewControllerAnimatedTransitioning protocol (this requires the class to conform to NSObjectProtocol, hence the NSObject subclass).

UIViewControllerAnimatedTransitioning允许我们定义过渡的动画和持续时间。 继续,创建一个名为HingeTransition的NSObject子类,该子类实现UIViewControllerAnimatedTransitioning协议(这要求该类符合NSObjectProtocol,因此要符合NSObject子类)。

Because we need to know what navigation operation is taking place (e.g., push, pop), create an initializer that takes a parameter of type UINavigationController.Operation that assigns it to one of its properties you’ll need to create:

因为我们需要知道正在进行的导航操作(例如,推,弹出),所以创建一个带有UINavigationController.Operation类型的参数的初始化程序,将其分配给您需要创建的属性之一:

init(operation: UINavigationController.Operation) {  self.operation = operation  super.init()}

Implement the method transitionDuration(using:) and return a time interval (I found 0.8 to be fast enough), and animateTransition(using:). The logic for the latter method is pretty simple:

实现方法transitionDuration(using:)并返回一个时间间隔(我发现0.8足够快)和animateTransition(using:) 。 后一种方法的逻辑非常简单:

  1. Determine the operation确定操作
  2. Add the to/from views to an intermediate view将“到/从”视图添加到中间视图
  3. Animate the frame of the view that’s transitioning对正在过渡的视图的框架进行动画处理

If we’re presenting, the operation will be .push:

如果我们正在演示,则操作将为.push:

let isPresenting = operation == .push

transitionContext provides us the information we need about the transition, including the to and from views. So grab those:

transitionContext 提供给我们的信息 ,我们需要过渡一下,包括往返的意见。 因此,抓住那些:

guard let toView = transitionContext.view(forKey: .to) else {   return }guard let fromView = transitionContext.view(forKey: .from) else {   return}

Next, we want to add these views to the containerView, which acts as an intermediate view of sorts where you can animate these views’ frames:

接下来,我们要将这些视图添加到containerView ,它充当各种中间视图,您可以在其中为这些视图的帧设置动画:

  1. If we’re presenting, we want to add the toView to the containerView

    如果要演示, toViewtoView添加到containerView

  2. When dismissing, we want to add the toView behind the view we’re on, fromView

    关闭时,我们想将toView添加到我们toView的视图的后面fromView

if (isPresenting) {  transitionContext.containerView.addSubview(toView)} else {  transitionContext.containerView.insertSubview(toView, belowSubview: fromView)}

Let’s animate now! But first, setup two frames:

现在开始动画! 但首先,设置两个框架:

  1. The visible frame, which represents the presented frame可见框架,代表呈现的框架
  2. The frame off-screen, which represents the dismissed frame屏幕外的帧,表示已解散的帧
let presentedFrame = transitionContext.containerView.framevar dismissedFrame = presentedFramedismissedFrame.origin.y = transitionContext.containerView.frame.height

We need to decide which of these will be the start and end frames according to whether or not we’re presenting:

我们需要根据我们是否要呈现的内容来决定将这些帧作为开始和结束帧:

  1. For the start frame: if we’re presenting, we want the view to start off-screen. Else, it needs to be the entire visible frame since we’re viewing it.对于开始帧:如果正在演示,我们希望视图在屏幕外开始。 否则,它必须是整个可见框架,因为我们正在查看它。
  2. For the end frame: if we’re presenting, we want the view to end up in the entire visible frame. Else, it needs to end off-screen.对于结束帧:如果要演示,则希望视图最终出现在整个可见帧中。 否则,它需要在屏幕外结束。
let startFrame = isPresenting ? dismissedFrame : presentedFramelet endFrame = isPresenting ? presentedFrame : dismissedFrame

Which view should we animate? Well, if we’re presenting, we want to animate the view we need to see, toView. When we’re dismissing, we want to animate the view that we’re looking at, fromView.

我们应该为哪个视图设置动画? 好吧,如果我们要演示的话,我们想动画化我们需要看到的视图toView 。 解雇时,我们希望为正在查看的视图fromView设置动画。

let transitioningView = isPresenting ? toView : fromView

Now we can adjust the frames using a spring animation, and when it completes, remove the transitioning view from the superview, and notify the transitionContext that we’re done:

现在,我们可以使用弹簧动画来调整帧,并在完成时从超级视图中删除过渡视图,并通知transitionContext我们已经完成:

transitioningView.frame = startFrameUIView.animate(withDuration: transitionDuration(using:  transitionContext),  delay: 0,  usingSpringWithDamping: 0.8,  initialSpringVelocity: 0.7,  options: .curveEaseOut,  animations: {  transitioningView.frame = endFrame}) { _ in  if (!isPresenting) {    transitioningView.removeFromSuperview()  }  transitionContext.completeTransition(true)}

Note: for the sake of this tutorial, we’re using this animation block. However, Apple discourages the use of these blocks, and instead recommends the UIViewPropertyAnimator class.

注意:在本教程中,我们使用的是动画块。 但是,Apple不鼓励使用这些块,而是建议使用UIViewPropertyAnimator类。

实施过渡 (Implementing this transition)

We’re almost done! Hop back into ProfileListViewController. Conform it to UINavigationControllerDelegate, set the navigationController delegate to be the class itself, and implement the function navigationController(_:animationControllerFor:from:to:) that returns the HingeTransition object:

我们快完成了! 跳回ProfileListViewController。 使其符合UINavigationControllerDelegate,将navigationController委托设置为该类本身,并实现返回HingeTransition对象的函数navigationController(_:animationControllerFor:from:to:)

return HingeTransition(operation: operation)

Voila! You’re done. You now have a navigation controller with Hinge-like profile push/pop transitions.

hinge_在Swift中在iOS上重新创建Hinge的配置文件过渡相关推荐

  1. 在 iOS 上开始创建你的虚拟现实应用

    原文链接 : Getting Started | Cardboard | Google Sevelopers 以前 Cradboard 也是支持在 iOS 上使用的,依靠 Unity 来实现,所以你需 ...

  2. 【Swift】在iOS上进行在线翻译

    环境 本文以百度翻译的接口为例,你可以在申请你的翻译API(免费) 上代码 首先导入网络库 import Alamofire 然后参考教程 func 发送翻译请求(你的APPID:String,你的密 ...

  3. 如何在Swift中创建漂亮的iOS图表

    通过图形和图表呈现数据是当今移动应用程序最显着的特征之一.iOS图表使应用程序看起来更漂亮,更有吸引力. 在本教程中,我们将向您展示如何使用代码示例在Swift中实现我们的iOS图表.我们将看一下Sw ...

  4. 微信sdk swift版_使用Swift 4的iOS版Google Maps SDK终极指南

    微信sdk swift版 by Dejan Atanasov 通过Dejan Atanasov 使用Swift 4的iOS版Google Maps SDK终极指南 (Your ultimate gui ...

  5. extjs chart无法在panel中显示_HighChart教程:Swift中的Highcharts iOS库

    以下文章总结了如何在Swift中使用Highcharts iOS库. 我们将对2016/2017赛季四支顶级冠军联赛球队的统计数据进行可视化. A.如何创建Highcharts项目 入门 在Xcode ...

  6. 转 如何在IOS设备中去掉屏幕上的status bar

    引入 如何在IOS设备中去掉屏幕上的status bar,即:不显示设备上方的[网络.时间.电池??]条? 操作 方法一: 在-info.list项目文件中,加上"Status bar is ...

  7. vue中解决时间在ios上显示NAN的问题

    vue中解决时间在ios上显示NAN的问题 参考文章: (1)vue中解决时间在ios上显示NAN的问题 (2)https://www.cnblogs.com/wzs5800/p/9580785.ht ...

  8. ios系统微信浏览器、safari浏览器中h5页面上拉下滑导致悬浮层脱离窗口的解决方法

    ios系统微信浏览器.safari浏览器中h5页面上拉下滑导致悬浮层脱离窗口的解决方法 参考文章: (1)ios系统微信浏览器.safari浏览器中h5页面上拉下滑导致悬浮层脱离窗口的解决方法 (2) ...

  9. iOS - 选取相册中iCloud云上图片和视频的处理

    关于iOS选取相册中iCloud云上图片和视频 推荐看: TZImagePickerController的源码,这个是一个非常靠谱的相册选择图片视频的库 .当然也可以自己写 如下遇到的问题 工作原因, ...

最新文章

  1. SimpleDateFormat的线程安全问题
  2. Linux_LAMP 最强大的动态网站解决方案
  3. QEMU虚拟网卡设备的创建流程
  4. python什么时候用框架_python时间模块的使用
  5. gdb 跟踪调试命令整理
  6. 学习WPF——使用Font-Awesome图标字体
  7. 获取当前周一日期_Excel工作表中最全的时间和日期函数,效率、办公必备
  8. linux 项目内存吃掉,Linux内存被吃掉了,它去哪里了?
  9. 在Redis中设置了过期时间的Key注意事项
  10. oracle官方文档下载使用
  11. MyBatis下载和环境搭建
  12. 分享一个千万数据的磁力搜索网站 bt书虫 php+mysql+nginx
  13. 找到某个关键字 同义词词林 python_python-004-标识符
  14. linux-mount-iso
  15. Pointnet++中tf_ops三个.so文件的生成
  16. 给在读研究生的一封信
  17. 三星“掌门人”李在镕身在看守所 但仍“遥控”三星
  18. 使用Selenium爬取网站表格类数据
  19. 【C++】多线程同步
  20. 计算机硬件英语文章带翻译,适合孩子阅读的英语小短文(带翻译)

热门文章

  1. redis集群搭建及管理命令
  2. 拼多多资深程序员带你了解 ”砍一刀“的设计与实现
  3. WPF基础之XAML----(XAML 根元素和 xmlns,事件和 XAML 代码隐藏)
  4. WIN XP SP2系统经常性死机问题解决历程
  5. Python的基本数据类型
  6. Python实现基于动态时间规整的股市交易策略测试
  7. Autocad毕业设计CAD机械练习图开始发放啦!
  8. 每日一练-1-CAD
  9. 试题 历届真题 机器人行走(C语言实现)
  10. 各国海关单证有哪些要求?