我有一个简单的应用程序,它有一个ViewController
,包含一个非常小的视图层次结构:DrawingView
(UIView
的子类)和三个ImageViews
(它们都是DrawingView
的子级)。
在DrawingView
中,我重写了draw(_:)
,以生成依赖于每个ImageView
中心的图形(具体来说,一个顶点为图像中心的多边形)。同时,ImageView
的位置由用户通过拖动手势控制。手势处理动作是ViewController
的方法。
我希望DrawingView
能够随着ImageView
位置的变化而实时更新。为了实现这一点,我在手势处理程序中调用了DrawingView.setNeedsDisplay()
。然而,这种方法只会离散地更新DrawingView
,而且似乎直到下一个手势开始时才更新(无论调用出现在switch gesture.state
语句中的何处)。
x1c 0d1x的数据
我的问题:我应该在哪里/如何调用setNeedsDisplay
以实现对DrawingView
的平滑(实时)更新?或者有更好的方法吗?
以下是我的类定义:
class ViewController: UIViewController {
@IBOutlet var drawingView: DrawingView!
@IBOutlet var majorVertex1: UIImageView!
@IBOutlet var majorVertex2: UIImageView!
@IBOutlet var majorVertex3: UIImageView!
var majorVertices: [UIImageView]!
@IBOutlet var majorVertex1XConstraint: NSLayoutConstraint!
@IBOutlet var majorVertex1YConstraint: NSLayoutConstraint!
@IBOutlet var majorVertex2XConstraint: NSLayoutConstraint!
@IBOutlet var majorVertex2YConstraint: NSLayoutConstraint!
@IBOutlet var majorVertex3XConstraint: NSLayoutConstraint!
@IBOutlet var majorVertex3YConstraint: NSLayoutConstraint!
var majorVertexXConstraints: [NSLayoutConstraint]!
var majorVertexYConstraints: [NSLayoutConstraint]!
static var majorVertexXOffsets: [Double]?
static var majorVertexYOffsets: [Double]?
override func viewDidLoad() {
super.viewDidLoad()
majorVertices = [majorVertex1, majorVertex2, majorVertex3]
majorVertexXConstraints = [majorVertex1XConstraint, majorVertex2XConstraint, majorVertex3XConstraint]
majorVertexYConstraints = [majorVertex1YConstraint, majorVertex2YConstraint, majorVertex3YConstraint]
ViewController.majorVertexXOffsets = majorVertexXConstraints.map {(constraint) -> Double in return constraint.constant}
ViewController.majorVertexYOffsets = majorVertexYConstraints.map {(constraint) -> Double in return constraint.constant}
}
@IBAction func handlePan(_ gesture: UIPanGestureRecognizer) {
guard let majorVertices = majorVertices,
let gestureView = gesture.view
else {return}
guard let parentView = gestureView.superview,
let gestureViewIndex = majorVertices.firstIndex(of: gestureView as! UIImageView)
else {return}
let translation = gesture.translation(in: parentView)
switch gesture.state {
case .began:
ViewController.majorVertexXOffsets = majorVertexXConstraints.map {(constraint) -> Double in return constraint.constant}
ViewController.majorVertexYOffsets = majorVertexYConstraints.map {(constraint) -> Double in return constraint.constant}
break
case .changed:
majorVertexXConstraints[gestureViewIndex].constant = ViewController.majorVertexXOffsets![gestureViewIndex] + translation.x
majorVertexYConstraints[gestureViewIndex].constant = ViewController.majorVertexYOffsets![gestureViewIndex] + translation.y
drawingView.setNeedsDisplay()
break
case .ended, .cancelled:
majorVertexXConstraints[gestureViewIndex].constant = gestureView.center.x - parentView.frame.size.width / 2.0
majorVertexYConstraints[gestureViewIndex].constant = gestureView.center.y - parentView.frame.size.height / 2.0
break
default:
break
}
}
}
class DrawingView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
func setupView() {
backgroundColor = .clear
}
override func draw(_ rect: CGRect) {
super.draw(rect)
drawTriangle(rect)
}
internal func drawTriangle(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext(),
let majorVertexXOffsets = ViewController.majorVertexXOffsets,
let majorVertexYOffsets = ViewController.majorVertexYOffsets
else {return}
let majorVertexXCenters = majorVertexXOffsets.map {(x) -> Double in return x + rect.width / 2.0}
let majorVertexYCenters = majorVertexYOffsets.map {(y) -> Double in return y + rect.height / 2.0}
context.setStrokeColor(UIColor.lightGray.cgColor)
context.setLineWidth(3)
context.move(to: CGPoint(x: majorVertexXCenters[0], y: majorVertexYCenters[0]))
context.addLine(to: CGPoint(x: majorVertexXCenters[1], y: majorVertexYCenters[1]))
context.addLine(to: CGPoint(x: majorVertexXCenters[2], y: majorVertexYCenters[2]))
context.addLine(to: CGPoint(x: majorVertexXCenters[0], y: majorVertexYCenters[0]))
context.strokePath()
}
}
字符串
1条答案
按热度按时间c7rzv4ha1#
你正在用
static
vars做一些相当时髦的事情,这需要直接引用特定的类.您看不到“实时”绘制更新的原因是因为您更改了约束常量,而没有更新X & Y偏移数组。
字符串
编辑- * 回应评论... *
您对
static
vars所采用的方法导致了所谓的“紧耦合”--两个或多个类严重依赖于彼此,这使得更改和/或重用这些类变得困难。这个问题有太多的深度,无法在这里充分讨论,但一个快速的例子:
在
DrawingView
类中,有以下两行:型
假设你想在
SomeOtherController
中使用DrawingView
?你必须编辑这两行:型
现在
DrawingView
不再在原来的ViewController
中工作。相反,您需要做的是向
DrawingView
添加var属性,并根据需要设置/更新它们。因此,在
ViewController
中删除static
关键字:型
然后删除代码中所有出现的
ViewController.
:型
接下来,我们向
DrawingView
添加两个属性:型
然后,将
drawTriangle()
的第一部分改为:型
最后一步回到
ViewController
:型
搜索
Tight Coupling Anti-Pattern
以获得更深入的讨论。