当前位置: 首页 > news >正文

封装了一个优雅的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```![请添加图片描述](https://img-blog.csdnimg.cn/direct/c1e3f47c8be74f6d95a9062735b2d36e.gif)

相关文章:

封装了一个优雅的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…...

数据中心技术:大数据时代的机遇与挑战

在大数据时代&#xff0c;数据中心网络对于存储和处理大量信息至关重要。随着云计算的出现&#xff0c;数据中心已成为现代技术的支柱&#xff0c;支持社交媒体、金融服务等众多行业。然而&#xff0c;生成和处理的大量数据带来了一些挑战&#xff0c;需要创新的解决方案。在这…...

29、架构-技术方法论之向微服务迈进

治理&#xff1a;理解系统复杂性 微服务架构的引入增加了系统的复杂性&#xff0c;这种复杂性不仅体现在技术层面&#xff0c;还包括组织、管理和运维等各个方面。本节将详细探讨微服务架构的复杂性来源&#xff0c;并介绍一些应对复杂性的治理策略。 1. 什么是治理 治理是指…...

点云处理实操 1. 求解点云法向

目录 一、点云法向的定义 二、如何计算计算法向量 三、实操 四、代码 main.cpp CMakeList.txt 一、点云法向的定义 点云法向量是指点云中某个点的局部表面法向量(Normal Vector)。法向量在三维空间中用来描述表面在该点处的方向属性,它是表面几何特征的重要描述工具。…...

XSS+CSRF组合拳

目录 简介 如何进行实战 进入后台创建一个新用户进行接口分析 构造注入代码 寻找XSS漏洞并注入 小结 简介 &#xff08;案例中将使用cms靶场来进行演示&#xff09; 在实战中CSRF利用条件十分苛刻&#xff0c;因为我们需要让受害者点击我们的恶意请求不是一件容易的事情…...

PasteSpiderFile文件同步管理端使用说明(V24.6.21.1)

PasteSpider作为一款适合开发人员的部署管理工具&#xff0c;特意针对开发人员的日常情况做了一个PasteSpiderFile客户端&#xff0c;用于windows上的开发人员迅速的更新发布自己的最新代码到服务器上&#xff01; 虽然PasteSpider也支持svn/git的源码拉取&#xff0c;自动编译…...

NLP中两种不同的中文分词形式,jieba和spaCy

1. jieba分词 import jiebatext在中国古代文化中&#xff0c;书法和绘画是艺术的重要表现形式。古人常说&#xff0c;‘文字如其人’&#xff0c;通过墨迹可以窥见作者的性情和气质。而画家则以笔墨搏击&#xff0c;表现出山川河流、花鸟虫鱼的灵动。这些艺术形式不仅仅是技艺…...

【数据库】四、数据库编程(SQL编程)

四、数据库编程 另一个大纲&#xff1a; 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的变量&#xff0c;包括变量的定义、变量的规则、变量范围、变量优先级、变量练习等。 以及对于tasks的控制&#xff0c;主要有loop循环作业、条件判断等 变量 介绍 Ansible支持变量功能&#xff0c;能将value存储到…...

React Suspense的原理

React Suspense组件的作用是当组件未完成加载时&#xff0c;显示 fallback 组件。那么 Suspense 是如何实现的呢&#xff1f;React 的渲染是通过 Fiber 进行的&#xff0c;Suspense 的更新机制也是要围绕 Fiber 架构进行的。Suspense 是由两部分组成&#xff0c;实际 UI 子组件…...

React的生命周期函数详解

import React,{Component} from "react";import SonApp from ./sonAppclass App extends Component{state{hobby:爱吃很多好吃的}// 是否要更新数据&#xff0c;这里返回true才会更新数据shouldComponentUpdate(nextProps,nextState){console.log("app.js第一步…...

DoubleSummaryStatistics 及其相关类之-简介

1. DoubleSummaryStatistics 使用简介 在Java 8中&#xff0c;DoubleSummaryStatistics 类被引入作为 java.util 包的一部分。它是一个用于收集统计数据&#xff08;如计数、最小值、最大值、和、平均值等&#xff09;的类&#xff0c;特别适用于处理 double 类型的数据。 Do…...

java线程间的通信 - join 和 ThreadLocal

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…...

差分GPS原理

双差RTK&#xff08;Real-Time Kinematic&#xff09;算法是基于差分全球卫星导航系统&#xff08;GNSS&#xff09;技术的一种高精度定位方法。它利用至少两个接收机&#xff08;一个为基站&#xff0c;其他为移动站&#xff09;接收自同一组卫星的信号来实现精确测量。双差处…...

【栈与队列】前k个高频元素

题目&#xff1a;给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 分析&#xff1a;首先我们需要计算数组中元素出现的频率&#xff0c;前几篇文章讲解了哈希表的应用&#xff0c;所以这里我们很容易想到用…...

B端产品竞品分析-总结版

B端竞品分析的难点 分析维度-业务逻辑复杂 B端产品与C端产品业务模型不同&#xff0c;B端产品主要以业务为导向&#xff0c;因此其业务流程与业务逻辑梳理起来也会较C端产品复杂的多&#xff0c;对于个人能力也有一定的要求&#xff0c;需要我们具备相关领域或行业专业知识。…...

刷代码随想录有感(116):动态规划——单词拆分

题干&#xff1a; 代码&#xff1a; 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 碎碎念…...

科技赋能冷链园区:可视化带来全新体验

应用图扑可视化技术&#xff0c;冷链园区能够更加直观地监控和管理资源&#xff0c;优化运作流程&#xff0c;提高运营效率与服务质量。...

高通安卓12-安卓系统定制2

将开机动画打包到system.img里面 在目录device->qcom下面 有lito和qssi两个文件夹 现在通过QSSI的方式创建开机动画&#xff0c;LITO方式是一样的 首先加入自己的开机动画&#xff0c;制作过程看前面的部分 打开qssi.mk文件&#xff0c;在文件的最后加入内容 PRODUCT_CO…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...

大数据治理的常见方式

大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法&#xff0c;以下是几种常见的治理方式&#xff1a; 1. 数据质量管理 核心方法&#xff1a; 数据校验&#xff1a;建立数据校验规则&#xff08;格式、范围、一致性等&#xff09;数据清洗&…...

Mysql故障排插与环境优化

前置知识点 最上层是一些客户端和连接服务&#xff0c;包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念&#xff0c;为通过安全认证接入的客户端提供线程。同样在该层上可…...

医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor

1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...

Element-Plus:popconfirm与tooltip一起使用不生效?

你们好&#xff0c;我是金金金。 场景 我正在使用Element-plus组件库当中的el-popconfirm和el-tooltip&#xff0c;产品要求是两个需要结合一起使用&#xff0c;也就是鼠标悬浮上去有提示文字&#xff0c;并且点击之后需要出现气泡确认框 代码 <el-popconfirm title"是…...

Selenium 查找页面元素的方式

Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素&#xff0c;以下是主要的定位方式&#xff1a; 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…...