项目实战No9 不等高cell高度 相册图片

一 日期处理

  • 判断时间是不是今年

    • 方法1:手机当前时间nowYear和selfYear比较

      - (BOOL)isThisYear
      {
      NSCalendar *calendar = [NSCalendar currentCalendar];
      // 获得年
      NSInteger nowYear = [calendar component:NSCalendarUnitYear fromDate:[NSDate date]];
      NSInteger selfYear = [calendar component:NSCalendarUnitYear fromDate:self];
      
      return nowYear == selfYear;
      }
      
    • 方法2:时间转字符串,比较字符串

- (BOOL)isThisYear
{
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"yyyy";

    NSString *nowYear = [fmt stringFromDate:[NSDate date]];
    NSString *selfYear = [fmt stringFromDate:self];

    return [nowYear isEqualToString:selfYear];
}
  • 判断是否为今天

    • 方法1:年月日是否都一样

      - (BOOL)isToday
      {
      NSCalendar *calendar = [NSCalendar currentCalendar];
      
      NSDate *now = [NSDate date];
      
      return [calendar component:NSCalendarUnitYear fromDate:now] == [calendar component:NSCalendarUnitYear fromDate:self]
      && [calendar component:NSCalendarUnitMonth fromDate:now] == [calendar component:NSCalendarUnitMonth fromDate:self]
      && [calendar component:NSCalendarUnitDay fromDate:now] == [calendar component:NSCalendarUnitDay fromDate:self];
      }
      
    • 方法2

      - (BOOL)isToday
      {
      NSCalendar *calendar = [NSCalendar currentCalendar];
      
      NSCalendarUnit unit = NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear;
      
      NSDateComponents *nowCmps = [calendar components:unit fromDate:[NSDate date]];
      NSDateComponents *selfCmps = [calendar components:unit fromDate:self];
      
      return nowCmps.year == selfCmps.year
      && nowCmps.month == selfCmps.month
      && nowCmps.day == selfCmps.day;
      }
    • 方法3

      - (BOOL)isToday
      {
      NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
      fmt.dateFormat = @"yyyy-MM-dd";
      
      NSString *nowString = [fmt stringFromDate:[NSDate date]];
      NSString *selfString = [fmt stringFromDate:self];
      
      return [nowString isEqualToString:selfString];
      }
      
  • 是否为昨天,不能直接用天数相减,需要增加判断
- (BOOL)isYesterday
{
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"yyyy-MM-dd";

    // 获得只有年月日的时间
    NSString *nowString = [fmt stringFromDate:[NSDate date]];
    NSDate *nowDate = [fmt dateFromString:nowString];

    NSString *selfString = [fmt stringFromDate:self];
    NSDate *selfDate = [fmt dateFromString:selfString];

    // 比较
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSCalendarUnit unit = NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear;

    NSDateComponents *cmps = [calendar components:unit fromDate:selfDate toDate:nowDate options:0];

    return cmps.year == 0
    && cmps.month == 0
    && cmps.day == 1;
}

同理,用(return cmps.year == 0
&& cmps.month == 0
&& cmps.day == -1)可以判断是否为明天

  • 时间逻辑运算

    • 今年时间显示格式

      • 今天
        1> 时间差距 < 1分钟,显示为“刚刚”;
        2> 1分钟 =< 时间差距 <= 59分钟,显示为“xx分钟前”;
        3> 时间差距 >= 1小时,显示为“xx小时前”;
      • 昨天
        1> 昨天时间格式显示为“18:06:56”;
      • 其它
        1> 时间格式显示为“08-07 18:06:56”;
    • 非今年时间显示格式

      • 统一显示为“2014-08-07 18:06:56”;
 - (NSString *)created_at
{
    // 日期格式化类
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";

    // NSString -> NSDate
    NSDate *createdAtDate = [fmt dateFromString:_created_at];

    // 比较【发帖时间】和【手机当前时间】的差值
    NSDateComponents *cmps = [createdAtDate intervalToNow];

    if (createdAtDate.isThisYear) {
        if (createdAtDate.isToday) { // 今天
            if (cmps.hour >= 1) { // 时间差距 >= 1小时
                return [NSString stringWithFormat:@"%zd小时前", cmps.hour];
            } else if (cmps.minute >= 1) { // 1分钟 =< 时间差距 <= 59分钟
                return [NSString stringWithFormat:@"%zd分钟前", cmps.minute];
            } else {
                return @"刚刚";
            }
        } else if (createdAtDate.isYesterday) { // 昨天
            fmt.dateFormat = @"昨天 HH:mm:ss";
            return [fmt stringFromDate:createdAtDate];
        } else { // 今年的其他时间
            fmt.dateFormat = @"MM-dd HH:mm:ss";
            return [fmt stringFromDate:createdAtDate];
        }
    } else { // 非今年
        return _created_at;
    }
}   

二 计算cell高度

Xib起名字注意:控制器加载Xib优先会加载没有..Controller的Xib,如果没有再加在..Controller的Xib

  • 加载和xib类名一样的文件
+ (instancetype)viewFromXib
{
    return [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
}
  • xib建一个懒加载,cell的set方法频繁调用,会加载很多xib
- (XMGTopicPictureView *)pictureView
{
    if (!_pictureView) {
        XMGTopicPictureView *pictureView = [XMGTopicPictureView viewFromXib];
        [self.contentView addSubview:pictureView];
        _pictureView = pictureView;
    }
    return _pictureView;
}
  • 代码计算cell高度
    • 标签高度+文字的高度+图片高度(判断)+底部工具条高度
#pragma mark - 代理方法
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // cell的高度
    CGFloat cellHeight = XMGTopicTextY;

    // 计算文字的高度
    XMGTopic *topic = self.topics[indexPath.row];
    CGFloat textW = XMGScreenW - 2 * XMGCommonMargin;
    CGFloat textH = [topic.text sizeWithFont:[UIFont systemFontOfSize:15] constrainedToSize:CGSizeMake(textW, MAXFLOAT)].height;
    cellHeight += textH + XMGCommonMargin;

    // 中间内容的高度
    if (topic.type != XMGTopicTypeWord) {
        CGFloat contentW = textW;
        // 图片的高度 * 内容的宽度 / 图片的宽度
        CGFloat contentH = topic.height * contentW / topic.width;

        cellHeight += contentH + XMGCommonMargin;
    }

    // 工具条的高度
    cellHeight += XMGTopicToolbarH + XMGCommonMargin;

    return cellHeight;
}
  • 文字高度计算另一种写法
    CGFloat textH = [topic.text boundingRectWithSize:CGSizeMake(textW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:15]} context:nil].size.height;

计算cell高度,拖拽时候重复调用,浪费性能,抽取代码放到模型里
重写方法,增加if (_cellHeight == 0) 判断,cell高度只计算一次;

  • 计算图片的frame
    • 图片尺寸拿到,用layoutsubviews布局
  - (void)layoutSubviews
  {
     [super layoutSubviews];
      self.pictureView.frame = topic.contentFrame;
  }
  • 会报错约束冲突
    • 本来设置frame与最终显示效果不一样,注意下面属性:
  // 清空自动伸缩属性
  self.autoresizingMask = UIViewAutoresizingNone;

把cell的高度(cellHeight)和中间内容的frame(contentFrame)写到模型里面?
1. 模型是用来放数据的
2. 一个模型对应一个cellHeight和contentFrame

  • 判断要不要添加gif标识
  self.gifView.hidden = !topic.is_gif;
  • 查看大图按钮是否隐藏
   self.seeBigPictureButton.hidden = !topic.isBigPicture;
    if (topic.isBigPicture) {
    // 图片拉伸不带Scale就不会拉伸
        self.imageView.contentMode = UIViewContentModeTop;
        self.imageView.clipsToBounds = YES;
    } else {
        self.imageView.contentMode = UIViewContentModeScaleToFill;  // 拉伸到填充整个iamgeview
        self.imageView.clipsToBounds = NO;
    }
  • 如何判断图片是否gif图
    • 判断路径最后格式名
  NSString *ext = topic.image1.pathExtension.lowercaseString; // 转换为小写gif
  self.gifView.hidden = ![ext isEqualToString:@"gif"];

取出文件第一个字节,可判断文件属于什么格式,前提要先下载完文件数据

三 下载进度条

  • 设置展位图片的内容模式(View→Mode)
    • Aspect Fit:伸缩到高度/宽度一致为止
    • Aspect Fill:按宽高比伸缩到填充整个imageView,能看到整个图片为止
  • 下载图片
// 进度条
@property (weak, nonatomic) IBOutlet DALabeledCircularProgressView *progressView;
  [self.imageView sd_setImageWithURL:[NSURL URLWithString:topic.image1] placeholderImage:nil options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {
     // 每下载一点图片数据,就会调用一次这个block
     weakSelf.progressView.hidden = NO;
     weakSelf.progressView.roundedCorners = 5;
     weakSelf.progressView.progress = 1.0 * receivedSize / expectedSize;
     weakSelf.progressView.progressLabel.text = [NSString stringWithFormat:@"%.0f%%", weakSelf.progressView.progress * 100];
     weakSelf.progressView.progressLabel.textColor = [UIColor whiteColor];
    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
     // 当图片下载完毕后,就会调用这个block
     weakSelf.progressView.hidden = YES;
    }];
  • 设置进度条圆角和颜色只需要调用一次
- (void)awakeFromNib
{
    // 清空自动伸缩属性
    self.autoresizingMask = UIViewAutoresizingNone;

    self.progressView.roundedCorners = 5;
    self.progressView.progressLabel.textColor = [UIColor whiteColor];

    self.imageView.userInteractionEnabled = YES; // 可以点击
    [self.imageView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageClick)]];
}
  • 弹出大图片
- (void)imageClick
{
    if (self.imageView.image == nil) return;

    XMGSeeBigPictureViewController *seeBig = [[XMGSeeBigPictureViewController alloc] init];
    seeBig.topic = self.topic;
    [self.window.rootViewController presentViewController:seeBig animated:YES completion:nil];
}

四 保存大图片

  • 查看大图控制器
    • 图片尺寸超过屏幕高度,设置图片x和y为(0,0)
    • 如果没有超过屏幕高度,居中显示
- (void)viewDidLoad {
    [super viewDidLoad];

    // 滚动控件
    UIScrollView *scrollView = [[UIScrollView alloc] init];
    scrollView.frame = [UIScreen mainScreen].bounds;
    scrollView.backgroundColor = [UIColor blackColor];
    scrollView.delegate = self;
    [self.view insertSubview:scrollView atIndex:0]; // 在数组最前面,保证所有控件放在前面

    // 图片
    UIImageView *imageView = [[UIImageView alloc] init];
    [imageView sd_setImageWithURL:[NSURL URLWithString:self.topic.image1]];
    [scrollView addSubview:imageView];
    self.imageView = imageView;

    // 图片的尺寸
    imageView.x = 0;
    imageView.width = XMGScreenW;
    imageView.height = self.topic.height * imageView.width / self.topic.width;
    if (imageView.height > XMGScreenH) { // 图片过长
        imageView.y = 0;
        scrollView.contentSize = CGSizeMake(0, imageView.height);
    } else { // 图片居中显示
        imageView.centerY = XMGScreenH * 0.5;
    }

    // 伸缩
    CGFloat maxScale = self.topic.height / imageView.height;
    if (maxScale > 1.0) {
        scrollView.maximumZoomScale = maxScale;
    }
}
  • 图片实现伸缩
    • 遵循UIscrollview代理
#pragma mark - <UIScrollViewDelegate>
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return self.imageView;
}

五 相册图片

  • 通过拍照获得一张图片
   UIImagePickerController *picker = [[UIImagePickerController alloc] init];
   picker.sourceType = UIImagePickerControllerSourceTypeCamera;
   [self presentViewController:picker animated:YES completion:nil];
  • 从相册中挑选一张图片
   UIImagePickerController *picker = [[UIImagePickerController alloc] init];
   picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
   [self presentViewController:picker animated:YES completion:nil];

自定义照相机 : AVCaptureSession

  • 遍历相册文件夹
  ALAssetsLibrary *Library = [ALAssetsLibrary alloc] init;
// 遍历所有文件夹,一个ALAssetsGroup对象就代表一个文件夹
 [Library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
// 遍历文件夹内的所有多媒体文件(图片、视频),一个ALAsset对象代表一张图片
    [group enumerateAssetsUsingBlock^(ALAsset *result, NSUInteger index, BOOL *stop) {
    XMGLog;
    }];
 } failureBlock:nil];
  • 文件夹名字
- (NSString *)groupName
{
    // 先从沙盒中取得名字
    NSString *groupName = [[NSUserDefaults standardUserDefaults] stringForKey:XMGGroupNameKey];
    if (groupName == nil) { // 沙盒中没有存储任何文件夹的名字
        groupName = XMGDefaultGroupName;

        // 存储名字到沙盒中
        [[NSUserDefaults standardUserDefaults] setObject:groupName forKey:XMGGroupNameKey];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }

    return groupName;
}
  • 添加一张图片到某个文件夹中
- (void)addImageToGroup:(ALAssetsGroup *)group
{
    __weak ALAssetsLibrary *weakLibrary = self.library;
    // 需要保存的图片
    CGImageRef image = self.imageView.image.CGImage;

    // 添加图片到【相机胶卷】
    [weakLibrary writeImageToSavedPhotosAlbum:image metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) {
        [weakLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) {
            // 添加一张图片到自定义的文件夹中
            [group addAsset:asset];
            [SVProgressHUD showSuccessWithStatus:@"保存成功!"];
        } failureBlock:nil];
    }];
}
  • 保存图片
- (IBAction)save
{
    // 获得文件夹的名字
    __block NSString *groupName = [self groupName];

    // self的弱引用
    XMGWeakSelf;

    // 图片库
    __weak ALAssetsLibrary *weakLibrary = self.library;

    // 创建文件夹
    [weakLibrary addAssetsGroupAlbumWithName:groupName resultBlock:^(ALAssetsGroup *group) {
        if (group) { // 新创建的文件夹
            // 添加图片到文件夹中
            [weakSelf addImageToGroup:group];
        } else { // 文件夹已经存在
            [weakLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
                NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
                if ([name isEqualToString:groupName]) { // 是自己创建的文件夹
                    // 添加图片到文件夹中
                    [weakSelf addImageToGroup:group];

                    *stop = YES; // 停止遍历
                } else if ([name isEqualToString:@"Camera Roll"]) {
                    // 文件夹被用户强制删除了
                    groupName = [groupName stringByAppendingString:@" "];
                    // 存储新的名字
                    [[NSUserDefaults standardUserDefaults] setObject:groupName forKey:XMGGroupNameKey];
                    [[NSUserDefaults standardUserDefaults] synchronize];
                    // 创建新的文件夹
                    [weakLibrary addAssetsGroupAlbumWithName:groupName resultBlock:^(ALAssetsGroup *group) {
                        // 添加图片到文件夹中
                        [weakSelf addImageToGroup:group];
                    } failureBlock:nil];
                }
            } failureBlock:nil];
        }
    } failureBlock:nil];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值