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

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

Chrome 浏览器前端与客户端双向通信实战

Chrome 前端&#xff08;即页面 JS / Web UI&#xff09;与客户端&#xff08;C 后端&#xff09;的交互机制&#xff0c;是 Chromium 架构中非常核心的一环。下面我将按常见场景&#xff0c;从通道、流程、技术栈几个角度做一套完整的分析&#xff0c;特别适合你这种在分析和改…...

【C++】纯虚函数类外可以写实现吗?

1. 答案 先说答案&#xff0c;可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...

git: early EOF

macOS报错&#xff1a; Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...