很多应用都有带弹跳动画发布界面,这里用一个 UIViewController 实现这种效果,外界只要 modal出不带动画这个控制器就可以实现

#import "BSPublishVC.h"
#import "BSVerticalButton.h"
#import <POP.h>
 
@interface BSPublishVC ()
 
@end
 
@implementation BSPublishVC
 
- (void)viewDidLoad {
    [super viewDidLoad];
    //背景图征
    UIImageView *imageView = [[UIImageView alloc]init];
    imageView.frame = [UIScreen mainScreen].bounds;
    // shareBottomBackground
    imageView.image = [UIImage imageNamed:@"shareBottomBackground"];
    imageView.contentMode = UIViewContentModeScaleToFill;
    [self.view addSubview:imageView];
    
    //退出按钮
    UIButton *cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [cancelButton setTitle:@"退出" forState:UIControlStateNormal];
    [cancelButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [cancelButton setBackgroundImage:[UIImage imageNamed:@"FollowBtnBg"] forState:UIControlStateNormal];
    [cancelButton setBackgroundImage:[UIImage imageNamed:@"FollowBtnClickBg"] forState:UIControlStateHighlighted];
    CGRect frame = cancelButton.frame;
    frame.size = CGSizeMake(200, 30);
    frame.origin.y = [UIScreen mainScreen].bounds.size.height * 0.8;
    cancelButton.frame = frame;
    CGPoint point = cancelButton.center;
    point.x = [UIScreen mainScreen].bounds.size.width * 0.5;
    cancelButton.center = point;
    [cancelButton addTarget:self action:@selector(cancelButtonClick) forControlEvents:UIControlEventTouchUpInside];
    [imageView addSubview:cancelButton];
    
    
    //让一开始动画时不让控制的view失去交互,那这时在做动时点击按钮等都不会起作用
    self.view.userInteractionEnabled = NO;
    
    NSArray *buttonImages = @[@"publish-video",@"publish-picture",@"publish-text",@"publish-audio",@"publish-review",@"publish-offline"];
    NSArray *buttonTitles = @[@"发视频",@"发图片",@"发段子",@"发声音",@"审贴子",@"离线下载"];
    
    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 < buttonImages.count; ++i) {
        
        BSVerticalButton *button = [[BSVerticalButton alloc]init];
        
        button.tag = i;
        
        [self.view addSubview:button];
        
        [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
        
        [button setImage:[UIImage imageNamed:buttonImages[i]] forState:UIControlStateNormal];
        
        [button setTitle:buttonTitles[i] 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];
    }
    
    UIImageView *topImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"app_slogan"]];
    topImageView.center = CGPointMake([[UIScreen mainScreen] bounds].size.width * 0.5, [[UIScreen mainScreen] bounds].size.height * 0.2 - [[UIScreen mainScreen] bounds].size.height);
    
    
    [self.view addSubview:topImageView];
    
    //创建pop弹簧动画对象
    POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
    
    animation.beginTime = CACurrentMediaTime() + buttonImages.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(@"-------这里可以写动画结束后所要执行的代码...");
        
        self.view.userInteractionEnabled = YES; //动画完时让view开启交互
    };
    
    //给顶部的图片添加动画
    [topImageView pop_addAnimation:animation forKey:nil];
}
 
- (void)buttonClick:(UIButton *)button{
    
    [self cancelButtonClick];
    
    [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;
        }
    }];
    
}
 
// 退出发布界面的动画
- (void)animationWithBlock:(void (^) ())completionBlock{
    
    //退出时也不让所有的按钮或view能点击
    self.view.userInteractionEnabled = NO;
    
    for (NSInteger i = 1; i < self.view.subviews.count; ++i) {
        
        UIView *view = self.view.subviews[i];
        
        //创建pop基本动画对象
        POPBasicAnimation *animation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
        //        POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
        
        animation.beginTime = CACurrentMediaTime() + (i - 1) * 0.085; //动画开始时间
        
        // 如果用这个基类 POPBasicAnimation  动画的执行节奏(一开始很慢, 后面很快)
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
        
        CGPoint center = view.center;
        CGRect frame = view.frame;
        animation.toValue = [NSValue valueWithCGPoint:CGPointMake(center.x,  frame.origin.y + SCREEN_H)];
        
        if (i == self.view.subviews.count - 1) { //说明是最后一个 view在做动画,就让执行结束的 block
            // 动画结束时调用的 block
            animation.completionBlock = ^(POPAnimation *anim, BOOL finished){
                
                NSLog(@"取消时 这里可以写动画结束后所要执行的代码...");
                [self dismissViewControllerAnimated:NO completion:nil];
                
                if (completionBlock) {
                    completionBlock();
                }
                //                !completionBlock ? : completionBlock();
            };
        }
        //给顶部的图片添加动画
        [view pop_addAnimation:animation forKey:nil];
    }
}
 
- (void)cancelButtonClick{
    
    [self animationWithBlock:nil];
}
 
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    [self animationWithBlock:nil];
}
@end

BSVerticalButton.h 自定义的垂直排布按钮

#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

OC实现带弹跳动画按钮的界面控制器view的更多相关文章

  1. WPF界面设计技巧(3)—实现不规则动画按钮

    原文:WPF界面设计技巧(3)-实现不规则动画按钮 发布了定义WPF按钮的教程后,有朋友问能否实现不规则形状的按钮,今天我们就来讲一下不规则按钮的制作. 不规则按钮的做法实际上和先前我们做不规则窗体的 ...

  2. [转]Android UI:看看Google官方自定义带旋转动画的ImageView-----RotateImageView怎么写(附 图片淡入淡出效果)

    http://blog.csdn.net/yanzi1225627/article/details/22439119 众所周知,想要让ImageView旋转的话,可以用setRotation()让其围 ...

  3. OC导航栏自定义返回按钮

    [iOS]让我们一次性解决导航栏的所有问题 在默认情况下,导航栏返回按钮长这个样子   导航栏默认返回按钮 导航栏左上角的返回按钮,其文本默认为上一个ViewController的标题,如果上一个Vi ...

  4. Android UI:看看Google官方自定义带旋转动画的ImageView-----RotateImageView怎么写(附 图片淡入淡...)

    众所周知,想要让ImageView旋转的话,可以用setRotation()让其围绕中心点旋转,但这个旋转是不带动画的,也就是旋转屏幕时图片噌的一下就转过去了,看不到旋转的过程,此UI体验不大好,为此 ...

  5. iOS开发——项目实战OC篇&类QQ黏性按钮(封装)

    类QQ粘性按钮(封装) 那个,先来说说原理吧: 这里原理就是,在界面设置两个控件一个按钮在上面,一个View在下面(同样大小),当我们拖动按钮的时候显示下面的View,view不移动,但是会根据按钮中 ...

  6. 冒泡动画按钮的简单实现(使用CSS3)

    冒泡动画按钮的简单实现(使用CSS3) 原始的参考文章是 http://tutorialzine.com/2010/10/css3-animated-bubble-buttons/ ,基本原理是利用了 ...

  7. Android使用shape制作圆形控件及添加弹跳动画

    --------本来为作者原创,未经同意禁止转载 前言:我们在很多时候都需要在res/drawable文件夹下创建相应的xml文件来为控件添加一些样式效果,比如按钮按下时的按钮样式变化.或者指定按钮的 ...

  8. bootstrap带图标的按钮与图标做连接

    bootstrap通过引入bootstrap的JS与css文件,给元素添加class属性即可. 使用图标只需要加入一个span,class属性设置为对应的图标属性即可.图标对应的class属性可以参考 ...

  9. uwp - 做一个相对炫酷的动画按钮/按钮动画

    原文:uwp - 做一个相对炫酷的动画按钮/按钮动画 看腻了系统自带的button animation何不尝试下自定义一个较为炫酷的动画顺便提升用户体验.效果图: 动画分为几个部分,分别是:内圆从中心 ...

随机推荐

  1. SpringMVC源码分析--容器初始化(三)HttpServletBean

    在上一篇博客springMVC源码分析--容器初始化(二)DispatcherServlet中,我们队SpringMVC整体生命周期有一个简单的说明,并没有进行详细的源码分析,接下来我们会根据博客中提 ...

  2. IOS中 浅谈iOS中MVVM的架构设计与团队协作

    今天写这篇文章是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇文章的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...

  3. J2EE学习从菜鸟变大鸟之七 Servlet

    Servlet现在自己的理解是一个控制器,简单的可以理解为不同的JSP页面由用户发送过来的请求可以由Servlet控制器来控制其向下调用的方向(结合三层好理解),但它比较特殊,因为它通常会从外界接收数 ...

  4. USB OTG原理+ ID 检测原理

    OTG 检测的原理是: USB OTG标准在完全兼容USB2.0标准的基础上,增添了电源管理(节省功耗)功能,它允许设备既可作为主机,也可作为外设操作(两用OTG).USB OTG技术可实现没有主机时 ...

  5. ROS_Kinetic_02 ROS Kinetic 迁移指南及中文wiki指南(Migration guide)

    ROS_Kinetic_02 ROS Kinetic 迁移指南(Migration guide) 对于ROS Kinetic Kame有些功能包已经更新改变,提供关于这些包的迁移注意或教程.主要针对于 ...

  6. android binder理解

    Android中的Parcel是什么  Parcel,翻译过来是"打包"的意思.打包干什么呢?是为了序列化.     如果要在进程之间传递一个整数,很简单,直接传就是行了:如果要传 ...

  7. Chipmunk僵尸物理对象的出现和解决(六)

    既然出现了这个问题下面就是如何找到原因. 因为该问题不是每次都出现,偶尔反弹棒碰到五角星时才会多出一个僵尸棒,现象比较随机,较难悉知具体原因. 有时多次触碰又没有出现问题,有时短时间内每次触碰都出现问 ...

  8. android studio中使用lambda

    环境准备 如果还没有安装Java 8,那么你应该先安装才能使用lambda和stream(译者建议在虚拟机中安装,测试使用). 像NetBeans 和IntelliJ IDEA 一类的工具和IDE就支 ...

  9. c++中各个数据类型的大小

    来哦金额各种数据类型有助于我们对这门语言的更好掌握,更好的利用之来编程,下面是一个简单的获得数据类型的大小的程序,虽然简单,但实用性却很高. #include <iostream> usi ...

  10. UGUI实现NGUI的UIEventListener功能

    在unity中处理UI事件时,习惯了使用NGUI的UIEventListener,虽然UGUI也有AddListener,但是一个组件只能对应一个函数,不能在一个函数中同时处理多个事件,显得有些麻烦 ...