iOS制作带弹跳动画发布界面
发布时间 - 2026-01-11 02:43:01 点击率:次项目中经常会用到带弹跳动画发布界面,具体内容如下

效果图:
代码:
// PublishView.m
// UIImage+ImageEffects.h 苹果蒙化图片的分类 pop.h弹跳动画框架 EJExtension.h模型转换框架
// ComposeModel 用于设置按钮文字与图片的模型,在本地设置plist文件保存image(按钮图片)和text(按钮文字)
#import "PublishView.h"
#import "BSVerticalButton.h"
#import "UIImage+ImageEffects.h"
#import "pop.h"
#import "MJExtension.h"
#import "ComposeModel.h"
@interface PublishView ()
/** 取消按钮 */
@property (nonatomic, weak) UIButton *cancelButton;
@end
@implementation PublishView
/** 全局 window_ */
static UIWindow *window_;
/** 显示发布view */
+ (void)show{
// 添加一个独立的window是为了隔离点击事件
window_ = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
window_.hidden = NO;
PublishView *publish = [[PublishView alloc]init];
publish.frame = window_.bounds;
[window_ addSubview:publish];
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UIImageView *imageView = [[UIImageView alloc]initWithImage:[self getEffectImage]];
[self addSubview:imageView];
[self setupUI];
}
return self;
}
- (void)setupUI{
//这里用自定义的 window 是为了隔绝点击事件 不让点击事件传到后面控制器的view上去
// 按钮弹跳动画时让view本身不能点击
self.userInteractionEnabled = NO;
// 从plis文件获得一个模型数组
NSArray *buttonModelArray = [ComposeModel mj_objectArrayWithFilename:@"buttonImage.plist"];
CGFloat button_w = 72;
CGFloat button_h = button_w + 30;
NSInteger maxLoc = 3; //最多列数
//按钮弹跳动画停止后的起始 y 值
CGFloat buttonEnd_y = ([[UIScreen mainScreen] bounds].size.height - button_h * 2) / 2;
//最开始在屏幕外上方的的起始 y 值
CGFloat buttonBegin_y = buttonEnd_y - [[UIScreen mainScreen] bounds].size.height;
//按钮的起始间隙值
CGFloat buttonStartMargin = 20;
//中间的一个按钮相对于两边按钮的间隙
CGFloat buttonMargin = ([[UIScreen mainScreen] bounds].size.width - buttonStartMargin * 2 - button_w * maxLoc) / (maxLoc - 1);
for (NSInteger i = 0; i < buttonModelArray.count; ++i) {
// BSVerticalButton 自定义的垂直排布按钮
BSVerticalButton *button = [[BSVerticalButton alloc]init];
button.tag = i;
[self addSubview:button];
[button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
ComposeModel *composeModel = buttonModelArray[i];
[button setImage:[UIImage imageNamed:composeModel.image] forState:UIControlStateNormal];
[button setTitle:composeModel.text forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:14];
NSInteger loc = i % maxLoc; //例号
NSInteger row = i / maxLoc; //行号
CGFloat button_x = buttonStartMargin + loc * (button_w + buttonMargin);
CGFloat buttonBginAnimation_y = buttonBegin_y + (button_h * row); //弹跳前的 y 值
CGFloat buttonEndAnimation_y = buttonEnd_y + (button_h * row); //弹跳后的 y 值
//创建pop弹簧动画对象
POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
animation.beginTime = CACurrentMediaTime() + i * 0.1; //动画开始时间
animation.springBounciness = 10; //弹簧增强 0-20
animation.springSpeed = 8; //弹簧速度 0-20
animation.fromValue = [NSValue valueWithCGRect:CGRectMake(button_x, buttonBginAnimation_y, button_w, button_h)];
animation.toValue = [NSValue valueWithCGRect:CGRectMake(button_x, buttonEndAnimation_y, button_w, button_h)];
//中间的按钮添加动画
[button pop_addAnimation:animation forKey:nil];
}
// 添加品牌logo
UIImageView *topImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"compose_slogan"]];
topImageView.center = CGPointMake([[UIScreen mainScreen] bounds].size.width * 0.5, [[UIScreen mainScreen] bounds].size.height * 0.2 - [[UIScreen mainScreen] bounds].size.height);
[self addSubview:topImageView];
// POPBasicAnimation 基本的动画
// POPSpringAnimation 弹簧动画
// POPDecayAnimation 减速动画
// POPCustomAnimation 自定义动画
//创建pop弹簧动画对象
POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
animation.beginTime = CACurrentMediaTime() + buttonModelArray.count * 0.001; //动画开始时间
animation.springBounciness = 10; //弹簧增强 0-20
animation.springSpeed = 10; //弹簧速度 0-20
CGFloat center_x = [[UIScreen mainScreen] bounds].size.width * 0.5;
CGFloat endCenter_y = [[UIScreen mainScreen] bounds].size.height * 0.2;
CGFloat beginCenter_y = endCenter_y - [[UIScreen mainScreen] bounds].size.height;
animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(center_x, beginCenter_y)];
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(center_x, endCenter_y)];
animation.completionBlock = ^(POPAnimation *anim, BOOL finished){
NSLog(@"-------这里可以写动画结束后所要执行的代码...");
// view本身开启交互
self.userInteractionEnabled = YES;
};
//给顶部的图片添加动画
[topImageView pop_addAnimation:animation forKey:nil];
// 底部取消按钮
UIButton *cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
[cancelButton setTitle:@"取 消" forState:UIControlStateNormal];
cancelButton.titleLabel.font = [UIFont systemFontOfSize:15];
[cancelButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[cancelButton setBackgroundColor:[UIColor whiteColor]];
[cancelButton addTarget:self action:@selector(cancelButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:cancelButton];
self.cancelButton = cancelButton;
}
- (void)cancelButtonClick:(UIButton *)button{
// 退出时执行动画 方法的参数block传空
[self animationWithBlock:nil];
}
- (void)layoutSubviews{
[super layoutSubviews];
// 取消按钮位置大小
CGPoint center = self.cancelButton.center;
center.x = self.center.x;
self.cancelButton.center = center;
CGRect frame = self.cancelButton.frame;
frame.origin.y = self.frame.size.height * 0.85;
frame.size = CGSizeMake(200, 35);
self.cancelButton.frame = frame;
}
- (void)buttonClick:(UIButton *)button{
[self animationWithBlock:^{
switch (button.tag) {
case 0:
NSLog(@"发视频");
break;
case 1:
NSLog(@"发图片");
break;
case 2:{
NSLog(@"发段子");
}
break;
case 3:
NSLog(@"发声音");
break;
case 4:
NSLog(@"审贴子");
break;
case 5:
NSLog(@"离线下载");
break;
default:
break;
}
}];
}
/** 退出时与点出了某个按钮时执行的弹跳动画后销毁 window_ 移除 这个蒙板 view ,如果block参数completionBlock有值先销毁window_后再执行这个block里的代码块 */
- (void)animationWithBlock:(void (^) ())completionBlock{
NSLog(@"----%@\n",self.subviews);
//退出的时候这里用自定义的 window 是为了隔绝点击事件 不让点击事件传到后面控制器的view上去
// view本身不能点
self.userInteractionEnabled = NO;
// 选移除取消按钮
[self.cancelButton removeFromSuperview];
for (NSInteger i = 1; i < self.subviews.count; ++i) {
UIView *view = self.subviews[i];
//创建pop基本动画对象
POPBasicAnimation *animation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
// POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
animation.beginTime = CACurrentMediaTime() + (i-1) * 0.1; //动画开始时间
// 如果用这个基类 POPBasicAnimation 动画的执行节奏(一开始很慢, 后面很快)
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
CGPoint center = view.center; //取出中心点
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(center.x , center.y + [[UIScreen mainScreen] bounds].size.height)];
if (i == self.subviews.count-1) { //说明是最后一个 view在做动画,就让执行结束的 block
// 动画结束时调用的 block
animation.completionBlock = ^(POPAnimation *anim, BOOL finished){
NSLog(@"取消时 这里可以写动画结束后所要执行的代码...");
[self removeFromSuperview];
window_ = nil; //销毁自定义的 window
!completionBlock ? : completionBlock();
};
}
//给顶部的图片添加动画
[view pop_addAnimation:animation forKey:nil];
}
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self animationWithBlock:nil];
}
// 获得一个磨纱蒙板 image 图片
- (UIImage *)getEffectImage{
UIWindow *window = [UIApplication sharedApplication].keyWindow; //获取当前 window
UIGraphicsBeginImageContext(window.size); //开启window大小的图形上下文
CGContextRef ref = UIGraphicsGetCurrentContext(); //开启图形上下文
[window.layer renderInContext:ref]; //把window图层 渲染到图形上下文当中
UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); //获取图片
UIGraphicsEndImageContext(); //关闭图形上下文
image = [image applyLightEffect]; //调用 image 分类方法 使图片调成蒙板状态
return image;
}
@end
项目中用到的垂直布局自定义按钮 BSVerticalButton
#import "BSVerticalButton.h"
@implementation BSVerticalButton
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setupUI];
}
return self;
}
- (void)awakeFromNib{
[super awakeFromNib];
[self setupUI];
}
- (void)setupUI{
self.titleLabel.textAlignment = NSTextAlignmentCenter;
}
- (void)layoutSubviews{
[super layoutSubviews];
//按钮内部图片 frame
CGRect imageViewFrame = self.imageView.frame;
imageViewFrame.origin.x = 0;
imageViewFrame.origin.y = 0;
imageViewFrame.size.width = self.bounds.size.width;
imageViewFrame.size.height = self.bounds.size.width;
self.imageView.frame = imageViewFrame;
//按钮内部label frame
CGRect titleLabelFrame = self.titleLabel.frame;
titleLabelFrame.origin.x = 0;
titleLabelFrame.origin.y = self.imageView.frame.size.height + 10;
titleLabelFrame.size.width = self.bounds.size.width;
self.titleLabel.frame = titleLabelFrame;
//按钮自身大小
CGRect buttonBounds = self.bounds;
buttonBounds.size.width = self.imageView.frame.size.width;
buttonBounds.size.height = self.imageView.bounds.size.height + self.titleLabel.bounds.size.height + 10;
self.bounds = buttonBounds;
}
@end
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# iOS弹跳动画
# iOS弹跳动画界面
# iOS动画发布界面
# 总结IOS界面间跳转的几种方法
# iOS图片界面翻页切换效果
# iOS仿微信图片分享界面实现代码
# IOS 聊天界面(自适应文字)的实现
# iOS中使用UItableviewcell实现团购和微博界面的示例
# iOS实现电商购物车界面示例
# IOS实现微信朋友圈相册评论界面的翻转过渡动画
# Unity iOS混合开发界面切换思路解析
# iOS高仿微信相册界面翻转过渡动画效果
# iOS开发之级联界面(推荐界面)搭建原理
# 自定义
# 是为了
# 行号
# 所要
# 移除
# 蒙板
# 离线
# 结束后
# 出了
# 最多
# 中心点
# 相对于
# 图层
# 很慢
# 结束时
# 具体内容
# 大家多多
# 调成
# 中经
# button_h
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel怎么集成Vue.js_Laravel Mix配置Vue开发环境
Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】
高端网站建设与定制开发一站式解决方案 中企动力
在centOS 7安装mysql 5.7的详细教程
如何制作公司的网站链接,公司想做一个网站,一般需要花多少钱?
创业网站制作流程,创业网站可靠吗?
Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives
移动端脚本框架Hammer.js
如何制作新型网站程序文件,新型止水鱼鳞网要拆除吗?
Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作
打开php文件提示内存不足_怎么调整php内存限制【解决方案】
如何快速生成凡客建站的专业级图册?
美食网站链接制作教程视频,哪个教做美食的网站比较专业点?
QQ浏览器网页版登录入口 个人中心在线进入
Laravel怎么使用Blade模板引擎_Laravel模板继承与Component组件复用【手册】
猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?
VIVO手机上del键无效OnKeyListener不响应的原因及解决方法
阿里云高弹*务器配置方案|支持分布式架构与多节点部署
Laravel如何部署到服务器_线上部署Laravel项目的完整流程与步骤
详解jQuery中的事件
微信小程序 配置文件详细介绍
html5如何设置样式_HTML5样式设置方法与CSS应用技巧【教程】
如何在云指建站中生成FTP站点?
为什么要用作用域操作符_php中访问类常量与静态属性的优势【解答】
Laravel怎么实现一对多关联查询_Laravel Eloquent模型关系定义与预加载【实战】
Laravel事件和监听器如何实现_Laravel Events & Listeners解耦应用的实战教程
焦点电影公司作品,电影焦点结局是什么?
西安专业网站制作公司有哪些,陕西省建行官方网站?
详解Android中Activity的四大启动模式实验简述
Laravel中间件如何使用_Laravel自定义中间件实现权限控制
如何批量查询域名的建站时间记录?
动图在线制作网站有哪些,滑动动图图集怎么做?
如何快速打造个性化非模板自助建站?
Laravel怎么实现验证码(Captcha)功能
Laravel如何操作JSON类型的数据库字段?(Eloquent示例)
jquery插件bootstrapValidator表单验证详解
如何在建站宝盒中设置产品搜索功能?
javascript中数组(Array)对象和字符串(String)对象的常用方法总结
车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?
如何在阿里云完成域名注册与建站?
香港服务器网站测试全流程:性能评估、SEO加载与移动适配优化
Java垃圾回收器的方法和原理总结
Win11怎么更改系统语言为中文_Windows11安装语言包并设为显示语言
详解Nginx + Tomcat 反向代理 负载均衡 集群 部署指南
千库网官网入口推荐 千库网设计创意平台入口
百度输入法ai面板怎么关 百度输入法ai面板隐藏技巧
如何快速启动建站代理加盟业务?
Laravel项目怎么部署到Linux_Laravel Nginx配置详解
php做exe能调用系统命令吗_执行cmd指令实现方式【详解】
Linux虚拟化技术教程_KVMQEMU虚拟机安装与调优

