Swift 4 放大镜功能实现

先上效果图吧,框框被限制在了image内了。

这个feature我把它用在了我的app里了,博客写得不容易,来star下啦🙏 https://github.com/Imputes/Nike-Collection/


## 就好像Ray Wenderlich的iOS Apprentice一书说的一样,要实现任何feature都要列个任务清单。所以我们先列个任务清单: ## 1. 实现把一个可拖动的View限制在一个特定的View里。 ## 2. 实现把框到的image放大。

## 首先讲第一点: ## 既然要实现拖动的feature,Google之后就知道Cocoa Touch框架里的UIKit module里有一个UIPanGestureRecognizer类,有了这个类之后就可以实现拖拽feature了。 ## 那么Google之后又知道了有两种方式: ## 一种是纯代码(在要放大的View所在的controller里或者view里, 在willAppear时刻或者didLoad时刻或者layoutSubView时刻写上, xxxView是拖拽的View): ```swift let panGesture = UIPanGestureRecognizer.init(target: self, action: #selector(handlePan(sender: ))) xxxView.addGestureRecognizer(panGesture) ``` ## 之后再在放大的View所在的类中写selector, 就是观察者panGestureRecognizer观察到被观察者(在这里是要拖拽的View)的变化之后执行的function。 ```swift @objc func handlePan(sender: UIPanGestureRecognizer) { ... } ```
##另一种是直接在storyboard里面拖panGesture到要拖拽的view上即可,再用IBAction连接到代码里,这个Action里写的东西和前面的handlePan一样。

## 那么如何限制在所在view里呢? ## Easy playing! 只要在action里添加(assistView是铺在上面的UIView,): ```swift let transition = sender.translation(in: self.assistView) let changeX = (sender.view?.center.x)! + transition.x let changeY = (sender.view?.center.y)! + transition.y var limitCenter = CGPoint.init(x: changeX, y: changeY) limitCenter.y = max((sender.view?.frame.size.height)! / 2, limitCenter.y) limitCenter.y = min(self.assistView.frame.size.height - (sender.view?.frame.size.height)! / 2, limitCenter.y) limitCenter.x = max((sender.view?.frame.size.width)! / 2, limitCenter.x) limitCenter.x = min(self.assistView.frame.size.width - (sender.view?.frame.size.width)! / 2, limitCenter.x) sender.view?.center = limitCenter sender.setTranslation(CGPoint.zero, in: self.assistView) ``` ## 到了这一步之后就可以把这个view限制在imageView里了。 ## 至此第一步实现。

## 那么第二步就简单了(因为可以直接Google到), ## 在所在类里写上这两个functions: ```swift private func snapshotTargetView(view: UIView!, inRect rect: CGRect!) -> UIImage! { let scale = UIScreen.main.scale
    //Snapshot of view
    UIGraphicsBeginImageContextWithOptions(rect.size, false, scale)
    UIGraphicsGetCurrentContext()?.translateBy(x: -rect.origin.x, y: -rect.origin.y)
    view.layer.render(in: UIGraphicsGetCurrentContext()!)
    
    //Need this to stop screen flashing, but it's slower
    let snapshotImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return snapshotImage
}

private func resizeImage(image: UIImage, toNewSize newSize:CGSize) -> UIImage {
    let scale = UIScreen.main.scale
    
    UIGraphicsBeginImageContextWithOptions(newSize, false, scale)
    image.draw(in: CGRect(x:0, y:0, width:newSize.width, height:newSize.height))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage!

}

## 再在Action里加上这两句(resultImageView是放大后要put的地方):
```swift
 let transition = sender.translation(in: self.assistView)
        let changeX = (sender.view?.center.x)! + transition.x
        let changeY = (sender.view?.center.y)! + transition.y
        var limitCenter = CGPoint.init(x: changeX, y: changeY)
        limitCenter.y = max((sender.view?.frame.size.height)! / 2, limitCenter.y)
        limitCenter.y = min(self.assistView.frame.size.height - (sender.view?.frame.size.height)! / 2, limitCenter.y)
        limitCenter.x = max((sender.view?.frame.size.width)! / 2, limitCenter.x)
        limitCenter.x = min(self.assistView.frame.size.width - (sender.view?.frame.size.width)! / 2, limitCenter.x)
        sender.view?.center = limitCenter
        sender.setTranslation(CGPoint.zero, in: self.assistView)

        // add this two lines
        let imges = snapshotTargetView(view: self.productImageView, inRect: sender.view?.frame)
        resultImageView.image = resizeImage(image: images!, toNewSize: resultImageView.frame.size)

OK了😊。

效果:

posted @ 2018-03-17 20:31  0x5f375a86  阅读(907)  评论(1编辑  收藏  举报