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

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...