iOS带弹跳动画发布界面

2023-10-31 20:50
文章标签 界面 发布 ios 动画 弹跳

本文主要是介绍iOS带弹跳动画发布界面,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

项目中经常会用到带弹跳动画发布界面


//  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带弹跳动画发布界面的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/318056

相关文章

iOS HTTPS证书不受信任解决办法

之前开发App的时候服务端使用的是自签名的证书,导致iOS开发过程中调用HTTPS接口时,证书不被信任 - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAu

WordPress网创自动采集并发布插件

网创教程:WordPress插件网创自动采集并发布 阅读更新:随机添加文章的阅读数量,购买数量,喜欢数量。 使用插件注意事项 如果遇到404错误,请先检查并调整网站的伪静态设置,这是最常见的问题。需要定制化服务,请随时联系我。 本次更新内容 我们进行了多项更新和优化,主要包括: 界面设置:用户现在可以更便捷地设置文章分类和发布金额。代码优化:改进了采集和发布代码,提高了插件的稳定

AI赋能天气:微软研究院发布首个大规模大气基础模型Aurora

编者按:气候变化日益加剧,高温、洪水、干旱,频率和强度不断增加的全球极端天气给整个人类社会都带来了难以估计的影响。这给现有的天气预测模型提出了更高的要求——这些模型要更准确地预测极端天气变化,为政府、企业和公众提供更可靠的信息,以便做出及时的准备和响应。为了应对这一挑战,微软研究院开发了首个大规模大气基础模型 Aurora,其超高的预测准确率、效率及计算速度,实现了目前最先进天气预测系统性能的显著

IOS 数组去重的几种方式

本来只知道NSSet和KeyValues的。今天又新学了几种方式 还有就是和同事学的一种方式 外层循环从0开始遍历,内层从最后一个元素开始遍历 for(int i=0;i<index;i++){  for(int j=index-1;j>i;j-- ){ } }

iOS Assertion failure in -[UITableView _classicHeightForRowAtIndexPath:]

iOS Assertion failure in -[UITableView _classicHeightForRowAtIndexPath:]  2015-04-24 11:40  956人阅读  评论(0)  收藏  举报   分类:   iOS 基础篇(208)  版权声明:本文为博主原创文章,未经博主允许不得转载。 Assertion

iOS:编译时出现no such file or directory:xxx以及use twice...filenames are used to distinguish private dec

简    注册  登录   添加关注 作者  婉卿容若 2016.04.29 11:22 写了21870字,被16人关注,获得了14个喜欢 iOS:编译时出现"no such file or directory:xxx"以及"use twice...filenames are used to distinguish private

iOS 到处 ipa包的时候 会有四个选项分别代表什么

如图 在 iOS 到处 ipa包的时候 会有四个选项  1.Save for iOS App Store Deployment 保存到本地 准备上传App Store 或者在越狱的iOS设备上使用 2.Save for Ad Hoc Deployment 保存到本地 准备在账号添加的可使用设备上使用(具体为在开发者账户下添加可用设备的udid),该app包是发布证书编

iOS 7适配上存在的各种问题

谈谈项目中遇到的各种iOS7适配问题 由于我的项目要适配到iOS7.1, 而现在已经是9时代了,在实际工作中我也是遇到了各种奇葩的坑,所以我想尽快把遇到的iOS7适配问题和解决方案分享出来,以后这些东西可能就用处不大了。   1.字体问题 iOS7中的字体适配恐怕是最麻烦的坑了,原因是iOS7以上的许多字体在7都是不存在的,甚至包括一些system-字体。比如system-

【Qt6.3 基础教程 17】 Qt布局管理详解:创建直观和响应式UI界面

文章目录 前言布局管理的基础为什么需要布局管理器? 盒布局:水平和垂直排列小部件示例:创建水平盒布局 栅格布局:在网格中对齐小部件示例:创建栅格布局 表单布局:为表单创建标签和字段示例:创建表单布局 调整空间和伸缩性示例:增加弹性空间 总结 前言 当您开始使用Qt设计用户界面(UI)时,理解布局管理是至关重要的。布局管理不仅关系到UI的外观,更直接影响用户交互的体验。本篇博

潜艇伟伟迷杂交版植物大战僵尸2024最新免费安卓+ios苹果+iPad分享

嗨,亲爱的游戏迷们!今天我要给你们种草一个超有趣的游戏——植物大战僵尸杂交版。这款游戏不仅继承了原有经典游戏的核心玩法,还加入了许多创新元素,让玩家能够体验到前所未有的乐趣。快来跟随我一起探索这个神奇的世界吧! 植物大战僵尸杂交版最新绿色版下载链接: https://pan.quark.cn/s/d60ed6e4791c 🔥 创新与经典的完美结合 植物大战僵尸杂交版在保持了原游戏经典玩