欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS制作带弹跳动画发布界面

程序员文章站 2023-12-18 20:28:58
项目中经常会用到带弹跳动画发布界面,具体内容如下 效果图: 代码: // publishview.m // uiimage+imageeffects...

项目中经常会用到带弹跳动画发布界面,具体内容如下

效果图:

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

上一篇:

下一篇: