从Swift中的掩码独立移动UIImageView

时间:2016-05-17 22:02:45

标签: ios swift uiimageview mask

我试图以这样的方式屏蔽UIImageView,它允许用户在不移动其蒙版的情况下拖动图像。效果类似于人们如何在Instagram应用程序中定位图像,基本上允许用户定义图像的裁剪区域。

这是一个动画GIF,用于演示我之后的所作所为。

enter image description here

这是我目前如何屏蔽图像并将其重新定位在拖动/平移事件上。

import UIKit

class ViewController: UIViewController {

    var dragDelta = CGPoint()
    @IBOutlet weak var imageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()
        attachMask()
    // listen for pan/drag events //
        let pan = UIPanGestureRecognizer(target:self, action:#selector(onPanGesture))
        pan.maximumNumberOfTouches = 1
        pan.minimumNumberOfTouches = 1
        self.view.addGestureRecognizer(pan)
    }

    func onPanGesture(gesture:UIPanGestureRecognizer)
    {
        let point:CGPoint = gesture.locationInView(self.view)
        if (gesture.state == .Began){
            print("begin", point)
        // capture our drag start position
            dragDelta = CGPoint(x:point.x-imageView.frame.origin.x, y:point.y-imageView.frame.origin.y)
        }   else if (gesture.state == .Changed){
        // update image position based on how far we've dragged from drag start
            imageView.frame.origin.y = point.y - dragDelta.y
        }   else if (gesture.state == .Ended){
            print("ended", point)
        }
    }

    func attachMask()
    {
        let mask = CAShapeLayer()
        mask.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 100, width: imageView.frame.size.width, height: 400), cornerRadius: 5).CGPath
        mask.anchorPoint = CGPoint(x: 0, y: 0)
        mask.fillColor = UIColor.redColor().CGColor
        view.layer.addSublayer(mask)
        imageView.layer.mask = mask;
    }
}

这会导致图像和蒙版一起移动,如下所示。 关于如何锁定"的任何建议这个面具可以在它下面独立移动,非常感谢。

enter image description here

3 个答案:

答案 0 :(得分:2)

将面具和框架彼此分开移动以达到此效果并不是实现此目的的最佳方式。大多数执行此类效果的应用都会执行以下操作:

  1. 将UIScrollView添加到根视图(启用平移/缩放)
  2. 将UIImageView添加到UIScrollView
  3. 调整UIImageView的大小,使其与图像的比例为1:1
  4. 设置UIScrollView的contentSize以匹配UIImageView
  5. 的内容

    用户现在可以根据需要平移并放大UIImageView。

    接下来,如果您正在裁剪图像:

    1. 获取可见矩形(取自Getting the visible rect of an UIScrollView's content

      CGRect visibleRect = [scrollView convertRect:scrollView.bounds toView:zoomedSubview];

    2. 在UIImage上使用您喜欢的任何裁剪方法来获取必要的内容。

    3. 这是处理这种交互的最流畅的方式,代码保持非常简单!

答案 1 :(得分:1)

刚想通了。将CAShapeLayer的position属性设置为拖动时UIImageView位置的倒数将将CAShapeLayer锁定在其原始位置,但默认情况下,CoreAnimation会在重新分配位置时尝试对其进行动画处理。

可以通过将两个位置设置包装在CATransaction中来禁用此功能,如下所示。

func onPanGesture(gesture:UIPanGestureRecognizer)
{
    let point:CGPoint = gesture.locationInView(self.view)
    if (gesture.state == .Began){
        print("begin", point)
    // capture our drag start position
        dragDelta = CGPoint(x:point.x-imageView.frame.origin.x, y:point.y-imageView.frame.origin.y)
    }   else if (gesture.state == .Changed){
    // update image & mask positions based on the distance dragged 
    // and wrap both assignments in a CATransaction transaction to disable animations
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        mask.position.y = dragDelta.y - point.y
        imageView.frame.origin.y = point.y - dragDelta.y
        CATransaction.commit()
    }   else if (gesture.state == .Ended){
        print("ended", point)
    }
}

<强>更新

这是我相信AlexKoren建议的实现。此方法在UIScrollView中嵌套UIImageView,并使用UIScrollView来屏蔽图像。

class ViewController: UIViewController, UIScrollViewDelegate {

    @IBOutlet weak var scrollView: UIScrollView!

    var imageView:UIImageView = UIImageView()

    override func viewDidLoad() {
        super.viewDidLoad()

        let image = UIImage(named: "point-bonitas")
        imageView.image = image
        imageView.frame = CGRectMake(0, 0, image!.size.width, image!.size.height);

        scrollView.delegate = self
        scrollView.contentMode = UIViewContentMode.Center
        scrollView.addSubview(imageView)
        scrollView.contentSize = imageView.frame.size

        let scale = scrollView.frame.size.width / scrollView.contentSize.width
        scrollView.minimumZoomScale = scale
        scrollView.maximumZoomScale = scale // set to 1 to allow zoom out to 100% of image size //
        scrollView.zoomScale = scale

    // center image vertically in scrollview //
        let offsetY:CGFloat = (scrollView.contentSize.height - scrollView.frame.size.height) / 2;
        scrollView.contentOffset = CGPointMake(0, offsetY);
    }

    func scrollViewDidZoom(scrollView: UIScrollView) {
        print("zoomed")
    }

    func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
        return imageView
    }
}

答案 2 :(得分:0)

另一种可能更简单的方法是将图像视图放在滚动视图中,让滚动视图为您管理它。它处理一切。