当前位置: 移动技术网 > 移动技术>移动开发>IOS > ios新手开发——toast提示和旋转图片加载框

ios新手开发——toast提示和旋转图片加载框

2019年01月02日  | 移动技术网移动技术  | 我要评论
不知不觉自学ios已经一个月了,从oc语法到app开发,过程虽然枯燥无味,但是结果还是挺有成就感的,在此分享我的ios开发之路中的小小心得~废话不多说,先上我们今天要实现的效果图:  

不知不觉自学ios已经一个月了,从oc语法到app开发,过程虽然枯燥无味,但是结果还是挺有成就感的,在此分享我的ios开发之路中的小小心得~废话不多说,先上我们今天要实现的效果图:

 

\

 

有过一点做app经验的都知道,提示框和等待加载框一直是app首当其中的效果,ios不像android一样,自带toast和progressbardialog,所以在做ios开发的时候,我首先想到了先封装这两个基础控件~当然网上的资源数不胜数,但是博主抱着一颗自主研究的精神,做出的效果也不错,也已适配了所有iphone型号和版本.望大家多多支持~

 

ypxtoastview实现

 

接触过安卓开发的ios开发者可能对待toast这么个东西很不陌生,它主要是一种轻量级的提示,代替了复杂的对话框,有的显示在中间,有的显示在屏幕下方,当然,这些都是根据需求而来的.废话不多说,首先清理一下我们实现这个toast的一些必要思路:

 

1.实现的基础控件------uilabel封装

2.弹出的时间和透明度变化设置

3.显示的位置调整

 

一.uilabel的封装

首先我们想要实现一下这个效果,首当其冲的肯定想到uilabel,那么接下来就是对uilabel的封装了,首先我们创建一文件继承uilabel,然后写好要对外暴露的方法:

 

@interface ypxtoastview : uilabel

{
    @public
    cgfloat screenwidth,screenheight;
    int _corner;
    int _duration;
}

@property(assign,nonatomic)int corner;
@property(assign,nonatomic)int duration;


-(void)showtoastviewwithtext:(nsstring *)text andduration:(int)duration andparentview:(uiview *)parentview;

-(void)showtoastviewwithtext:(nsstring *)text andparentview:(uiview *)parentview;

-(void)showtoastviewwithtext:(nsstring *)text andduration:(int)duration andcorner:(int)corner andparentview:(uiview *)parentview;

+(void)showtoastviewwithtext:(nsstring *)text andduration:(int)duration andparentview:(uiview *)parentview;

+(void)showtoastviewwithtext:(nsstring *)text andparentview:(uiview *)parentview;

+(void)showtoastviewwithtext:(nsstring *)text andduration:(int)duration andcorner:(int)corner andparentview:(uiview *)parentview;

-(void)setbackgroundwithcolor:(uicolor *)color;

@end

定义了四个全局变量,两个属性,分别制定了提示框的圆角和时间.方法中定义了三个类方法,和四个实例方法,主要是因为我们在使用时并不想实例化一次我们的提示框,所有的实例方法中抽出了三个类方法方便用户调用.

 

下面我们来看内部主要方法实现:

 

 

/**
 *  新建ui
 *
 *  @param str 要显示的文本
 */
-(void)createuibytext:(nsstring *)str{
    self.textalignment = nstextalignmentcenter;
    self.backgroundcolor = [uicolor colorwithred:00 green:00 blue:00 alpha:0.5];
    self.alpha = 0.8;
    self.text=str;
    self.font = [uifont systemfontofsize:14];
    self.textcolor=[uicolor whitecolor];
    nsdictionary *attributes = @{nsfontattributename:[uifont systemfontofsize:self.font.pointsize],};
    cgsize textsize = [self.text boundingrectwithsize:cgsizemake(100, 100) options:nsstringdrawingtruncateslastvisibleline attributes:attributes context:nil].size;;
    self.frame=cgrectmake(screenwidth/2-(textsize.width*1.7)/2, screenheight*0.5,textsize.width*1.7,
                               textsize.height*2);
    self.layer.cornerradius = _corner;
    self.clipstobounds = yes;
}

-(void)setbackgroundwithcolor:(uicolor *)color{
    self.backgroundcolor =color;
}


/**
 *  初始化测量数据
 */
-(void)caculatesize{
    screenwidth=[uiscreen mainscreen].bounds.size.width;
    screenheight=[uiscreen mainscreen].bounds.size.height;
}

 

 

方法一目了然,指定了uilabel的居中方式和背景,并设置属性让其宽度自适应,涉及到一些简单的frame计算,主要是定位于屏幕中间,宽度设为文本宽度的1.7倍,看起来比较适中.y点主要就是屏幕高度的一半,理应减去文本的高度的一半,但是博主在这偷个懒,并没有计算label的高度,所以就不赘述了~~

二.弹出的时间和透明度变化设置

原理很简单,就是设定了一个animatewithduration的block回调,然后设置label的透明度和时间,具体实现如下:

 

/**
 *  显示toast
 *
 *  @param parentview <#parentview description#>
 */
-(void)showtoastbyparentview:(uiview *)parentview{
    [parentview addsubview:self];
    //animatewithduration可以控制label显示持续时间
    [uiview animatewithduration:_duration animations:^{
        self.alpha = 1.0;
    } completion:^(bool finished){
        [self removefromsuperview];
    }];
}

默认时间为1秒,思路很清晰,先添加进我们的parentview中,然后指定时间后移除.

 

到此,我们的ypxtoastview已经全部完成,其实内部逻辑主要是对uilabel的定制,思路简单,但是对于ios开发之路的封装思想有很大的帮助.调用时只需要一行代码:

 

[ypxtoastview showtoastviewwithtext:@"已开启" andduration:3 andcorner:5 andparentview:self.view];

调用方便简洁,以后测试就不需要用nslog了嘿嘿~

 

ypxloddingview实现

 

相信在ios的开发中少不了加载等待框的开发,毕竟原生中貌似没有这样的对话框,我们在访问网络或者读取数据时可能需要给用户一个等待回馈,这里就用到了我们的等待加载.上面的gif中提供了两种等待加载框的样式,一种是自定义图片的旋转,顺时针或者逆时针,另一种是使用系统的uiactivityindicatorview,使用大的加载loadding.具体开发思路如下:

 

 

1.继承uiview通过添加uiimageview和uilabel来组合实现

2.控制uiimageview的旋转以及uilabel的三个点的动态效果

3.显示和隐藏

 

一.uiview的封装

通过效果我们可以一目了然的知道,实现这个控件至少需要一个uiimageview(或者uiactivityindicatorview)和uilabel,一个提供加载图片,一个提供加载文本,组合方式为竖直方向,然后设置背景的透明度.具体.h文件如下:

 

#import 

@interface ypxloaddingview : uiview

{
    @public
    int num;
    cgfloat angle;
    bool isshowloadding;
    uiimageview * imageview;
    uilabel * label;
    cgfloat width;
    cgfloat x;
    cgfloat y,screenwidth,screenheight;
    uiview * _parentview;
    nsstring * _text;
    nstimer * _timer;
    uiactivityindicatorview * _activityview;
    uiview * view;
}

@property(retain,nonatomic)nstimer * timer;
@property(copy,nonatomic) nsstring * text;
@property(retain,nonatomic) uiactivityindicatorview * activityview;

-(void)showloaddingviewwithtext:(nsstring *) string;

-(void)dismissloaddingview;

-(instancetype)initwithparentview:(uiview *) parentview;

+(id)initwithparentview:(uiview *) parentview;

-(bool)isshowing;

-(void)showloaddingview;

-(void)showloaddingviewwithstyle:(int)style;

-(void)showloaddingviewwithtext:(nsstring * )text andstyle:(int)style;

@end


定义了一些必要的属性,包括计时器和显示文本等,主要功能为show开头的方法,style应该是个枚举类型,但是博主目前还没有写过枚举类,所以直接引用0和1来指定使用图片还是系统的菊花加载.看完.h我们来看看具体的uiview代码实现:

 

 

/**
 *  计算一些必要尺寸
 *
 *  @param parentview <#parentview description#>
 */
-(void)caculatsizewithtarget:(uiview *) parentview
{
    screenwidth=[uiscreen mainscreen].bounds.size.width;
    screenheight=[uiscreen mainscreen].bounds.size.height;
    width=screenwidth*0.3;
    x= screenwidth/2-width/2;
    y= screenheight/2-width/2;
    angle=0;
    num=0;
    isshowloadding=no;
    _parentview=parentview;
    
}

/**
 *  创建loadding视图
 */
-(void)creatloaddingview
{
    view=[[uiview alloc]init];
    view.frame=cgrectmake(0, 0, screenwidth, screenheight);
    
    imageview=[[uiimageview alloc]init];
    imageview.frame=cgrectmake(width/2-width*0.5/2,15, width*0.5,width*0.4);
    imageview.clipstobounds=yes;
    imageview.layer.rasterizationscale=[uiscreen mainscreen].scale;
    [imageview setimage:[uiimage imagenamed:@"loadding.png"]];
    
    _activityview=[[uiactivityindicatorview alloc]initwithframe:cgrectmake(width/2-width*0.55/2,15, width*0.55,width*0.45)];
    _activityview.activityindicatorviewstyle=uiactivityindicatorviewstylewhitelarge;
    
    
    label=[[uilabel alloc]init];
    label.textcolor=[uicolor whitecolor];
    label.font=[uifont systemfontofsize:14];
    int y2=imageview.frame.size.height+(width-imageview.frame.size.height)/2;
    label.frame=cgrectmake(0,y2, width, 20);
    label.textalignment=nstextalignmentcenter;
    
}

手动布局,我们指定了imageview和label的frame,通过一系列计算,把imageview设为uiview中上部,并留出四周的边距,看起来更亲切自然一点.label的位置根据imageview的frame来指定,这样就可以完成适配避免在不同屏幕上显示不同的问题.完场上述代码,一个初步的静态效果已经生成,剩下的就是添加动画;

 

二.uiimageview旋转动画以及uilabel点点动态展示

 

imageview的动画添加很简单,因为我们只是涉及一点点的旋转动画,其中并没有加速度变化,读者若是想要添加,可以自己尝试一下.旋转动画的实现方式有两种:

一种是用animatewithduration来动态的旋转一定角度,然后通过延时来改变旋转的速率,好处是简单,但是缺点也很明显,在5s中动画显得僵硬,并伴随着一点点的卡顿,如下是第一种动画方案的代码:

 

 

/**
 *  开启loadding动画
 */
- (void)startanimation
{
    if(isshowloadding==yes){
        cgaffinetransform endangle = cgaffinetransformmakerotation(angle * (m_pi / -180.0f));
        [uiview animatewithduration:0.03f delay:0 options:uiviewanimationoptioncurvelinear animations:^{
            imageview.transform =endangle;
        } completion:^(bool finished) {
            if(angle==360){
                angle=0;
            }
            if(angle==0||angle==360){
                label.text=[_text stringbyappendingstring:@"..."];
            }else if(angle==90){
                label.text=_text;
            }else if(angle==180){
                label.text=[_text stringbyappendingstring:@"."];
            }else if(angle==270){
                label.text=[_text stringbyappendingstring:@".."];
            }
            angle += 10;
            
            [self startanimation];
        }];
    }
    
}


 

通过改变imageview的角度来旋转图片的方式,使用block回调中的角度关系,我们可以动态的设置提示文本省略号的动态展示.因为实现效果有点卡顿,所以博主采用了第二种实现方式,代码如下:

 

/**
 *  启动计数定时器
 */
-(void)updatetext
{
    num++;
    if (num>4) {
        num=0;
    }
    if(num==0||num==4){
       label.text=[_text stringbyappendingstring:@"..."];
    }else if(num==1){
       label.text=_text;
    }else if(num==2){
       label.text=[_text stringbyappendingstring:@"."];
    }else if(num==3){
        label.text=[_text stringbyappendingstring:@".."];
    }

}

/**
 *  给imageview添加动画
 *
 *  @param imageview imageview
 *
 *  @return imageview
 */
+ (uiimageview *)rotateimageview:(uiimageview *)imageview
{
    cabasicanimation *animation = [ cabasicanimation
                                   animationwithkeypath: @"transform" ];
    animation.fromvalue = [nsvalue valuewithcatransform3d:catransform3didentity];
    
    //围绕z轴旋转,垂直与屏幕
    animation.tovalue = [ nsvalue valuewithcatransform3d:
                         catransform3dmakerotation(m_pi, 0.0, 0.0, 1.0) ];
    animation.duration = 0.5;
    //旋转效果累计,先转180度,接着再旋转180度,从而实现360旋转
    animation.cumulative = yes;
    animation.repeatcount = 10000;
    
    [imageview.layer addanimation:animation forkey:nil];
    return imageview;
}

采用cabasicanimation的动画效果可以达到动画流畅度的完美展示,优点就是增加了旋转性能,缺点就是没有像animatewithduration那样有动画的回调,这样我们就没有办法动态的去改变label的提示文本,所以细心的读者会发现,博主前面的.h文件中已经申明了一个定时器,那么这个定时器的作用是用来干嘛的呢?我们通过启动定时器,来动态的刷新label的提示文本达到一种动态展示的效果,这种思路在安卓里也同样适用.

 

完成了我们的图片旋转,基本上这个功能已经完成了百分之八十,剩下就是显示和隐藏了;

 

三.显示和隐藏

前面介绍.h文件申明的时候,已经把本控件的所有调用方法已经列出来了,其中包含了一系列的.show方法,因为loadding这种控件,我们可能需要对其状态进行判断,而且可能在网络请求中调用多次,为了不浪费内存,我们在这里提倡使用单例模式,并初始化一个loadding在viewdidload中.后期调用只需要show和dismiss即可,下面我们来看具体的show和dismiss的方法实现:

 

/**
 *  显示loadding.默认文本为 "正在加载"
 */
-(void)showloaddingview
{
    if(isshowloadding==yes){
        return;
    }
    if(_text==nil||[_text isequaltostring:@""]){
        _text=@"正在加载";
    }
    label.text=_text;
    isshowloadding=yes;
    angle=0;
    self.hidden=no;
    [self addsubview:imageview];
    [self addsubview:label];
    [view addsubview:self];
    [_parentview addsubview:view];
    [ypxloaddingview rotateimageview:imageview];
    _timer=[nstimer scheduledtimerwithtimeinterval:0.5 target:self selector:@selector(updatetext) userinfo:nil repeats:yes];

}

-(void)showloaddingviewwithstyle:(int)style
{
    if(style==0){//菊花加载
        if(isshowloadding==yes){
            return;
        }
        if(_text==nil||[_text isequaltostring:@""]){

             _text=@"正在加载";
         }
        label.text=_text;
        isshowloadding=yes;
        angle=0;
        self.hidden=no;
        [self addsubview:_activityview];
        [self addsubview:label];
        [imageview removefromsuperview];
        [_activityview startanimating];
        [view addsubview:self];
        [_parentview addsubview:view];
        _timer=[nstimer scheduledtimerwithtimeinterval:0.5 target:self selector:@selector(updatetext) userinfo:nil repeats:yes];

    }else{//旋转图片加载
        [self showloaddingview];
    }

}

/**
 *  显示loadding
 *
 *  @param string 显示的文本
 */
-(void)showloaddingviewwithtext:(nsstring *) string
{
    _text=string;
    [self showloaddingview];
}


-(void)showloaddingviewwithtext:(nsstring *)text andstyle:(int)style{
    _text=text;
    [self showloaddingviewwithstyle:style];
}

/**
 *  消失loadding
 */
-(void)dismissloaddingview
{
    self.hidden=yes;
    isshowloadding=no;
    [_timer invalidate];
    [imageview.layer removeallanimations];
    [_activityview stopanimating];
    [view removefromsuperview];
}

总体来说show方法中就是单纯的控制了imageview和_activityview通过style来隐藏和显示,思路很简单,再次不做赘述.dismiss中只需要移除我们的view就好,非常简单,同时不要忘记stop我们的_activityview以及关闭定时器就好.

致此,所有的代码实现已经完成,我们在需要调用的地方首先实例化一次,然后使用show和dismiss即可.

 

总结

ios开发总体来说还算顺风顺水,因为对安卓有一定的基础,学习oc等面向对象的语法不免要快一点,但是ios中对于控件的方法并不是很多,甚至某些安卓一行代码就能实现的功能,ios需要好多行,这就是一个语言的魅力所在,当然,在自学ios的过程中我会不断的通过写博客的方式来提升自己的水平,在新手开发道路中,希望我能雨你们同行,谢谢读者的支持~~

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网