封装了一个优雅的iOS转场动画
效果图

代码
//
// LBTransition.m
// LBWaterFallLayout_Example
//
// Created by mac on 2024/6/16.
// Copyright © 2024 liuboliu. All rights reserved.
//#import "LBTransition.h"@interface LBPushAnimation:NSObject<UIViewControllerAnimatedTransitioning>@property (nonatomic, weak) id <LBTransitionDelegate> delegate;@end@implementation LBPushAnimation- (instancetype)initWithDelegate:(id <LBTransitionDelegate>) delegate
{if (self = [super init]) {self.delegate = delegate;}return self;
}#pragma mark - UIViewControllerCanimatedtransitioning- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{return 0.25;
}- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{UIView *containerView = [transitionContext containerView];UIViewController *toVC = (UIViewController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];[containerView addSubview:toView];UIViewController <LBTransitionDelegate> *transToVc;if ([toVC conformsToProtocol:@protocol(LBTransitionDelegate)]) {transToVc = (UIViewController <LBTransitionDelegate> *)toVC;}id transmitData = [self.delegate transmitViewData];CGRect finalFrame = [transToVc transmitViewfinalFrameWithData:transmitData containerView:containerView];UIView *transView = [self.delegate prepareTransimitView:containerView finalFrame:finalFrame];toView.alpha = 0;CGFloat scaleWidth = transView.frame.size.width / toView.frame.size.width;CGFloat scaleHeight = transView.frame.size.height / toView.frame.size.height;toView.transform = CGAffineTransformMakeScale(scaleWidth, scaleHeight);toView.center = transView.center;CGRect toViewFinalFrame = [transitionContext finalFrameForViewController:toVC];CGPoint finalCenter = CGPointMake(toViewFinalFrame.origin.x + toViewFinalFrame.size.width * 0.5,toViewFinalFrame.origin.y + toViewFinalFrame.size.height * 0.5);NSTimeInterval duration = [self transitionDuration:transitionContext];[UIView animateWithDuration:durationdelay:0options:UIViewAnimationOptionCurveEaseInOutanimations:^{[transToVc makeupAnimationStateTransmitView:transViewdata:transmitDatacontainerView:containerView];toView.alpha = 1;toView.center = finalCenter;toView.transform = CGAffineTransformIdentity;} completion:^(BOOL finished) {[self.delegate completeTransition];[transToVc completeTransitionWithView:transView data:transmitData];[transitionContext completeTransition:!transitionContext.transitionWasCancelled];}];}@end@interface LBPopAnimatin : NSObject <UIViewControllerAnimatedTransitioning>@property (nonatomic, weak) id <LBTransitionDelegate> delegate;@end@implementation LBPopAnimatin- (instancetype)initWithDelegate:(id <LBTransitionDelegate>)delegate {if (self = [super init]) {self.delegate = delegate;}return self;
}#pragma mark - UIViewControllerAnimatedTransitioning- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{return 0.25;
}- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{UIView *containerView = [transitionContext containerView];UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];UIView *fromView = fromVC.view;[containerView insertSubview:toView aboveSubview:fromView];UIViewController <LBTransitionDelegate> *transToVc;if ([fromVC conformsToProtocol:@protocol(LBTransitionDelegate)]) {transToVc = (UIViewController <LBTransitionDelegate> *)fromVC;}id transmitData = [transToVc transmitViewData];CGRect finalFrame = [self.delegate transmitViewfinalFrameWithData:transmitData containerView:containerView];UIView *transView = [transToVc prepareTransimitView:containerView finalFrame:finalFrame];NSTimeInterval duration = [self transitionDuration:transitionContext];CGPoint finalCenter = CGPointMake(finalFrame.origin.x + finalFrame.size.width * 0.5, finalFrame.origin.y + finalFrame.size.height * 0.5);CGFloat scaleWidth = finalFrame.size.width / fromView.frame.size.width;CGFloat scaleHeight = finalFrame.size.height / fromView.frame.size.height;CGFloat scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale);[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{[self.delegate makeupAnimationStateTransmitView:transView data:transmitDatacontainerView:containerView];fromView.alpha = 0;fromView.center = finalCenter;fromView.transform = transform;} completion:^(BOOL finished) {if (transitionContext.transitionWasCancelled) {[transToVc completeTransitionWithView:transView data:transmitData];} else {[self.delegate completeTransitionWithView:transView data:transmitData];}[transitionContext completeTransition:!transitionContext.transitionWasCancelled];}];
}@end@interface LBTransition () <UIGestureRecognizerDelegate, UIViewControllerTransitioningDelegate>@property (nonatomic, weak) UIViewController <LBTransitionDelegate> *presentVC;
@property (nonatomic, weak) id <UIViewControllerContextTransitioning> transitionContext;
@property (nonatomic, assign) CGPoint startLocation;
@property (nonatomic, assign) CGFloat animationDuration;
@property (nonatomic, strong) UIView *transView;
@property (nonatomic, assign) CGFloat transViewCornerRadius;
@property (nonatomic, strong) id transmidData;
@property (nonatomic, strong) UIView *snapshotView;
@property (nonatomic, assign) CGRect origionFrame;
@property (nonatomic, assign) CGRect transViewFrame;@end@implementation LBTransition- (instancetype)initWithDelegate:(id<LBTransitionDelegate>)delegate
{if (self = [super init]) {self.delegate = delegate;self.origionFrame = CGRectZero;self.transViewFrame = CGRectZero;self.animationDuration = 0.25;}return self;
}#pragma mark - UINaivgationControllerDelegate- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operationfromViewController:(UIViewController *)fromVCtoViewController:(UIViewController *)toVC
{if (operation == UINavigationControllerOperationPush) {return [[LBPushAnimation alloc] initWithDelegate:self.delegate];} else {return [[LBPopAnimatin alloc] initWithDelegate:self.delegate];}
}- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationControllerinteractionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
{if (!self.interacting) {return nil;}return self;
}- (void)wireToViewController:(UIViewController<LBTransitionDelegate> *)viewController
{self.presentVC = viewController;UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];gesture.delegate = self;[viewController.view addGestureRecognizer:gesture];self.gesture = gesture;}- (void)startInteractiveTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{if (self.gesture.state == UIGestureRecognizerStatePossible) {dispatch_async(dispatch_get_main_queue(), ^{[transitionContext completeTransition:NO];});return;}self.transitionContext = transitionContext;UIView *containerView = [transitionContext containerView];UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];UIView *fromView = fromVC.view;[containerView insertSubview:toView belowSubview:fromView];self.transmidData = [self.presentVC transmitViewData];CGRect finalFrame = [self.delegate transmitViewfinalFrameWithData:self.transmidData containerView:containerView];self.transView = [self.presentVC prepareTransimitView:containerView finalFrame:finalFrame];self.transViewCornerRadius = self.transView.layer.cornerRadius;self.snapshotView = [fromView snapshotViewAfterScreenUpdates:NO];[self.snapshotView addSubview:self.transView];self.origionFrame = self.snapshotView.frame;self.transViewFrame = self.transView.frame;[containerView addSubview:self.snapshotView];fromView.alpha = 0;
}- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{return YES;
}
#pragma mark - action- (void)handleGesture:(UIPanGestureRecognizer *)gestureRecognizer
{CGFloat width = gestureRecognizer.view.superview.frame.size.width;CGPoint location = [gestureRecognizer locationInView:gestureRecognizer.view.superview];switch (gestureRecognizer.state) {case UIGestureRecognizerStateBegan:{self.interacting = YES;id transmitData = [self.presentVC transmitViewData];[self.delegate prepareAnimationWithData:transmitData];self.startLocation = location;UINavigationController *navigationController = self.presentVC.navigationController;id <UINavigationControllerDelegate> navigationControllerDelegate = navigationController.delegate;navigationController.delegate = self;[self.presentVC.navigationController popViewControllerAnimated:YES];navigationController.delegate = navigationControllerDelegate;}break;case UIGestureRecognizerStateChanged: {CGPoint trans = CGPointMake(location.x - self.startLocation.x, location.y - self.startLocation.y);CGFloat minScale = 0.3;CGFloat scale = (width - fabs(trans.x))/ width * (1 - minScale) + minScale;CGPoint transViewCenter = CGPointMake(self.transViewFrame.origin.x + self.transViewFrame.size.width * 0.5, self.transViewFrame.origin.y + self.transViewFrame.origin.y + self.transViewFrame.size.height * 0.5);self.snapshotView.frame = CGRectMake(0, 0, self.origionFrame.size.width * scale, self.origionFrame.size.height * scale);self.snapshotView.center = CGPointMake(self.origionFrame.size.width * 0.5 + trans.x, self.origionFrame.size.height * 0.5 + trans.y);transViewCenter.x *= scale;transViewCenter.y *= scale;self.transView.frame = CGRectMake(0, 0, self.transViewFrame.size.width * scale, self.transViewFrame.size.height * scale);self.transView.layer.cornerRadius = self.transViewCornerRadius * scale;self.transView.center = transViewCenter;}break;case UIGestureRecognizerStateCancelled:case UIGestureRecognizerStateEnded:{UIView *containerView = [self.transitionContext containerView];UIView *toView = [self.transitionContext viewForKey:UITransitionContextToViewKey];CGPoint trans = CGPointMake(location.x - self.startLocation.x, location.y - self.startLocation.y);if (fabs(trans.x) < (width * 0.15)) {[UIView animateWithDuration:self.animationDuration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{self.snapshotView.frame = self.origionFrame;self.transView.frame = self.transViewFrame;self.transView.layer.cornerRadius = 12;} completion:^(BOOL finished) {[toView removeFromSuperview];self.presentVC.view.alpha = 1;[self.snapshotView removeFromSuperview];[self.presentVC completeTransitionWithView:self.transView data:self.transmidData];[self.delegate completeTransition];self.interacting = NO;[self cancelInteractiveTransition];[self.transitionContext completeTransition:NO];}];} else {CGRect cFrame = [self.snapshotView convertRect:self.transView.frame toView:containerView];[containerView addSubview:self.transView];self.transView.frame = cFrame;NSTimeInterval duration = self.animationDuration;[UIView animateKeyframesWithDuration:duration delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.1 animations:^{self.snapshotView.alpha = 0;}];[UIView addKeyframeWithRelativeStartTime:0.1 relativeDuration:1 animations:^{[self.delegate makeupAnimationStateTransmitView:self.transViewdata:self.transmidDatacontainerView:containerView];}];} completion:^(BOOL finished) {[self.snapshotView removeFromSuperview];[self.delegate completeTransitionWithView:self.transView data:self.transmidData];self.interacting = NO;[self finishInteractiveTransition];[self.transitionContext completeTransition:YES];}];}break;}default:break;}
}
@end```相关文章:
封装了一个优雅的iOS转场动画
效果图 代码 // // LBTransition.m // LBWaterFallLayout_Example // // Created by mac on 2024/6/16. // Copyright © 2024 liuboliu. All rights reserved. //#import "LBTransition.h"interface LBPushAnimation:NSObject<UIViewControllerAnimated…...
数据中心技术:大数据时代的机遇与挑战
在大数据时代,数据中心网络对于存储和处理大量信息至关重要。随着云计算的出现,数据中心已成为现代技术的支柱,支持社交媒体、金融服务等众多行业。然而,生成和处理的大量数据带来了一些挑战,需要创新的解决方案。在这…...
29、架构-技术方法论之向微服务迈进
治理:理解系统复杂性 微服务架构的引入增加了系统的复杂性,这种复杂性不仅体现在技术层面,还包括组织、管理和运维等各个方面。本节将详细探讨微服务架构的复杂性来源,并介绍一些应对复杂性的治理策略。 1. 什么是治理 治理是指…...
点云处理实操 1. 求解点云法向
目录 一、点云法向的定义 二、如何计算计算法向量 三、实操 四、代码 main.cpp CMakeList.txt 一、点云法向的定义 点云法向量是指点云中某个点的局部表面法向量(Normal Vector)。法向量在三维空间中用来描述表面在该点处的方向属性,它是表面几何特征的重要描述工具。…...
XSS+CSRF组合拳
目录 简介 如何进行实战 进入后台创建一个新用户进行接口分析 构造注入代码 寻找XSS漏洞并注入 小结 简介 (案例中将使用cms靶场来进行演示) 在实战中CSRF利用条件十分苛刻,因为我们需要让受害者点击我们的恶意请求不是一件容易的事情…...
PasteSpiderFile文件同步管理端使用说明(V24.6.21.1)
PasteSpider作为一款适合开发人员的部署管理工具,特意针对开发人员的日常情况做了一个PasteSpiderFile客户端,用于windows上的开发人员迅速的更新发布自己的最新代码到服务器上! 虽然PasteSpider也支持svn/git的源码拉取,自动编译…...
NLP中两种不同的中文分词形式,jieba和spaCy
1. jieba分词 import jiebatext在中国古代文化中,书法和绘画是艺术的重要表现形式。古人常说,‘文字如其人’,通过墨迹可以窥见作者的性情和气质。而画家则以笔墨搏击,表现出山川河流、花鸟虫鱼的灵动。这些艺术形式不仅仅是技艺…...
【数据库】四、数据库编程(SQL编程)
四、数据库编程 另一个大纲: 5.1存储过程 5.1.1存储过程基本概念 5.1.2创建存储过程 5.1.3存储过程体 5.1.4调用存储过程 5.1.5删除 5.2存储函数 5.2.1创建存储函数 5.2.2调用存储函数 5.2.3删除存储函数 目录 文章目录 四、数据库编程1.SQL编程基础1.1常量1.2变…...
17.RedHat认证-Ansible自动化运维(下)
17.RedHat认证-Ansible自动化运维(下) 这个章节讲ansible的变量,包括变量的定义、变量的规则、变量范围、变量优先级、变量练习等。 以及对于tasks的控制,主要有loop循环作业、条件判断等 变量 介绍 Ansible支持变量功能,能将value存储到…...
React Suspense的原理
React Suspense组件的作用是当组件未完成加载时,显示 fallback 组件。那么 Suspense 是如何实现的呢?React 的渲染是通过 Fiber 进行的,Suspense 的更新机制也是要围绕 Fiber 架构进行的。Suspense 是由两部分组成,实际 UI 子组件…...
React的生命周期函数详解
import React,{Component} from "react";import SonApp from ./sonAppclass App extends Component{state{hobby:爱吃很多好吃的}// 是否要更新数据,这里返回true才会更新数据shouldComponentUpdate(nextProps,nextState){console.log("app.js第一步…...
DoubleSummaryStatistics 及其相关类之-简介
1. DoubleSummaryStatistics 使用简介 在Java 8中,DoubleSummaryStatistics 类被引入作为 java.util 包的一部分。它是一个用于收集统计数据(如计数、最小值、最大值、和、平均值等)的类,特别适用于处理 double 类型的数据。 Do…...
java线程间的通信 - join 和 ThreadLocal
你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益: 了解大厂经验拥有和大厂相匹配的技术等 希望看什么,评论或者私信告诉我! 文章目录 一…...
差分GPS原理
双差RTK(Real-Time Kinematic)算法是基于差分全球卫星导航系统(GNSS)技术的一种高精度定位方法。它利用至少两个接收机(一个为基站,其他为移动站)接收自同一组卫星的信号来实现精确测量。双差处…...
【栈与队列】前k个高频元素
题目:给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 分析:首先我们需要计算数组中元素出现的频率,前几篇文章讲解了哈希表的应用,所以这里我们很容易想到用…...
B端产品竞品分析-总结版
B端竞品分析的难点 分析维度-业务逻辑复杂 B端产品与C端产品业务模型不同,B端产品主要以业务为导向,因此其业务流程与业务逻辑梳理起来也会较C端产品复杂的多,对于个人能力也有一定的要求,需要我们具备相关领域或行业专业知识。…...
刷代码随想录有感(116):动态规划——单词拆分
题干: 代码: class Solution { public:bool wordBreak(string s, vector<string>& wordDict) {unordered_set<string>set(wordDict.begin(), wordDict.end());vector<bool>dp(s.size() 1, false);dp[0] true;for(int j 0; j &…...
CSS-0_1 CSS和层叠(样式优先级、内联样式、选择器 用户代理样式)
CSS 的本质就是声明规则 ——《深入解析CSS》 文章目录 CSS层叠和优先级用户代理样式请和用户代理样式和谐相处 选择器单选择器的优先级选择器组的优先级关于选择器的其他源码顺序尽可能的选择优先级低的选择器 内联样式内联样式和JavaScript !important多个 !important 碎碎念…...
科技赋能冷链园区:可视化带来全新体验
应用图扑可视化技术,冷链园区能够更加直观地监控和管理资源,优化运作流程,提高运营效率与服务质量。...
高通安卓12-安卓系统定制2
将开机动画打包到system.img里面 在目录device->qcom下面 有lito和qssi两个文件夹 现在通过QSSI的方式创建开机动画,LITO方式是一样的 首先加入自己的开机动画,制作过程看前面的部分 打开qssi.mk文件,在文件的最后加入内容 PRODUCT_CO…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...
高考志愿填报管理系统---开发介绍
高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…...
统计学(第8版)——统计抽样学习笔记(考试用)
一、统计抽样的核心内容与问题 研究内容 从总体中科学抽取样本的方法利用样本数据推断总体特征(均值、比率、总量)控制抽样误差与非抽样误差 解决的核心问题 在成本约束下,用少量样本准确推断总体特征量化估计结果的可靠性(置…...
新版NANO下载烧录过程
一、序言 搭建 Jetson 系列产品烧录系统的环境需要在电脑主机上安装 Ubuntu 系统。此处使用 18.04 LTS。 二、环境搭建 1、安装库 $ sudo apt-get install qemu-user-static$ sudo apt-get install python 搭建环境的过程需要这个应用库来将某些 NVIDIA 软件组件安装到 Je…...
HTML版英语学习系统
HTML版英语学习系统 这是一个完全免费、无需安装、功能完整的英语学习工具,使用HTML CSS JavaScript实现。 功能 文本朗读练习 - 输入英文文章,系统朗读帮助练习听力和发音,适合跟读练习,模仿学习;实时词典查询 - 双…...
2025年全国I卷数学压轴题解答
第19题第3问: b b b 使得存在 t t t, 对于任意的 x x x, 5 cos x − cos ( 5 x t ) < b 5\cos x-\cos(5xt)<b 5cosx−cos(5xt)<b, 求 b b b 的最小值. 解: b b b 的最小值 b m i n min t max x g ( x , t ) b_{min}\min_{t} \max_{x} g(x,t) bmi…...
盲盒一番赏小程序:引领盲盒新潮流
在盲盒市场日益火爆的今天,如何才能在众多盲盒产品中脱颖而出?盲盒一番赏小程序给出了答案,它以创新的玩法和优质的服务,引领着盲盒新潮流。 一番赏小程序的最大特色在于其独特的赏品分级制度。赏品分为多个等级,从普…...
创客匠人:如何通过创始人IP打造实现知识变现与IP变现的长效增长?
在流量红利逐渐消退的当下,创始人IP的价值愈发凸显。它不仅能够帮助中小企业及个人创业者突破竞争壁垒,还能成为企业品牌影响力的核心资产。然而,市场上IP孵化机构鱼龙混杂,如何选择一家真正具备长期价值的合作伙伴?创…...
