简体   繁体   中英

UIView won't move upon dragging using UIPanGestureRecognizer

I have a container called ChartView that holds my planet's UIImageView . I adds my planets programatically then I assign them the UIPanGestureRecognizer . From what I understand, I need to forward the delegate to my container ViewController then implements my draggedView() function.

I successfully enter that function but the UIImageView doesn't move visually even though I'm printing its new position in draggedView(). What did I do wrong?

**** UPDATED ****

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)")
    }

}

Here's the ChartView:

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)
    }
}

The problem with this question is that you're lying. Not on purpose, perhaps! But the simple fact is that your code, as shown, does work. Therefore the problem lies elsewhere. Here I am, dragging your "planet" in your "chart view":

在此处输入图片说明

The code I used is all your code . All I did was reduce it still further. This is the complete code of my example:

class FirstViewController: UIViewController {
    @IBOutlet weak var chartView: ChartView!
    override func viewDidLoad() {
        super.viewDidLoad()
        self.chartView.delegate = self
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.chartView.addPlanet(fullAngle: CGFloat(0),name: "name")
    }
    @objc func draggedView(_ sender:UIPanGestureRecognizer){
        let translation = sender.translation(in: self.chartView)
        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.chartView)
    }
}
extension FirstViewController: UIGestureRecognizerDelegate {
}
@IBDesignable class ChartView: UIView {
    var delegate: FirstViewController?
    public func addPlanet(fullAngle: CGFloat, name: String) {
        let planetImageView: UIImageView = UIImageView()
        planetImageView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 10, height: 10))
        planetImageView.backgroundColor = .blue
        let panGesture = UIPanGestureRecognizer(target: self.delegate, action: #selector(self.delegate?.draggedView(_:)))
        planetImageView.isUserInteractionEnabled = true
        planetImageView.addGestureRecognizer(panGesture)
        self.addSubview(planetImageView)
    }
}

Do you recognize that code? You should! It is your code, completely unchanged. I cut some of it, and I replaced the network stuff with this line, so we would have just one "planet":

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

And it works! Therefore I conclude that you are lying; the code you are showing is not the code that creates the non-draggable planet.

I've created a simple blue square, then add a red planet. You can pan a red square. Here is the example, programmatically.

在此处输入图片说明

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)
  }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM