首页 > 解决方案 > UIView 在使用 UIPanGestureRecognizer 拖动时不会移动

问题描述

我有一个名为的容器,里面装着ChartView我星球的UIImageView. 我以编程方式添加我的行星,然后我将它们分配给UIPanGestureRecognizer. 据我了解,我需要将委托转发到我的容器 ViewController 然后实现我的draggedView()功能。

我成功输入了该函数,但即使我在 draggedView() 中打印它的新位置,UIImageView 也不会在视觉上移动。我做错了什么?

**** 更新 ****

import UIKit

extension FloatingPoint {
    var degreesToRadians: Self { return self * .pi / 180 }
    var radiansToDegrees: Self { return self * 180 / .pi }
}

extension CGFloat {
    static func random() -> CGFloat {
        return CGFloat(arc4random()) / CGFloat(UInt32.max)
    }
}

extension UIColor {
    static func random() -> UIColor {
        return UIColor(red:   .random(),
                       green: .random(),
                       blue:  .random(),
                       alpha: 1)
    }
}

class FirstViewController: UIViewController, UIGestureRecognizerDelegate {


    @IBOutlet weak var chartView: ChartView!

    private var planets: [Planet] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        self.chartView.delegate = self
        self.chartView.setSegmentValues(
            values: [50, 50, 50,50,50,50,50,50,50,50,50,50],
            totals: [50, 50, 50,50,50,50,50,50,50,50,50,50])

        self.chartView.addPlanet(fullAngle: CGFloat(180),name: "test")

    }

    @objc func didPan(sender: UIPanGestureRecognizer) {
        let translation = sender.translation(in: self.view)
        if let view = sender.view {
            view.center = CGPoint(x:view.center.x + translation.x,
                                  y:view.center.y + translation.y)
        }
        sender.setTranslation(CGPoint.zero, in: self.view)
        print("Pos: \(translation.x)- \(translation.y)")
    }

}

这是图表视图:

import UIKit
import Foundation

@IBDesignable class ChartView: UIView {


    var delegate: UIGestureRecognizerDelegate?

    // Static value
    private let ELEMENT_COLOR: [UIColor] = [UIColor.red, UIColor.gray, UIColor.blue, UIColor.yellow, UIColor.cyan]

    //Values for each segment
    private var segmentValues : [Float]
    //Total for each segment
    private var segmentTotals : [Float]
    //Sum of each segmentTotals element
    private var segmentTotalAll : Float

    override init(frame: CGRect) {
        segmentValues = []
        segmentTotals = []
        segmentTotalAll = 0
        super.init(frame: frame)
        self.isUserInteractionEnabled = true
        self.backgroundColor = UIColor.clear
    }

    required init?(coder aDecoder: NSCoder) {
        segmentValues = []
        segmentTotals = []
        segmentTotalAll = 0
        super.init(coder: aDecoder)
        self.isUserInteractionEnabled = true
        self.backgroundColor = UIColor.clear
    }

    override func draw(_ rect: CGRect) {

        // Base Circle
        UIColor.random().setFill()
        let outerPath = UIBezierPath(ovalIn: rect)
        outerPath.fill()

//        Semicircles
        //self.frame isn't defined yet, so we can't use self.center
        let viewCenter = CGPoint(x: rect.width / 2, y: rect.height / 2)
        var i: Int = 0
        var lastAngle :Float = 0.0
        let baseCircleRadius = rect.width / 2 - 1.5
        let centerCircleRadius = rect.width / 2 * 0.4

        //value : current number
        for value in segmentValues {
            //total : total number
            let total = segmentTotals[i]

            //offsetTotal : difference between Base Circle and Center Circle
            let offset =  baseCircleRadius - centerCircleRadius

            //radius : radius of segment
            let radius = CGFloat(value / total) * offset + centerCircleRadius
            //startAngle : start angle of this segment
            let startAngle = lastAngle
            //endAngle : end angle of this segment
            let endAngle = lastAngle + total / segmentTotalAll * 360.0
            //color : color of the segment
            let color = self.ELEMENT_COLOR[i % 4]
            color.setFill()

            let midPath = UIBezierPath()
            midPath.move(to: viewCenter)

            midPath.addArc(withCenter: viewCenter, radius: CGFloat(radius), startAngle: CGFloat(startAngle.degreesToRadians), endAngle: CGFloat(endAngle.degreesToRadians), clockwise: true)

            midPath.close()
            UIColor.black.setStroke()
            midPath.lineWidth = 2
            midPath.stroke()
            midPath.fill()

            lastAngle = endAngle
            i += 1
        }

        //Center circle
        UIColor.white.setFill()
        let centerPath = UIBezierPath(ovalIn: rect.insetBy(dx: rect.width / 2 * 0.4, dy: rect.height / 2 * 0.4))
        UIColor.black.setStroke()
        centerPath.lineWidth = 3
        centerPath.stroke()

        centerPath.fill()
    }


    //Sets all the segment members in order to draw each segment
    func setSegmentValues(values : [Int], totals : [Int]){
        //Must be equal lengths
        if values.count != totals.count{
            return;
        }
        //Set the colors
        segmentTotalAll = 0
        for total in totals {
            segmentTotalAll += Float(total)
            segmentTotals.append(Float(total))
        }
        for val in values {
            segmentValues.append(Float(val))
        }
    }


    public func addPlanet(fullAngle: CGFloat, name: String) {

        let planetPosition: CGPoint = self.getPosition(center: CGPoint(x: self.frame.width/2, y: self.frame.height/2), radius: self.bounds.width/4, angle: fullAngle)
        let planetImageView: UIImageView = UIImageView()
        planetImageView.frame = CGRect(origin: planetPosition, size: CGSize(width: 10, height: 10))
        planetImageView.center = planetPosition
        planetImageView.backgroundColor = .blue
        self.addSubview(planetImageView)

        let panGesture = UIPanGestureRecognizer(target: self.delegate, action: #selector(FirstViewController.didPan(sender:)))
        panGesture.delegate = self.delegate
        planetImageView.isUserInteractionEnabled = true
        planetImageView.addGestureRecognizer(panGesture)

        // paint curve for sun
        let path = UIBezierPath(arcCenter: CGPoint(x: self.frame.width/2, y: self.frame.height/2), radius: self.bounds.width/4, startAngle: CGFloat(0), endAngle: fullAngle.degreesToRadians, clockwise: true)

        let animation = CAKeyframeAnimation(keyPath: #keyPath(CALayer.position))
        animation.duration = 1.5
        animation.isRemovedOnCompletion = false // do not remove the animation effect, no state changes.
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
        animation.fillMode = kCAFillModeBoth // keep to value after finishing
        animation.path = path.cgPath

        planetImageView.layer.add(animation, forKey: animation.keyPath)
    }

    private func getPosition(center: CGPoint, radius: CGFloat, angle: CGFloat) -> CGPoint {
        return CGPoint(x: center.x + radius * cos(angle.degreesToRadians), y: center.y + radius * sin(angle.degreesToRadians))
    }

    public func addCenterCircle(){
        let centerCircle = UIBezierPath(arcCenter: CGPoint(x: self.bounds.width/2,y: self.bounds.height/2), radius: self.bounds.width/4, startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)

        let shapeLayer = CAShapeLayer()
        shapeLayer.path = centerCircle.cgPath

        //change the fill color
        shapeLayer.fillColor = UIColor.white.cgColor
        //you can change the stroke color
        shapeLayer.strokeColor = UIColor.black.cgColor
        //you can change the line width
        shapeLayer.lineWidth = 1

        self.layer.addSublayer(shapeLayer)
    }
}

标签: iosswiftuigesturerecognizer

解决方案


我创建了一个简单的蓝色方块,然后添加了一个红色星球。您可以平移一个红色方块。这是以编程方式的示例。

在此处输入图像描述

import UIKit

class ViewController: UIViewController, UIGestureRecognizerDelegate {

  private lazy var chartView: ChartView = {
      let cv = ChartView(frame: CGRect(x: 0,
                                       y: 0,
                                       width: view.frame.width - 20,
                                       height: view.frame.height/2))
      cv.center = view.center
      // Important
      cv.panGesture.delegate = self
      return cv
  }()

  override func viewDidLoad() {
      super.viewDidLoad()

    view.addSubview(chartView)
    chartView.addPlanet(fullAngle: 50, name: "Mars")
  }

}

class ChartView: UIView {

  lazy var panGesture: UIPanGestureRecognizer = {
      let v = UIPanGestureRecognizer(target: self, action: #selector(didPan(sender:)))
      return v
  }()

  override init(frame: CGRect) {
      super.init(frame: frame)

      backgroundColor = .blue
  }

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

  @objc private func didPan(sender: UIPanGestureRecognizer) {
      let translation = sender.translation(in: self)
      if let view = sender.view {
          view.center = CGPoint(x:view.center.x + translation.x,
                                y:view.center.y + translation.y)
      }
      sender.setTranslation(CGPoint.zero, in: self)
      print("Pos: \(translation.x)- \(translation.y)")
  }

  func addPlanet(fullAngle: CGFloat, name: String) {
      let planetImageView: UIImageView = UIImageView()
      planetImageView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 100, height: 100))
      planetImageView.backgroundColor = .red
      planetImageView.addGestureRecognizer(panGesture)
      planetImageView.isUserInteractionEnabled = true
      self.addSubview(planetImageView)
  }

}

推荐阅读