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)