swift图片浏览器

2016-08-23  本文已影响1552人  07212a79db66

先看运行效果:

1. UIPageViewController简介

它是iOS 5.0之后提供的一个分页控件可以实现图片轮播效果和翻书效果.使用起来也很简单方便.先来了解一下UIPageViewController,新建工程查看官方示例Demo,新建完成直接运行起来

在RootViewController里面可以看到其实现的核心代码


override func viewDidLoad() {
        super.viewDidLoad()

        self.pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
        self.pageViewController!.delegate = self

        //设置子控制器,并且指定翻页的方向
        let startingViewController: DataViewController = self.modelController.viewControllerAtIndex(0, storyboard: self.storyboard!)!
        let viewControllers = [startingViewController]
        self.pageViewController!.setViewControllers(viewControllers, direction: .forward, animated: false, completion: {done in })

        //设置数据源代理
        self.pageViewController!.dataSource = self.modelController

        //添加子控制器和子控制器视图
        self.addChildViewController(self.pageViewController!)
        self.view.addSubview(self.pageViewController!.view)

        // Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
        var pageViewRect = self.view.bounds
        if UIDevice.current().userInterfaceIdiom == .pad {
            pageViewRect = pageViewRect.insetBy(dx: 40.0, dy: 40.0)
        }
        self.pageViewController!.view.frame = pageViewRect
        //完成添加子控制器
        self.pageViewController!.didMove(toParentViewController: self)
    }

在初始化方法中我们可以设置不同的参数使其展现不同的样式


self.pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)

各个参数的大概说明

第一个参数transitionStyle为一个枚举值,展现不同的样式

public enum UIPageViewControllerTransitionStyle : Int {

    
    case pageCurl // Navigate between views via a page curl transition.

    case scroll // Navigate between views by scrolling.
}

第二各参数navigationOrientation,也是一个枚举

public enum UIPageViewControllerNavigationOrientation : Int {

    case horizontal

    case vertical
}

第三个参数options,是一个字典,实现图片浏览器的时候给它赋值之后可以看到图片左右滑动的时候两张图片之间的间隔

2. UIPageViewController的数据源代理

 /**
     返回前一页控制器,viewController指当前显示的控制器,如果返回为nil说明滑动到头了
     */
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        var index = self.indexOfViewController(viewController as! DataViewController)
        if (index == 0) || (index == NSNotFound) {
            return nil
        }
        
        index -= 1
        return self.viewControllerAtIndex(index, storyboard: viewController.storyboard!)
    }

    /**
     返回前一页控制器,viewController指当前显示的控制器,如果返回为nil说明滑动到尾了
     */
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        var index = self.indexOfViewController(viewController as! DataViewController)
        if index == NSNotFound {
            return nil
        }
        
        index += 1
        if index == self.pageData.count {
            return nil
        }
        return self.viewControllerAtIndex(index, storyboard: viewController.storyboard!)
    }

2. 图片浏览器的实现代码

import UIKit

class ScanViewController: UIViewController {

    //:MARK - 属性
    ///选中照片的索引
    private let selectedIndex:Int
    ///图片的url字符串数组
    private let urls:[URL]
    
    init(selectIndex: Int, urls: [URL]) {
        self.selectedIndex = selectIndex
        self.urls = urls
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setUpUI()
        NotificationCenter.default().addObserver(self, selector: #selector(ScanViewController.tapAction), name: "notify", object: nil)
    }

    deinit {
       NotificationCenter.default().removeObserver(self)
    }
    
    func tapAction()  {
        dismiss(animated: true, completion: nil)
    }


    
}

extension ScanViewController {
    
    @objc private func setUpUI() {
        
        view.backgroundColor = UIColor.black()
        

        //1 实例化分页控制器
        let pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: [UIPageViewControllerOptionInterPageSpacingKey:20])
        
        pageViewController.dataSource = self
        
        let viewer = PhotoViewController(photoIndex: selectedIndex, photoUrl: urls[selectedIndex], count: urls.count)
        
        pageViewController.setViewControllers([viewer], direction: .forward, animated: false, completion: nil)
        
        view.addSubview(pageViewController.view)
        addChildViewController(pageViewController)
        pageViewController.didMove(toParentViewController: self)
        
        view.gestureRecognizers = pageViewController.gestureRecognizers
        
        let tap = UITapGestureRecognizer(target: self, action: #selector(ScanViewController.tapAction))
        tap.numberOfTapsRequired = 1
        view.addGestureRecognizer(tap)
    }
}


extension ScanViewController: UIPageViewControllerDataSource {
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {

        //从控制器取出当前照片的索引
        var index = (viewController as! PhotoViewController).photoIndex
        //判断是否到头
        index += 1
        
        if index >= urls.count {
            return nil
        }
        return PhotoViewController(photoIndex: index, photoUrl:urls[index], count: urls.count)
        
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        //从控制器取出当前照片的索引
        var index = (viewController as! PhotoViewController).photoIndex
        
        //判断是否到头
        if index == NSNotFound {
            return nil
        }
        index -= 1
        if index <= 0 {
            return nil
        }
        return PhotoViewController(photoIndex: index, photoUrl:urls[index], count: urls.count)
    }
}

图片浏览器页面PhotoViewController.swift

import UIKit
import SDWebImage

class PhotoViewController: UIViewController {

    
    //:MARK - 属性和控件
    private lazy var scrollview = UIScrollView()
    private lazy var imageView = UIImageView()
    var photoIndex: Int
    var photoUrl:URL?
    var count: Int
    var recordImage:UIImage?
    ///是否双击图片
    var isClick:Bool = false

    init(photoIndex: Int, photoUrl:URL, count: Int) {
        self.photoIndex = photoIndex
        self.photoUrl = photoUrl
        self.count = count
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        setupIU()

    }
    
    @objc private func setupIU() {
        view.addSubview(scrollview)
        scrollview.addSubview(imageView)
        scrollview.backgroundColor = UIColor.clear()
        view.addSubview(titleLabel)
        self.titleLabel.text = "\(photoIndex)/\(count)"
        
        scrollview.delegate = self
        scrollview.maximumZoomScale = 4.0
        scrollview.minimumZoomScale = 0.5
        scrollview.showsVerticalScrollIndicator = false
        scrollview.showsHorizontalScrollIndicator = false
        

        imageView.isUserInteractionEnabled = true
        let tapTwo = UITapGestureRecognizer(target: self, action: #selector(PhotoViewController.handleDouble(recongnizer:)))
        tapTwo.numberOfTapsRequired = 2
        imageView.addGestureRecognizer(tapTwo)
        
        let tapOne = UITapGestureRecognizer(target: self, action: #selector(PhotoViewController.handleOneClick(recongnizer:)))
        tapOne.numberOfTapsRequired = 1
        imageView.addGestureRecognizer(tapOne)
        
        //当没有检测到双击 或者 检测双击失败,单击才有效
        tapOne.require(toFail: tapTwo)

        loadImage()
    }
    
    func handleOneClick(recongnizer:UITapGestureRecognizer) {
        if isClick == true {
            UIView.animate(withDuration: 0.3, animations: {
                self.scrollview.zoomScale = 0
                self.setImageViewPosition(image: self.recordImage!)
            })
            isClick = false
            return
        }
      NotificationCenter.default().post(name: "notify" as NSNotification.Name, object: nil)
        
    }

    /// 双击图片的处理
    func handleDouble(recongnizer:UITapGestureRecognizer) {

            let status = recongnizer.state
            if isClick == false {
                switch status {
                case .began: break
                case .changed: break
                case .cancelled: break
                case .ended:
                    //以点击的点为中心,放大图片
                    let  point = recongnizer.location(in: recongnizer.view)
                    let zoom = scrollview.zoomScale > 0 ? true : false
                    let scale = zoom ? scrollview.maximumZoomScale : scrollview.minimumZoomScale
                    
                    UIView.animate(withDuration: 0.3, animations: {
                        self.scrollview.zoomScale  = scale
                        if zoom {
                            var x = point.x * scale - self.scrollview.bounds.size.width/2
                            let maxX = self.scrollview.contentSize.width - self.scrollview.bounds.size.width
                            let minX = CGFloat.leastNormalMagnitude
                            x = x > maxX ? maxX : x
                            x = x < minX ? minX : x 
                            var y = point.y * scale - self.scrollview.bounds.size.height * 0.5
                            let maxY = self.scrollview.contentSize.height - self.scrollview.bounds.size.height
                            let minY = CGFloat.leastNormalMagnitude
                            y = y > maxY ? maxY : y
                            y = y < minY ? minY : y
                            self.scrollview.contentOffset = CGPoint(x: x, y: y)
                        }
                    })
                    isClick = true
                default:
                    break
                }
                
            }else{
                switch status {
                case .began: break
                case .changed: break
                case .cancelled: break
                case .ended:
                    UIView.animate(withDuration: 0.3, animations: {
                        self.scrollview.zoomScale = 0
                        self.setImageViewPosition(image: self.recordImage!)
                    })
                    isClick = false
                default:
                    break
                }
            }
    }
    

    func loadImage()  {
        imageView.sd_setImage(with: photoUrl) { (image, error, _, _) in
            guard let image = image else {
            return
            }
            //设置图像视图的大小
            self.setImageViewPosition(image: image)
            self.recordImage = image
        }
    }
    
    func setImageViewPosition(image:UIImage) {
        
        let size = imageSizeWithScreen(image: image)
        imageView.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        scrollview.frame = UIScreen.main().bounds
        scrollview.contentSize = size

        if size.height < scrollview.bounds.size.height {
            titleLabel.isHidden = false
            
            imageView.frame.origin.y = (scrollview.bounds.size.height - size.height) * 0.5
        }else{
            titleLabel.isHidden = true
        }
    
    }
    
    func imageSizeWithScreen(image:UIImage) -> CGSize {
        var size = UIScreen.main().bounds.size
        size.height = image.size.height * size.width / image.size.width
        return size
    }
    
    private lazy var titleLabel:UILabel = {
    let tip = UILabel()
    tip.frame = CGRect(x: (screenWidth - 100) * 0.5, y: 20, width: 100, height: 20)
    tip.textColor = UIColor.white()
     tip.textAlignment = NSTextAlignment.center
    return tip
    }()
    
}

extension PhotoViewController:UIScrollViewDelegate {
    //指定缩放UIScrolleView时,缩放UIImageView来适配
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }
    
    //缩放后让图片显示到屏幕中间
    func scrollViewDidZoom(_ scrollView: UIScrollView) {
            let originalSize = scrollView.bounds.size;
            let contentSize = scrollView.contentSize;
            let offsetX = originalSize.width > contentSize.width ? (originalSize.width-contentSize.width)/2 : 0
            let offsetY = originalSize.height > contentSize.height ? (originalSize.height-contentSize.height)/2 : 0
            self.imageView.center = CGPoint(x: contentSize.width/2+offsetX, y: contentSize.height/2+offsetY)
    }
    
}

上一篇下一篇

猜你喜欢

热点阅读