当前位置: 首页 > 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…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...