下载大图和绘制进度

/// 照片查看视图控制器 class PhotoBrowserViewController: UIViewController { /// 图像 URL 数组 var urls: [NSURL] /// 选中照片索引 var selectedIndexPath: NSIndexPath // MARK: - 构造函数 init(urls: [NSURL], indexPath: NSIndexPath) { self.urls = urls self.selectedIndexPath = indexPath super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }

  • 在 HomeTableViewController 加载照片查看视图控制器,并且传递数据
// 注册通知
NSNotificationCenter.defaultCenter().addObserverForName(WBStatusSelectedPhotoNotification,
    object: nil,
    queue: nil) { [weak self] (n) -> Void in

        guard let urls = n.userInfo?[WBStatusSelectedPhotoURLKey] as? [NSURL] else {
            return
        }
        guard let indexPath = n.userInfo?[WBStatusSelectedPhotoIndexPathKey] as? NSIndexPath else {
            return
        }

        let vc = PhotoBrowserViewController(urls: urls, indexPath: indexPath)
        self?.presentViewController(vc, animated: true, completion: nil)
}

搭建界面

  • 在 UIButton+Extension 中扩展便利构造函数
/// 便利构造函数
///
/// - parameter title:     title
/// - parameter color:     color
/// - parameter fontSize:  字体大小
/// - parameter imageName: 图像名称
/// - parameter backColor: 背景颜色
///
/// - returns: UIButton
convenience init(title: String, fontSize: CGFloat, color: UIColor, imageName: String?, backColor: UIColor? = nil) {
    self.init()

    setTitle(title, forState: .Normal)
    setTitleColor(color, forState: .Normal)

    if let imageName = imageName {
        setImage(UIImage(named: imageName), forState: .Normal)
    }

    titleLabel?.font = UIFont.systemFontOfSize(fontSize)
    backgroundColor = backColor

    sizeToFit()
}

  • 懒加载控件
// MARK: - 懒加载控件
/// collectionView
private var collectionView: UICollectionView = UICollectionView(frame: CGRectZero,
    collectionViewLayout: UICollectionViewFlowLayout())
/// 关闭按钮
private var closeButton: UIButton = UIButton(title: "关闭",
    fontSize: 14,
    color: UIColor.whiteColor(),
    imageName: nil,
    backColor: UIColor.darkGrayColor())
/// 保存按钮
private var saveButton: UIButton = UIButton(title: "保存",
    fontSize: 14,
    color: UIColor.whiteColor(),
    imageName: nil,
    backColor: UIColor.darkGrayColor())

  • 设置界面
override func loadView() {
    let rect = UIScreen.mainScreen().bounds

    view = UIView(frame: rect)

    setupUI()
}

  • 设置界面扩展
// MARK: - 设置界面
private extension PhotoBrowserViewController {

    private func setupUI() {
        // 1. 添加控件
        view.addSubview(collectionView)
        view.addSubview(closeButton)
        view.addSubview(saveButton)

        // 2. 控件布局
        collectionView.frame = view.bounds

        closeButton.snp_makeConstraints { (make) -> Void in
            make.bottom.equalTo(view.snp_bottom).offset(-8)
            make.left.equalTo(view.snp_left).offset(8)
            make.size.equalTo(CGSize(width: 100, height: 36))
        }
        saveButton.snp_makeConstraints { (make) -> Void in
            make.bottom.equalTo(view.snp_bottom).offset(-8)
            make.right.equalTo(view.snp_right).offset(-8)
            make.size.equalTo(CGSize(width: 100, height: 36))
        }
    }
}

  • 按钮监听方法
// MARK: - 监听方法
/// 关闭
@objc private func close() {
    dismissViewControllerAnimated(true, completion: nil)
}

/// 保存照片
@objc private func save() {
    print("保存照片")
}

  • 添加按钮监听
// 3. 监听方法
closeButton.addTarget(self, action: "close", forControlEvents: .TouchUpInside)
saveButton.addTarget(self, action: "save", forControlEvents: .TouchUpInside)

数据源方法

  • 定义可重用标识符号常量
/// 可重用标识符号
private let PhotoBrowserViewCellId = "PhotoBrowserViewCellId"

  • 定义 照片查看 Cell
// MARK: - 照片查看 Cell
private class PhotoBrowserCell: UICollectionViewCell {

}

  • 设置数据源
// 4. 准备控件
    prepareCollectionView()
}

/// 准备 CollectionView
private func prepareCollectionView() {
    // 1. 设置数据源
    collectionView.dataSource = self

    // 2. 注册可重用 cell
    collectionView.registerClass(PhotoBrowserCell.self, forCellWithReuseIdentifier: PhotoBrowserViewCellId)
}

  • 利用 extension 扩展数据源方法
// MARK: - UICollectionViewDataSource
extension PhotoBrowserViewController: UICollectionViewDataSource {

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return urls.count
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(PhotoBrowserViewCellId, forIndexPath: indexPath) as! PhotoBrowserCell

        cell.backgroundColor = UIColor.redColor()

        return cell
    }
}

  • 设置布局
// MARK: - 照片浏览视图布局
private class PhotoBrowserViewLayout: UICollectionViewFlowLayout {

    private override func prepareLayout() {
        super.prepareLayout()

        itemSize = collectionView!.bounds.size
        minimumInteritemSpacing = 0
        minimumLineSpacing = 0

        scrollDirection = .Horizontal

        collectionView?.pagingEnabled = true
        collectionView?.showsHorizontalScrollIndicator = false
        collectionView?.bounces = false
    }
}

  • 添加 UIColor+Extension
extension UIColor {

    /// 随机颜色
    class func randomColor() -> UIColor {

        let r = CGFloat(random() % 256) / 255
        let g = CGFloat(random() % 256) / 255
        let b = CGFloat(random() % 256) / 255

        return UIColor(red: r, green: g, blue: b, alpha: 1.0)
    }
}

  • 数据源方法
cell.backgroundColor = UIColor.randomColor()

 
  • 主要内容1. 正则表达式2. 照片查看器
    • 2.1. 选择照片事件传递2.2. 照片查看器界面搭建2.3. 照片查看 Cell2.4. 照片间距2.5. 细节处理2.6. 保存照片2.7. 点击照片关闭控制器2.8. 转场动画2.9. 转场进阶
  • Published using GitBook
 
 

照片浏览器

2.3照片查看 Cell

准备工作

  • 新建 PhotoBrowserCell
  • 定义内部控件
// MARK: - 照片查看 Cell
class PhotoBrowserCell: UICollectionViewCell {

    // MARK: - 构造函数
    override init(frame: CGRect) {
        super.init(frame: frame)

        setupUI()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setupUI() {
        // 1. 添加控件
        contentView.addSubview(scrollView)
        scrollView.addSubview(imageView)

        // 2. 设置位置
        scrollView.frame = bounds
    }

    // MARK: - 懒加载控件
    /// 滚动视图
    private lazy var scrollView: UIScrollView = UIScrollView()
    /// 图像视图
    private lazy var imageView: UIImageView = UIImageView()
}

设置图像

  • 错误的设置图像

var imageURL: NSURL? {
    didSet {
        imageView.sd_setImageWithURL(imageURL!)
    }
}

设置图像后,imageView 的 frame 没有计算

  • 修改设置图像代码
/// 图像 URL
var imageURL: NSURL? {
    didSet {
        imageView.sd_setImageWithURL(imageURL, placeholderImage: nil) { image, _, _, _ in
            self.imageView.sizeToFit()
        }
    }
}

图像非常小,原因:在微博首页显示的图片是缩略图

  • 新建函数处理 imageURL
/// 创建大图 URL
///
/// - parameter url: 缩略图 URL
///
/// - returns: 中图 URL
private func middleUrl(url: NSURL) -> NSURL {
    var urlString = url.absoluteString
    urlString = urlString.stringByReplacingOccurrencesOfString("/thumbnail/", withString: "/bmiddle/")

    return NSURL(string: urlString)!
}

  • 修改 didSet 函数
/// 图像 URL
var imageURL: NSURL? {
    didSet {

        guard let url = imageURL else {
            return
        }

        // 用缩略图当作占位视图
        let key = url.absoluteString
        imageView.image = SDWebImageManager.sharedManager().imageCache.imageFromDiskCacheForKey(key)
        imageView.sizeToFit()
        imageView.center = scrollView.center

        imageView.sd_setImageWithURL(middleUrl(imageURL!),
            placeholderImage: nil) { image, _, _, _ in

                delay(1.0, callFunc: { () -> () in
                    self.imageView.center = CGPointZero
                    self.imageView.sizeToFit()
                })
        }
    }
}

计算长短图

  • 以 cell 宽度为基准计算显示尺寸
/// 计算图像显示大小
///
/// - parameter image: 图像
///
/// - returns: 以 ScrollView 宽度为基准的图像大小
private func displaySize(image: UIImage) -> CGSize {

    let w = scrollView.bounds.width
    let h = image.size.height * w / image.size.width

    return CGSize(width: w, height: h)
}

  • 在回调代码中重新设置 imageView 的 size
imageView.sd_setImageWithURL(middleUrl(imageURL!),
    placeholderImage: nil) { image, _, _, _ in

        if image == nil {
            SVProgressHUD.showInfoWithStatus("加载图像失败")
            return
        }

        delay(1.0, callFunc: { () -> () in
            self.imageView.center = CGPointZero
            self.imageView.frame = CGRect(origin: CGPointZero, size: self.displaySize(image))
        })
}

提示:此处一定加上图像加载判断,因为 SDWebImage 的超时时长是 15s,一旦超时,图像就会加载失败

  • 计算图片位置
/// 设置图像位置
///
/// * 如果是长图,顶端对齐
/// * 如果是短图,居中显示
private func setImagePosition(image: UIImage) {

    // 1. 计算图像显示大小
    let size = displaySize(image)
    scrollView.contentSize = size

    // 2. 判断图像高度
    if size.height > scrollView.bounds.height {
        imageView.frame = CGRect(origin: CGPointZero, size: size)
    } else {
        let y = (scrollView.bounds.height - size.height) * 0.5
        imageView.frame = CGRect(x: 0, y: y, width: size.width, height: size.height)
    }
}

  • 长图增加 contentSize 保证图像能够滚动
scrollView.contentSize = size

  • 修改 imageURL 的 didSet
self.setImagePosition()

运行测试

缩放处理

  • 设置滚动视图
/// 准备滚动视图
private func prepareScrollView() {
    scrollView.delegate = self
    scrollView.minimumZoomScale = 0.5
    scrollView.maximumZoomScale = 2.0
}

  • 实现代理方法
// MARK: - UIScrollViewDelegate
extension PhotoBrowserCell: UIScrollViewDelegate {

    /// 返回要缩放的视图
    func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
        return imageView
    }

    /// 缩放完成后才回被调用
    ///
    /// - parameter scrollView: scrollView
    /// - parameter view:       被缩放的视图
    /// - parameter scale:      缩放完成的比例
    func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView?, atScale scale: CGFloat) {

    }

    // 只要缩放就会被调用
    func scrollViewDidZoom(scrollView: UIScrollView) {

    }
}

运行测试发现短图放大后,无法滚动显示底部内容

  • 调整 setImagePosition 函数,使用 contentInset 调整短图的图像视图位置
/// 设置图像位置
///
/// * 如果是长图,顶端对齐
/// * 如果是短图,居中显示
private func setImagePosition(image: UIImage) {

    // 1. 计算图像显示大小
    let size = displaySize(image)
    scrollView.contentSize = size

    // 2. 判断图像高度
    if size.height > scrollView.bounds.height {
        imageView.frame = CGRect(origin: CGPointZero, size: size)
    } else {
        imageView.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)

        let y = (scrollView.bounds.height - size.height) * 0.5
        scrollView.contentInset = UIEdgeInsets(top: y, left: 0, bottom: 0, right: 0)
    }
}

  • 缩放停止后重新调整 Y 轴位置
/// 缩放完成后才回被调用
///
/// - parameter scrollView: scrollView
/// - parameter view:       被缩放的视图
/// - parameter scale:      缩放完成的比例
func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView?, atScale scale: CGFloat) {

    var offsetY = (scrollView.bounds.height - view!.frame.height) * 0.5

    offsetY = offsetY < 0 ? 0 : offsetY

    scrollView.contentInset = UIEdgeInsets(top: offsetY, left: 0, bottom: 0, right: 0)
}

注意:使用 transform 修改视图大小时,bounds 本身不会发生变化,而 frame 会发生变化

  • 增加水平方向位置调整
/// 缩放完成后才回被调用
///
/// - parameter scrollView: scrollView
/// - parameter view:       被缩放的视图
/// - parameter scale:      缩放完成的比例
func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView?, atScale scale: CGFloat) {

    var offsetY = (scrollView.bounds.height - view!.frame.height) * 0.5
    var offsetX = (scrollView.bounds.width - view!.frame.width) * 0.5

    offsetY = offsetY < 0 ? 0 : offsetY
    offsetX = offsetX < 0 ? 0 : offsetX

    scrollView.contentInset = UIEdgeInsets(top: offsetY, left: offsetX, bottom: 0, right: 0)
}

  • 图像缩放比例复位,以及滚动视图内容属性
/// 重置滚动视图
private func resetScrollView() {
    imageView.transform = CGAffineTransformIdentity

    scrollView.contentInset = UIEdgeInsetsZero
    scrollView.contentOffset = CGPointZero
    scrollView.contentSize = CGSizeZero
}

  • 最终完成的 imageURL 属性
/// 图像 URL
var imageURL: NSURL? {
    didSet {

        guard let url = imageURL else {
            return
        }

        // 重置滚动视图
        resetScrollView()


        // 用缩略图当作占位视图
        let key = url.absoluteString
        imageView.image = SDWebImageManager.sharedManager().imageCache.imageFromDiskCacheForKey(key)
        imageView.sizeToFit()
        imageView.center = scrollView.center

        imageView.sd_setImageWithURL(middleUrl(imageURL!),
            placeholderImage: nil,
            options: [SDWebImageOptions.RetryFailed, SDWebImageOptions.RefreshCached],
            progress: { (current, total) -> Void in

                dispatch_async(dispatch_get_main_queue()) {
                    self.imageView.progress = CGFloat(current) / CGFloat(total)
                }

            }) { (image, _, _, _) in

                if image == nil {
                    SVProgressHUD.showInfoWithStatus("加载图像失败")
                    return
                }

                self.setImagePosition(image)
        }
    }
}

转载于:https://www.cnblogs.com/hxmShy/p/6685814.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值