IOS 一句代码搞定启动引导页

  • 前言
    引导页,一个酷炫的页面,自从微博用了之后一下就火起来了,对于现在来说一个app如果没有引导页似乎总显那么不接地气,那么为了让我们的app也“高大上”一次,我写了一个demo来实现启动引导页的实现,鉴于我的强迫症,使用起来也是尽可能的简单才算罢休,这不,一句代码就搞定了,而且支持版本更新后显示新的引导页,先看效果:

LaunchIntroduction.gif

demo中封装了两个方法以供调用,一个是在滚动视图的最后一个页面带有进入按钮,一个是不带按钮,直接滚动就可隐藏引导页。


  • 特点
    1、使用简单,一句代码搞定
    2、支持自定义指示器的颜色
    3、支持应用升级后显示新的引导页
  • 下载地址:LaunchIntroductionDemo 下载
    先说使用方法,来不及的童靴可以先尝尝鲜:

    1、导入LaunchIntroductionView.m 和 LaunchIntroductionView.h 文件到工程中
    2、在APPDelegate中包含头文件 #import "LaunchIntroductionView.h"
    3、调用:
    [LaunchIntroductionView sharedWithImages:@[@"launch0.jpg",@"launch1.jpg",@"launch2.jpg",@"launch3"]];
    4、还有一种调用方法,是带button的:
    [LaunchIntroductionView sharedWithImages:@[@"launch0.jpg",@"launch1.jpg",@"launch2.jpg",@"launch3"] buttonImage:@"login" buttonFrame:CGRectMake(kScreen_width/2 - 551/4, kScreen_height - 150, 551/2, 45)];


  • 讲解

  • 头文件
    /**
    *  选中page的指示器颜色,默认白色
    */
    @property (nonatomic, strong) UIColor *currentColor;
    /**
    *  其他状态下的指示器的颜色,默认
    */
    @property (nonatomic, strong) UIColor *nomalColor;
    /**
    *  不带按钮的引导页,滑动到最后一页,再向右滑直接隐藏引导页
    *
    *  @param imageNames 背景图片数组
    *
    *  @return   LaunchIntroductionView对象
    */
    +(instancetype)sharedWithImages:(NSArray *) imageNames;
    /**
    *  带按钮的引导页
    *
    *  @param imageNames      背景图片数组
    *  @param buttonImageName 按钮的图片
    *  @param frame           按钮的frame
    *
    *  @return LaunchIntroductionView对象
    */
    +(instancetype)sharedWithImages:(NSArray *) imageNames buttonImage:(NSString *) buttonImageName buttonFrame:(CGRect ) frame;
  • 核心实现
  • 实现原理
    创建一个UIView对象view,然后在view上添加一个scrollview,scrollview上添加需要的图片及按钮等,然后程序第一次启动或者应用升级后把view添加到当前的window上,这样view就显示了出来,当滑动到最后或者点击进入程序的按钮时将view从window上移除,为了更好的体验效果,在view移除时加了一个0.5s的动画,产生了一个view渐渐消失的效果。
  • 详细讲解
    1、下面是调用接口的实现,均采用的是单例形式
    得益于i_Steven的一席话,已修改,详情见文章底部的更新,不再使用单例的形式,也欢迎围观我的这篇文章单例的使用及避免对单例的滥用
    不带按钮时默认是滑动到最后时将引导页隐藏
    #pragma mark - 创建单例-->>不带button
    +(instancetype)sharedWithImages:(NSArray *)imageNames{
      static LaunchIntroductionView *launch = nil;
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
          images = imageNames;//背景数组
          isScrollOut = YES;//不带按钮时默认是滑动到最后时将引导页隐藏
          launch = [[LaunchIntroductionView alloc] initWithFrame:CGRectMake(0, 0, kScreen_width, kScreen_height)];
          launch.backgroundColor = [UIColor whiteColor];
      });
      return launch;
    }

    带按钮时默认是点击按钮时将引导页隐藏,滑动并不会隐藏引导页,按钮出现在最后一个页面

    #pragma mark - 创建单例-->>带button
    +(instancetype)sharedWithImages:(NSArray *)imageNames buttonImage:(NSString *)buttonImageName buttonFrame:(CGRect)frame{
      static LaunchIntroductionView *launch = nil;
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
          images = imageNames;
          isScrollOut = NO;//带按钮默认是点击按钮时将引导页隐藏
          enterBtnFrame = frame;//button的frame
          enterBtnImage = buttonImageName;//button的图片名字
          launch = [[LaunchIntroductionView alloc] initWithFrame:CGRectMake(0, 0, kScreen_width, kScreen_height)];
          launch.backgroundColor = [UIColor whiteColor];
      });
      return launch;
    }

    2、初始化时根据是不是首次启动或者更新版本后首次启动来判断要不要添加引导页到window上

    #pragma mark - 初始化
    -(instancetype)initWithFrame:(CGRect)frame
    {
      self = [super initWithFrame:frame];
      if (self) {
          //使用KVO监听指示器颜色的变化
          [self addObserver:self forKeyPath:@"currentColor" options:NSKeyValueObservingOptionNew context:nil];
          [self addObserver:self forKeyPath:@"nomalColor" options:NSKeyValueObservingOptionNew context:nil];
          if ([self isFirstLauch]) {
              UIWindow *window = [[UIApplication sharedApplication] windows].lastObject;
              [window addSubview:self];
              [self addImages];
          }else{
              [self removeFromSuperview];
              self = nil;
          }
      }
      return self;
    }

    3、版本更新或者首次启动的判断

    #pragma mark - 判断是不是首次登录或者版本更新
    -(BOOL )isFirstLauch{
      //获取当前版本号
      NSDictionary *infoDic = [[NSBundle mainBundle] infoDictionary];
      NSString *currentAppVersion = infoDic[@"CFBundleShortVersionString"];
      //获取上次启动应用保存的appVersion
      NSString *version = [[NSUserDefaults standardUserDefaults] objectForKey:kAppVersion];
      //版本升级或首次登录
      if (version == nil || ![version isEqualToString:currentAppVersion]) {
          [[NSUserDefaults standardUserDefaults] setObject:currentAppVersion forKey:kAppVersion];
          [[NSUserDefaults standardUserDefaults] synchronize];
          return YES;
      }else{
          return NO;
      }
    }

    4、滚动视图的创建就很简单了,不具体再介绍,大家可以下载代码看具体的实现,接下来主要说一下我在demo中遇到的稍微费点劲的问题:滚动方向的判断
    demo中现在用的是这样的判断:

    #pragma mark - 判断滚动方向
    -(BOOL )isScrolltoLeft:(UIScrollView *) scrollView{
      //返回YES为向左反动,NO为右滚动
      if ([scrollView.panGestureRecognizer translationInView:scrollView.superview].x < 0) {
          return YES;
      }else{
          return NO;
      }
    }

    其中translationInView的官方解释是这样的:

    translation in the coordinate system of the specified view

英文不太好,我的理解大概就是在一个特定view中的坐标,那么到底是干什么用的呢?log一下看看,结果返现只要往左滑动屏幕,由

[scrollView.panGestureRecognizer translationInView:scrollView.superview].x

得到的值就为负数,反之则为正数,而且在手指触摸的起始地方为坐标的(0,0)点,那么好了,这样我就能判断左右滑动的方向了,然后就可以根据带不带button,在scrollview的delegate中在最后一个界面上来判断要不要隐藏引导页了:

#pragma mark - scrollView Delegate
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    int cuttentIndex = (int)(scrollView.contentOffset.x + kScreen_width/2)/kScreen_width;
    if (cuttentIndex == images.count - 1) {//保证是在最后一个页面
        if ([self isScrolltoLeft:scrollView]) {//是否为左滑
            if (!isScrollOut) {//在设置为滑动不能隐藏引导页的情况下直接返回
                return ;
            }
            [self hideGuidView];//反之在左滑成立的情况下隐藏引导页
        }
    }
}

当然,并不是所有的事情看起来都那么理所当然,我刚开始用到的判断滑动方向的方法并不是这样的,而是:

-(BOOL )isScrolltoLeft:(UIScrollView *) scrollView{
    BOOL ret = NO;
    static CGFloat newX = 0;
    static CGFloat oldX = 0;
    newX = scrollView.contentOffset.x;
    if (newX > oldX) {
        ret = YES;
    }else{
        ret = NO;
    }
    oldX = newX;
    return ret;//返回YES就是向左滑动,返货NO就是向右滑动
}

根据scrollView的contentOffset来判断,这样做在scrollview的bounce为yes的情况下是完全没问题的,bounce如果为NO在最后一个页面是无法判断作画效果的,原因也很简单,但却让我费了一番功夫,bounce为no的情况下,在最后一个页面向左滑动时scrollview的contentOffset是不会发生发生辩护的,所以导致在无按钮的情况下无论怎么滑引导页都不会隐藏,那bounce就设为yes不就行了?但是引导页如果带个bounce效果,那实在是让人无法接受的,查找了多方资料才找到上面的那个方法,希望大家以后避免这个坑,少走弯路。


  • 详细使用方法
    1、不带按钮、不定义指示器的颜色:

    [LaunchIntroductionView sharedWithImages:@[@"launch0.jpg",@"launch1.jpg",@"launch2.jpg",@"launch3"]];

    是的,就这么一句代码就搞定了,我们只需要传入背景图片即可。
    2、不带按钮,定制指示器的颜色:

      LaunchIntroductionView *launch = [LaunchIntroductionView sharedWithImages:@[@"launch0.jpg",@"launch1.jpg",@"launch2.jpg",@"launch3"]];
      launch.currentColor = [UIColor redColor];
      launch.nomalColor = [UIColor greenColor];

    3、带按钮、不定制指示器的颜色:

    [LaunchIntroductionView sharedWithImages:@[@"launch0.jpg",@"launch1.jpg",@"launch2.jpg",@"launch3"] buttonImage:@"login" buttonFrame:CGRectMake(kScreen_width/2 - 551/4, kScreen_height - 150, 551/2, 45)];

    传的参数稍微多了点,不过也是应该并且值得的:背景图片数组,进入应用的按钮图片,按钮的frame,共三个参数
    4、带按钮,定制指示器的颜色

      LaunchIntroductionView *launch = [LaunchIntroductionView sharedWithImages:@[@"launch0.jpg",@"launch1.jpg",@"launch2.jpg",@"launch3"] buttonImage:@"login" buttonFrame:CGRectMake(kScreen_width/2 - 551/4, kScreen_height - 150, 551/2, 45)];
      launch.currentColor = [UIColor redColor];
      launch.nomalColor = [UIColor greenColor];


  • End

  • 更新1
    首先感谢i_Steven的意见,刚开始实现这个效果的时候想着用单例挺方便的,但随之而来的内存问题确实是存在的,或许占得内存确实是不大的,但是这确实是一个问题,是问题就得改,于是我改了:

    #pragma mark - 创建对象-->>不带button
    +(instancetype)sharedWithImages:(NSArray *)imageNames{
      images = imageNames;
      isScrollOut = YES;
      launch = [[LaunchIntroductionView alloc] initWithFrame:CGRectMake(0, 0, kScreen_width, kScreen_height)];
      launch.backgroundColor = [UIColor whiteColor];
      return launch;
    }
    #pragma mark - 创建对象-->>带button
    +(instancetype)sharedWithImages:(NSArray *)imageNames buttonImage:(NSString *)buttonImageName buttonFrame:(CGRect)frame{
      images = imageNames;
      isScrollOut = NO;
      enterBtnFrame = frame;
      enterBtnImage = buttonImageName;
      launch = [[LaunchIntroductionView alloc] initWithFrame:CGRectMake(0, 0, kScreen_width, kScreen_height)];
      launch.backgroundColor = [UIColor whiteColor];
      return launch;
    }

    于是也催生了我这篇单例的使用及避免对单例的滥用文章,欢迎围观。

  • 更新2
    更新时间: 2017.01.12
    更新内容:添加storyboard支持

使用storyboard时调用的方法

需要注意的是,如果项目不是使用的storyboard创建时调用此方法会导致crash。

时间: 2024-10-12 20:09:19

IOS 一句代码搞定启动引导页的相关文章

对百度WebUploader开源上传控件的二次封装,精简前端代码(两句代码搞定上传)

首先声明一下,我这个是对WebUploader开源上传控件的二次封装,底层还是WebUploader实现的,只是为了更简洁的使用他而已. 下面先介绍一下WebUploader 简介: WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件.在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,沿用原来的FLASH运行时,兼容IE6+,iOS 6+, android 4+.两套运行时,同样的调用方式,可供

Android开发:一句代码搞定eclipse查看v4源码

在android开发的时候,看不到源码其实是很悲催的事情的,关于如何查看源码的博文已经许多了,可是今天在试图添加V4源码的时候,发现了许多麻烦且不靠谱的方式,实验了许久,还是没有加上,比如以下的这些方法: 解决eclipse无法打开android-support-v4的源码 解决eclipse无法查看v4,v7-appcompat源码 Android 如何在Eclipse中查看Android API源码以及support包源码 跟着这些复杂方法,弄了很久,最终也没有搞定,后来柳暗花明,终于在st

【开源】1句代码搞定图片批量上传,无需什么代码功底【无语言界限】

开源地址:https://github.com/dunitian/LoTUploader WebUploader基础上的封装改善,一句代码全部实现(样式美化,实例JS优化(配置优化,样式调整,名称+大小显示,错误处理等),后端代码.....) 效果:(完整demo:https://github.com/dunitian/LoTUploader/tree/V1.0/Demo) 一句代码:$.lotuploader('lot-uploader', '/Home/Upload'); //必填参数:ID

python交换两个变量的值,一句代码搞定

a = 10 b = 20 # 不需要中间变量,一步搞定 a, b = b, a

iOS开发小功能之九:五句代码搞定简单的父子控制器

小码哥大神的代码,确实精简! 1.最终结果如下面三个图,点击one,two,three,分别出现3个不同的控制器 直接代码:(三个控制器的创建就上了) #import "ViewController.h" #import "ZWOneViewController.h" #import "ZWTwoViewController.h" #import "ZWThreeViewController.h" @interface Vie

一句代码搞定,所有页面点击空白处隐藏键盘

首先新建一个appdelegate的分类 代码如下: #import "AppDelegate.h" @interface AppDelegate (DismissKeyboard) /** 开启点击空白处隐藏键盘功能 */ - (void)openTouchOutsideDismissKeyboard; @end @implementation AppDelegate (DismissKeyboard) /** 开启点击空白处隐藏键盘功能 */ - (void)openTouchOu

c# 一句代码搞定菱形打印

需求:打印金字塔,菱形,如: 首先定义行数n,对金字塔而言,空格依次递减,星号依次递增.菱形以行数位分界点,从0-n与金字塔相同,从n到2n-1行规律相反:因此需要以n位基准,用行数与n相减求绝对值,方法如下: public static void PrintDiamond(int n) { for (int i = 1; i <= 2 * n - 1; i++)      // 金字塔则只需在该行将2n-1改为n即可 { for (int j = 1; j <= Math.Abs(n - i

猫猫学IOS(四十一)UI之核心动画 两行代码搞定3D转场(做android的哭死)

猫猫分享,必须精品 原创文章,欢迎转载.转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243?viewmode=contents 源码素材地址:http://blog.csdn.net/u013357243/article/details/45583465 效果: 代码: 其实代码很少,苹果都给封装好了 // 1.创建核心动画 CATransition *ca = [CATransition animation]; // 1.1动画过渡类型 ca.typ

iOS开发三步搞定百度推送

iOS开发三步搞定百度推送 百度推送很简单,准备工作:在百度云推送平台注册应用,上传证书. 步骤一: 百度云推送平台 http://push.baidu.com/sdk/push_client_sdk_for_ios  在这里下载iOS端SDK包,如下图: 把SDK包里面的下图文件夹拖到你的工程中,如下图,第一步就这么简单. 步骤二: 在工程中AppDelegate.m中的- (BOOL)application:(UIApplication *)application didFinishLaun