行使 UICollectionView 实现日历签到功能

效果图


。。。。。葡京签到送彩金 1

接在北京地区的朋友等以10月与微软学者相聚于共同享受Windows Phone应用开发的不错! 
•超值技术大餐~~免费与哦~~ 参与运动开发App就见面得到免费之Windows Phone Token 
•除了免费的Windows Phone Token, 还有多两全其美礼品~~~ 
•精彩尽,收获无限,沟通无限,尽在2013年10月19日! 
•欢迎热爱新技巧,热爱读书之爱人报名与! 

概述


在 App 中,日历通常与签到功能结合使用。是提高用户活跃度的一种方式,同时,签到数据中蕴含了丰富的极其有价值的信息。下面我们就来看看如何在 App 中实现日历签到功能。

走日程: 

加上“日历签到”控件


  • 拿“日历签到”控件添加至控制器的 view 上

    - (void)viewDidLoad {
        [super viewDidLoad];
        // 添加“日历签到”视图
        self.calendarSignInView = [[IDCalendarSignInView alloc] init];
        [self.view addSubview:self.calendarSignInView];
        // 添加“签到”按钮
        self.signInButton = [[IDConfirmButton alloc] init];
        [self.signInButton setTitle:@"签到" forState:UIControlStateNormal];
        [self.signInButton addTarget:self action:@selector(signInButtonClick:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:self.signInButton];
    }
    
  • 点击“签到”按钮,更新签到标签的状态

    - (void)signInButtonClick:(UIButton *)button {
        self.calendarSignInView.isSignInForToday = YES;
    }
    

2:30- 3:30
Windows Phone 应用开发
姜泳涛 

切实落实


  • 声明
    • 此部分主要阐述代码实现,代码中有详细的注释,若对以上思路不太理解,可以结合代码整理自己的思路
    • 由于篇幅限制,在这里,不再贴出应用实现的全部代码。若有需要的朋友,请联系我,我将提供完整的工程文件。感谢您的理解和支持,您的支持是我坚持下去最大的动力,真心的谢谢你们。以下是我的 Blog 地址:
      • 猥琐孤岛
  • 供展示“日历”所待的数额( NSDate+Calculate 文件 )

    • 收获当前月总共有多少天

      + (NSInteger)numberOfDaysInCurrentMonth {
          // 初始化日历
          NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
          // 获取系统当前日期
          NSDate *currentDate = [NSDate date];
          // 获取当前日期中当前月中天的范围
          NSRange range = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:currentDate];
          // 得到当前月中总共有多少天(即范围的长度)
          NSInteger numberOfDaysInCurrentMonth = range.length;
          return numberOfDaysInCurrentMonth;
      }
      
    • 取当前月份被共有多少周

      + (NSInteger)numberOfWeeksInCurrentMonth {
          // 初始化日历
          NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
          // 获取系统当前日期
          NSDate *currentDate = [NSDate date];
          // 获取当前日期中当前月中周的范围
          NSRange range = [calendar rangeOfUnit:NSCalendarUnitWeekOfMonth inUnit:NSCalendarUnitMonth forDate:currentDate];
          // 得到当前月中总共有多少周(即范围的长度)
          NSInteger numberOfWeeksInCurrentMonth = range.length;
          return numberOfWeeksInCurrentMonth;
      }
      
  • 于定义流水布局( IDCalendarCollectionViewFlowLayout 文件 )

    • 安各一个 Item 的布局

      /** 设置 indexPath 位置的 Item 的布局属性 */
      - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
          // 获取 indexPath 位置的布局属性
          UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
          // 计算每一个 Item 的 frame
          CGFloat collectionViewLeftPadding = self.collectionView.contentInset.left;
          CGFloat collectionViewRightPadding = self.collectionView.contentInset.right;
          // size
          CGFloat itemWidth = (self.collectionView.bounds.size.width - collectionViewLeftPadding - collectionViewRightPadding - 5*IDCalendarCollectionViewCellHerizontalMargin) / 7.0;
          CGFloat itemHeigh = self.collectionView.bounds.size.height / [NSDate numberOfWeeksInCurrentMonth];
          // origin
          CGFloat itemX = ((self.indexOfWeekForFirstDayInCurrentMonth + indexPath.item) % 7) * (itemWidth + IDCalendarCollectionViewCellHerizontalMargin);
          CGFloat itemY = ((self.indexOfWeekForFirstDayInCurrentMonth + indexPath.item) / 7) * itemHeigh;
          layoutAttributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeigh);
          // 返回 indexPath 位置的 Item 的布局属性
          return layoutAttributes;
      }
      
  • 自定义“日历” CollectionView 的 Cell( IDCalendarCollectionViewCell
    文件 )

    • 供接口,用于控制签到标签的状态

      /** 是否已经签到 */
      @property (nonatomic, assign) BOOL haveSignedIn;
      /** 重写 set 方法,用于更新 “签到” 标签的状态 */
      - (void)setHaveSignedIn:(BOOL)haveSignedIn {
          _haveSignedIn = haveSignedIn;
          if (_haveSignedIn) {
              self.signInLabel.hidden = NO;
          } else {
              self.signInLabel.hidden = YES;
          }
      }
      
    • 补给加子控件

      - (instancetype)initWithFrame:(CGRect)frame {
          if (self = [super initWithFrame:frame]) {
              // 初始化 “日期数字” label,并添加到 cell 中
              self.dateLabel = [[UILabel alloc] init];
              self.dateLabel.textColor = [UIColor colorWithRed:122/255.0 green:122/255.0 blue:122/255.0 alpha:1.0];
              [self.contentView addSubview:self.dateLabel];
              // 初始化 “签到” label,并添加到 cell 中
              self.signInLabel = [[UILabel alloc] init];
              self.signInLabel.hidden = YES; // 默认隐藏“签到”标签
              self.signInLabel.textColor = [UIColor colorWithRed:228/255.0 green:49/255.0 blue:42/255.0 alpha:1.0];
              self.signInLabel.font = [UIFont systemFontOfSize:10];
              self.signInLabel.text = @"签到";
              [self.contentView addSubview:self.signInLabel];
          }
          return self;
      }
      
  • 自定义“日历签到”控件( IDCalendarSignInView 文件)

    • 加加子控件

      /** 设置 “日期” 部分 */
      - (void)setupCalendarDateView {
          // 初始化 “日期” View,并添加到 IDCalendarSignInView
          self.calendarDateView = [[UIView alloc] init];
          [self addSubview:self.calendarDateView];
          // 初始化分割线 并添加到 “日期” View
          self.dateSeperatorView = [[UIView alloc] init];
          self.dateSeperatorView.backgroundColor = [UIColor colorWithRed:226/255.0 green:226/255.0 blue:226/255.0 alpha:1.0];
          [self.calendarDateView addSubview:self.dateSeperatorView];
          // 初始化日期 label 并添加到 “日期” View
          self.calendarDateLabel = [[UILabel alloc] init];
          self.calendarDateLabel.font = [UIFont systemFontOfSize:15];
          NSDate *currentDate = [NSDate date];
          NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
          dateFormatter.dateFormat = @"yyyy年MM月";
          NSString *dateString = [dateFormatter stringFromDate:currentDate];
          self.calendarDateLabel.text = dateString;
          [self.calendarDateView addSubview:self.calendarDateLabel];
      }
      /** 设置 “周几” 部分 */
      - (void)setupCalendarWeekdayView {
          // 初始化 “日期” View,并添加到 IDCalendarSignInView
          self.calendarWeekdayView = [[UIView alloc] init];
          [self addSubview:self.calendarWeekdayView];
          // 初始化分割线 并添加到 “周几” View
          self.weekdaySeperatorView = [[UIView alloc] init];
          self.weekdaySeperatorView.backgroundColor = [UIColor colorWithRed:226/255.0 green:226/255.0 blue:226/255.0 alpha:1.0];
          [self.calendarWeekdayView addSubview:self.weekdaySeperatorView];
          // 初始化 “周几” label 并添加到 “周几” View
          NSArray *weekday = @[@"日", @"一", @"二", @"三", @"四", @"五", @"六"];
          for (NSInteger i = 0; i < 7; i++) {
              UILabel *weekDayLabel = [[UILabel alloc] initWithFrame:CGRectZero];
              weekDayLabel.textAlignment = NSTextAlignmentCenter;
              weekDayLabel.font = [UIFont systemFontOfSize:13];
              weekDayLabel.textColor = [UIColor colorWithRed:97/255.0 green:97/255.0 blue:97/255.0 alpha:1.0];
              weekDayLabel.text = weekday[i];
              // 将 “周几” 信息保存在成员变量中
              [self.weekdayLabelArray addObject:weekDayLabel];
              [self.calendarWeekdayView addSubview:weekDayLabel];
          }
      }
      /** 设置 “日历” 部分 */
      - (void)setupCalendarCollectionView {
          // 设置 "日历" 的布局
          IDCalendarCollectionViewFlowLayout *flowLayout = [[IDCalendarCollectionViewFlowLayout alloc] init];
          flowLayout.headerReferenceSize = CGSizeMake(self.bounds.size.width, 20);
          // 初始化 “日历” CollectionView,设置相关属性,并添加到 IDCalendarSignInView
          self.calendarCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
          self.calendarCollectionView.backgroundColor = [UIColor whiteColor];
          self.calendarCollectionView.scrollEnabled = NO;
          self.calendarCollectionView.dataSource = self;
          self.calendarCollectionView.delegate = self;
          [self.calendarCollectionView registerClass:[IDCalendarCollectionViewCell class] forCellWithReuseIdentifier:IDCalendarCollectionViewCellIdentifier];
          [self addSubview:self.calendarCollectionView];
          // 初始化分割线 并添加到 “日历” View
          self.collectionViewSeperatorArray = [NSMutableArray array];
          for (NSInteger i = 0; i < [NSDate numberOfWeeksInCurrentMonth]; i++) {
              UIView *collectionViewSeperator = [[UIView alloc] initWithFrame:CGRectZero];
              collectionViewSeperator.backgroundColor = [UIColor colorWithRed:226/255.0 green:226/255.0 blue:226/255.0 alpha:1.0];
              [self.collectionViewSeperatorArray addObject:collectionViewSeperator];
              [self.calendarCollectionView addSubview:collectionViewSeperator];
          }
          // 设置“日历” View 的内边距
          self.calendarCollectionView.contentInset = UIEdgeInsetsMake(0, 15, 0, 15);
      }
      
    • 布局子控件

      - (void)layoutSubviews {
          [super layoutSubviews];
          // “日期”
          [self.calendarDateView mas_makeConstraints:^(MASConstraintMaker *make) {
              make.leading.trailing.equalTo(self);
              make.top.equalTo(self.mas_top);
              make.height.offset(35);
          }];
          // “周几”
          [self.calendarWeekdayView mas_makeConstraints:^(MASConstraintMaker *make) {
              make.leading.trailing.equalTo(self);
              make.top.equalTo(self.calendarDateView.mas_bottom);
              make.height.offset(38);
          }];
          // “日历”
          [self.calendarCollectionView mas_makeConstraints:^(MASConstraintMaker *make) {
              make.top.equalTo(self.calendarWeekdayView.mas_bottom);
              make.leading.trailing.bottom.equalTo(self);
          }];
          // “日期” 部分的分割线
          [self.dateSeperatorView mas_makeConstraints:^(MASConstraintMaker *make) {
              make.leading.trailing.top.equalTo(self.calendarDateView);
              make.height.offset(1);
          }];
          // 周几信息
          for (NSInteger i = 0; i < 7; i++) {
              self.weekdayLabelArray[i].frame = CGRectMake(i * (self.calendarCollectionViewItemSize.width + 10) + 15, 0, self.calendarCollectionViewItemSize.width, 35);
          }
          // “周几” 部分的分割线
          [self.weekdaySeperatorView mas_makeConstraints:^(MASConstraintMaker *make) {
              make.leading.top.trailing.equalTo(self.calendarWeekdayView);
              make.height.offset(1);
          }];
          // “日历” 显示日期的 label
          [self.calendarDateLabel mas_makeConstraints:^(MASConstraintMaker *make) {
              make.centerX.centerY.equalTo(self.calendarDateView);
          }];
          // “日历” 部分的分割线
          for (NSInteger i = 0; i < [NSDate numberOfWeeksInCurrentMonth]; i++) {
              self.collectionViewSeperatorArray[i].frame = CGRectMake(0, i * self.calendarCollectionViewItemSize.height, [UIScreen mainScreen].bounds.size.width - 30, 1);
          }
      }
      
    • 供“日历” CollectionView 的数据源

      - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
          return [NSDate numberOfDaysInCurrentMonth];
      }
      - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
          IDCalendarCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:IDCalendarCollectionViewCellIdentifier forIndexPath:indexPath];
          cell.numberTextInDateLabel = indexPath.item + 1;
          return cell;
      }
      
  • “签到”按钮( IDConfirmButton 文件)

    • 接近于“签到”按钮这样外观的按钮,是采取被比普遍的按钮,如:“确定”、“取消”按钮通常为是这种外观,通常我们将如此的按钮写成一个通用的半空中,放到
      Common 文件被
    • 未指定拉伸区域时的效用

      葡京签到送彩金 2

    • 指定拉伸区域后底功用

      葡京签到送彩金 3

    • 自定义 IDConfirmButton

      - (instancetype)initWithFrame:(CGRect)frame {
          if (self = [super initWithFrame:frame]) {
              [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
              [self setBackgroundImage:[UIImage resizedImageWithName:@"btn_normal"] forState:UIControlStateNormal];
              [self setBackgroundImage:[UIImage resizedImageWithName:@"btn_highlight"] forState:UIControlStateHighlighted];
              [self setBackgroundImage:[UIImage resizedImageWithName:@"btn_disable"] forState:UIControlStateDisabled];
              self.layer.cornerRadius = 5.0;
              self.layer.masksToBounds = YES;
          }
          return self;
      }
      
    • IDConfirmButton
      的图,若提供的图的尺寸,不等于按钮的尺码,图片就会被牵涉伸。当图片有圆角是,拉伸后的图纸通常不复合需求,所以我们得指定图片的拖累伸区域(UIImage+Resizing)

      /** 返回一张图片,按指定方式拉伸的图片:width * 0.5 : height * 0.5 */
      + (UIImage *)resizedImageWithName:(NSString *)name {
          UIImage *image = [UIImage imageNamed:name];
          return [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5];
      }
      

Windows Phone Development 张欣:
微博
微软Windows Phone Development方向最好有价专家。十不必要年的色支付及保管更,历年来多次充当MEDC、TechEd、MSDN Webcast等Windows Phone方面的科目讲师。目前行为运动应用领域的技艺研讨及放工作。

思路分析


实现日历签到功能的思路有很多种,这里我们就使用 UICollectionView 来实现具备签到功能的日历
  • 基础知识

    • 关于瀑布流(若你针对 UICollectionView 及 UICollectionViewLayout
      的学问无极端了解,请参考以下文章)

      • 瀑布流-01-自定义布局实现绚丽之瀑布流
      • 瀑布流-02-手把手教而包装自定义布局
      • 瀑布流-03-通过包装的自定义布局快速实现货物展示
    • 关于布局(使用 CocoaPods 集成第三正框架 Masonry
      进行界面布局,若你针对 CocoaPods 的使不顶了解,请参考以下文章)

      • CocoaPods的安及采取那些从(Xcode 7.2,iOS
        9.2,Swift)
    • 关于 pch 文件的部署方式,请参考以下文章
      • pch
        文件的布置方式
    • 关于路之公文结构

      在应用开发过程中,我们通常会指定一定的文件结构,便于项目的开发和维护。该博客中的文件结构如图:
      

      葡京签到送彩金 4

      • 祈求中一级文件结构的底剪切是本使用的政工模块划分,如:
        • Sections:应用之功能模块
        • Network:应用的网要模块
        • Common:应用被通用的文本,通常是起定义控件
        • Macro:应用中的庞
        • Category:应用被之归类
        • Other:其他,如:Appdelegate,main,pch 等文件
      • 贪图备受二级文件结构的底划分是按照用之功能模块划分,如:
        • Mine:是一个品类遭到,通常所有的功能模块
      • 贪图被三级级文件结构的之剪切是本 MVC 架构模式划分,如:
        • Model
        • View
        • Controller
  • 思路

    • 显“日历”所待的数目(使用 NSDate 的归类提供)
      • 目前月总共有多少天,即:“日历” CollectionView 中 Item 的多寡
      • 当前月份被共有多少周,即:“日历” CollectionView 的行数
      • 脚下月份被首先上在同样两全内之目,即:实现“日历”中的诸一样天与周几信息对应
      • 当天当当月遭受之目(第几天),即:点击“签到”按钮时,通过索引找到“日历”
        CollectionView 中之 Item 更新 “签到”标签的状态
    • “日历”布局(使用 IDCalendarCollectionViewFlowLayout 定义)
      • 在此处用从定义流水布局来设置 “日历” CollectionView
        的布局(使用 frame 布局 每一个 Item)
    • “日历” 控件
      • 合日历控件(IDCalendarSignInView)中查封装了以下控件
        • calendarDateView:显示日期,如:2016年03月
        • calendarWeekdayView:显示周几信息,如:日 一 二 …… 六
        • calendarCollectionView:显示日历
        • seperatorView:分割线
      • 分控件的布局
        • 于此间,统一在 layoutSubviews
          方法吃布局子控件(此时获取到的 IDCalendarSignInView
          控件的 frame
          才是终极确定的)。这一个专业,尽量遵循,可以避过多难调试之
          bug

地方:微软北京望京Office (北京朝阳区通往京街利星行广场微软大厦3层培训室)。
公共交通:可乘坐公交536或者是538在国风北京站就任就至。   

活动说明和报名地点
www.aka.ms\mvpbeijing

 

挪组织者和运动讲师: 
MVP姜泳涛 
微博
Windows Phone Development MVP,TechED讲师。主要从事Windows Phone开发,现在只顾于Windows Phone平台技术的研究暨推广。 连续三年获得Windows Phone development微软绝有价专家(MVP)称号。随着Windows Phone 8的揭示,他将重要精力放到Windows Phone 8技术之学着,致力为Windows Phone 8平台技术的钻研与推广。

显赫Windows Phone 开发讲师: 
Expression Blend MVP 李靖南:
微博 
李靖南,Client Development MVP,专注于用户体验的规划及实现,作品包括[城里人日记]、[超电压]、[知事]等。 

时间     1:00- 1:30 
课 程    签到,MVP项目介绍
讲 师    MVP

Windows Phone Development 马宁:
微博
一度凭微软亚洲工程院软件工程师,从事Windows Embedded Compact开发工作. 加入微软之前, 连续四年获得”微软绝有价专家”称号,Windows Embedded 应用开发者,长期从Windows Embedded 企业级以的付出和系统架构设计工作;Tech•Ed 和 MEDC 讲师;《程序员》杂志移动开专栏撰稿人。 

时间:2013年10月19日 周六 下午1点 -下午5点30分。 

1:30- 2:30
Windows Phone 应用设计
李靖南 

3:30- 4:10
Windows Phone 游戏应用开发、推广经验分享
马宁 
 
4:10- 5:00
Windows Phone
号级应用分享
张欣 
 
5:00- 5:30
Q&A
MVP
 
运动说明和申请地点
www.aka.ms\mvpbeijing

 欢迎北京底冤家参与于当年10月开办的Windows Phone 应用开发专场活动。多各项资深的微软绝有价专家Windows Phone和Client端开发MVP为而详细描述Windows Phone应用开发,让你通过一致下午底日到摸底Windows Phone开发的通。与业界专家进行面对面的交流。通过此次活动,能够让开发者了解Windows Phone的开发工具,所急需控制的出语言,技术架构。让设计师和产品经营了解Windows Phone的筹划理念,如何提升利用之用户体验。让Windows Phone爱好者了解怎么发布以与玩,在采用Windows Phone Store发布以之经过被,需要注意如何大的问题,帮助大家再轻松的通告应用程序,更快速地加大好的下与游戏 。 

微软MVP社区秋日巡讲 —— 北京Windows  Phone应用开发训练营