前言
公司忙着开放发功能,一直都都没时间来更新,废话不多。今天主要完成的功能
1、微博列表的展示
2、下拉刷新和上拉加载更多
3、点击查看大图和长按图片保存的本地相册。
首先来来张效果图
1、普通微博界面的UI
我把其分为三部分,如下图
1.1、布局分析
个人信息和微博内容为一部分(偷懒没有自定义view)
图片展示用CollectView来展示
底部三个按钮则是用xib拖得的View
布局的话用AutoLayout的第三方SnapKit来进行布局的。
这里就不贴代码了。
1.2不等高Cell问题的解决
由于不同的微博内容,导致cell的高度不同,因此需要定义一个方法来获取cell的高度。
// MARK:计算cell的高度
func getCellHeight(status:YJStatus) -> CGFloat {
self.status = status
layoutIfNeeded()
return CGRectGetMaxY(bottomToolBar.frame);
}
该方法在cell的返回高度的地方调用,
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let status = statusArry[indexPath.row]
let height = calCell.getCellHeight(status)
print("计算高度")
return height
}
注意:这里的calCell我是懒加载一个专门用来计算cell高度的cell,懒加载的目的是不要重复创建cell。因为使用下面方法获取cell计算的高度是有问题的。所以暂时这样计算高度。
let cell = tableView.dequeueReusableCellWithIdentifier(reuseID)
2、数据的处理
微博官网文档的数据结构如下(截图不完整
)
从上图中我们中我们可以看出返回的包含微博对象的数组,微博对象中又包含了User对象。因此我们需要新建两个对象,将返回的数据包装到两个对象中,方法使用。
微博对象
class YJStatus: NSObject
用户对象
class YJUser: NSObject
重写init方法将字典转为对象
init(dict: [String:AnyObject]) {
super.init()
setValuesForKeysWithDictionary(dict)
}
这里重写setValueForKey是为叫user转为对象
override func setValue(value: AnyObject?, forKey key: String) {
if key == "user" {
user = YJUser(dict: value as![String:AnyObject])
return
}
super.setValue(value, forKey: key)
}
因为我创建的对象YJStatus没包含数据中所有的key值,所有需要重写下面的方法,防止程序崩溃,注意不需要实现
//重写该方法是为不崩溃
override func setValue(value: AnyObject?, forUndefinedKey key: String) {
}
有了数据后,剩下就是把数据赋值给cell,然后更新UI。以前OC中我一般会重写model的set方法,在该方法中去更新UI,swift中我的写法如下,在didSet中赋值,更新UI,其他和OC中一样。
//微博模型
var status:YJStatus?{
didSet {
//在这里赋值
sourceLabel.text = status?.source
contentLabel.text = status?.text
crateTimeLabel.text = status?.created_at
userIconImageView.sd_setImageWithURL(status?.user!.iconURL)
nickNameLabel.text = status?.user?.name
//给缩略图片赋值
pictureView.imageURLS = status!.thumbURLs
// 赋值给大图
pictureView.largeURLs = status!.largeURLs
//图片赋值完后计算图片大小,更新约束
let size = pictureView.calPictureSize()
print(size)
self.pictureHeighCons?.constraint.updateOffset(size.height)
self.pictureWidthCons?.constraint.updateOffset(size.width)
}
}
这里另外讲下微博时间的处理,因为返回的时间并不是我们想要的格式,我们需要对其处理,在给时间赋值的didSet方法中进行处理,处理如下
//微博的创建时间
var created_at: String? {
didSet {
//在这里处理时间
//先把时间处理为NSDate
let formatter = NSDateFormatter()
//设置时间的格式
formatter.dateFormat = "EEE MMM d HH:mm:ss Z yyyy"
// 设置时间的区域
formatter.locale = NSLocale(localeIdentifier: "en")
// 转化为NSDate
let cratedDate = formatter.dateFromString(created_at!)
if let realDate = cratedDate {
//在这里与当前时间比较
//获取当前日历
let currentCalendar = NSCalendar.currentCalendar()
if currentCalendar.isDateInToday(realDate) {
//如果在今天之内
//计算当前时间和系统时间之差
let interval = Int(NSDate().timeIntervalSinceDate(realDate))
if interval<60 {
created_at = "刚刚"
}
if interval<60*60 {
created_at = "\(interval/60)分钟前"
}
created_at = "\(interval/60/60)小时前"
}
// 2.判断是否是昨天
var formatterStr = "HH:mm"
if currentCalendar.isDateInYesterday(realDate) {
formatterStr = "昨天:" + formatterStr
}
else {
//处理一年以内
formatterStr = "MM-dd " + formatterStr
//获取年份
let comps = currentCalendar.components(NSCalendarUnit.Year, fromDate: realDate, toDate: NSDate(), options: NSCalendarOptions(rawValue: 0))
if comps.year >= 1 {
formatterStr = "yyyy-" + formatterStr
}
}
//设置格式化
formatter.dateFormat = formatterStr
created_at = formatter.stringFromDate(realDate)
}
}
}
3、点击查看大图的实现
分析:点击图片的present一个控制器用来展示大图,和起对象处于哪一张,所以点击的时候需要把大图的数组和图片对应的索引传递给首页的控制。由于View的层级超过了三层,我们就不用闭包了,采用通知的形式。在collectionVIew的点击事件中发送通知,实现如下:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("我是图片我被点击拉")
//在这里发送通知,info中包含大图数组,和被点击图片所在的索引
let info:[String:AnyObject] = [YJLargeURLSkey:largeURLs!,YJIndexKey:indexPath]
NSNotificationCenter.defaultCenter().postNotificationName(YJShowPhotoBrowerNotification, object: nil, userInfo: info)
}
在主控制器注册通知
// 注册显示图片浏览器的通知
NSNotificationCenter.defaultCenter().addObserverForName(YJShowPhotoBrowerNotification, object: nil, queue: nil) { (notice) in
if let info = notice.userInfo {
//通知处理
let photoBrowserVC = YJPhotoBrowseViewController()
photoBrowserVC.sourceImageURLs = info[YJLargeURLSkey] as?[NSURL]
photoBrowserVC.clickIndex = (info[YJIndexKey] as! NSIndexPath).row
self.presentViewController(photoBrowserVC, animated: true, completion: nil)
}
}
注意记得移除通知
//MARK: 移除通知
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
YJPhotoBrowseViewController的实现,也是collectinVIew来实现。
定义两个变量,一个是图片数组,还有就是记录被点击图片的索引
// 图片数组
var sourceImageURLs:[NSURL]?{
didSet {
collectView.contentSize = CGSizeMake(CGFloat(sourceImageURLs!.count)*UIScreen.mainScreen().bounds.size.width, UIScreen.mainScreen().bounds.size.height)
}
}
// 点击图片的所在索引
var clickIndex:Int? {
didSet {
topLabel.text = "\(clickIndex! + 1)/\(sourceImageURLs!.count)"
let offSetX = (CGFloat(clickIndex!)*UIScreen.mainScreen().bounds.size.width)
print(offSetX)
collectView.contentOffset = CGPointMake(offSetX, 0)
}
}
在图片的didSet中设置collectionVIew的contensize,在索引didSet中设置contenOffset。
大图的展示和图片比较大的显示进度的图片处理
var photoURL:NSURL?{
didSet {
// 重置起状态
reset()
// 下载图片
SDWebImageManager.sharedManager().downloadWithURL(photoURL, options: SDWebImageOptions.HighPriority, progress:{ (totalSize, receiveSize) in
SVProgressHUD.showProgress(Float(receiveSize)/Float(totalSize))
if totalSize == receiveSize {
SVProgressHUD.dismiss()
}
}) { (originImage, _, _, _) in
if originImage == nil {
return
}
let originWidth = originImage.size.width
let originHeight = originImage.size.height
let screenWidth = UIScreen.mainScreen().bounds.size.width
let screenHeight = UIScreen.mainScreen().bounds.size.height
let realImageHeight = (originWidth/originHeight)*screenWidth
if realImageHeight<screenHeight {
self.photeImageView.frame = CGRectMake(0, (screenHeight - realImageHeight)*0.5, screenWidth , realImageHeight)
}else {
self.photeImageView.frame = CGRectMake(0, 0, screenWidth, originHeight)
self.backScrollView.contentSize = CGSizeMake(screenWidth, realImageHeight)
}
self.photeImageView.image = originImage
}
}
}
点击图片dimiss和长按保存的实现,给图片添加分别添加一个tap手势和长按手势,然后通过闭包传递事件给YJPhotoBrowseViewController
首先定义两个闭包
//图片单击一闭包
var imageClick:(()->())?
//图片长按闭包,传递需要保存的图片参数
var imageLongPress:((saveImage:UIImage)->())?
给图片添加tap和长按手势
//图片添加一个点击事件
let tap = UITapGestureRecognizer.init(target: self, action: "tapClick")
photeImageView.userInteractionEnabled = true
photeImageView.addGestureRecognizer(tap)
//给图片添加一个长按手势
let longPressGesture = UILongPressGestureRecognizer.init(target: self, action: "longPressAction:")
photeImageView.addGestureRecognizer(longPressGesture)
事件方法
//MARK:点击事件
func tapClick() {
imageClick?()
}
//MARK:长按点击事件
func longPressAction(longPressGeture:UILongPressGestureRecognizer){
let clickImageView = longPressGeture.view as! UIImageView
if longPressGeture.state == .Ended {
//长按收拾结束哦
print("长按保存图片可以吗")
imageLongPress?(saveImage:clickImageView.image!)
}
}
在控制返回cell进行事件处理
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectView.dequeueReusableCellWithReuseIdentifier(YJPhotoBrowseViewReuseID, forIndexPath: indexPath) as! YJPhotoBrowserCell
cell.backgroundColor = UIColor.yj_randomColor()
cell.photoURL = sourceImageURLs![indexPath.row]
// 图片的点击事件
cell.imageClick = {
//dismiss
self.dismissViewControllerAnimated(true, completion: nil)
}
// 长按保存图片的点击事件
cell.imageLongPress = {
(saveImage:UIImage)->() in
self.saveImage = saveImage
//保存图片到相册
let alertView = UIAlertView()
alertView.message = "保存图片到相册?"
alertView.addButtonWithTitle("取消")
alertView.addButtonWithTitle("保存")
alertView.delegate = self
alertView.show()
}
return cell
}
保存图片的方法如下
UIImageWriteToSavedPhotosAlbum(saveImage!, self, "image:didFinishSavingWithError:contextInfo:", nil)
保存的结果OC中会在该方法中回调, - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
坑爹的事没有swift方法函数,我们只能直接将OC方法改成swift中的写法,处理如下。
func image(image:(UIImage),didFinishSavingWithError error:(NSError?) ,contextInfo:(AnyObject)){
if error != nil {
SVProgressHUD.showErrorWithStatus("保存失败", maskType: SVProgressHUDMaskType.Black)
}
else {
SVProgressHUD.showSuccessWithStatus("保存成功", maskType: SVProgressHUDMaskType.Black)
}
}
还有图片的缩放,我是利用了UIScorllView的缩放来实现。