我有一个 ViewController,它有一个名为 myView
的 UIView 和一个名为 myImageView
的 UIImageView。在下面的代码中,我有一个名为 viewLine
的类,它附加到名为 myView
的 UIView。
我遇到的问题是当 touchesEnded
被调用时,我想更改 ViewController 中 myImageView
的 alpha。当我尝试这样做时,myImageView
的 alpha 没有发生任何变化。
(或者,当我尝试通过将 viewLine
类移动到主 ViewController 中来实现此目的时,会出现以下错误 - override func drawRect(rect: CGRect)
- 方法不会覆盖其父类(super class)中的任何方法 和 self.setNeedsDisplay()
- “ViewController”类型的值没有成员“setNeedsDisplay”。 )
问题:
1 - 如何修改名为 viewLine
的类中的代码以访问 ViewController Storyboard上的其他 UI 对象或函数,例如 myImageView
?即,如何在调用 touchesEnded
后从名为 viewLine
的类更改 myImageView
的 alpha?
2 - 我在 ViewController 中有一个 slider sliderLineSize
,在 ViewController 中有一个变量 lineSize
。 UISlider sliderLineSize
更改 lineSize
。但是,lineSize
用于 viewLine
类的 drawRect
部分。
如何传递或访问类中 ViewController 中设置的变量?
(3 - 如何将 viewLine
类合并到主 ViewController 中?)
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myView: UIView!
@IBOutlet weak var myImageView: UIImageView!
var lineSize: Int = 1
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
myImageView.alpha = 0.5
}
@IBAction func sliderLineSize(sender: UISlider) {
lineSize = Int(sender.value)
}
}
class viewLine: UIView {
let path=UIBezierPath()
var incrementalImage:UIImage?
var previousPoint:CGPoint = CGPoint.zero
var strokeColor:UIColor?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect) {
incrementalImage?.drawInRect(rect)
path.lineWidth = lineSize
path.stroke()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
path.moveToPoint(currentPoint)
previousPoint=currentPoint
self.setNeedsDisplay()
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
let midPoint = self.midPoint(previousPoint, p1: currentPoint)
path.addQuadCurveToPoint(midPoint,controlPoint: previousPoint)
previousPoint=currentPoint
path.moveToPoint(midPoint)
self.setNeedsDisplay()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.drawBitmap()
self.setNeedsDisplay()
path.removeAllPoints()
}
func midPoint(p0:CGPoint,p1:CGPoint)->CGPoint {
let x=(p0.x+p1.x)/2
let y=(p0.y+p1.y)/2
return CGPoint(x: x, y: y)
}
func drawBitmap() {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 1)
strokeColor?.setStroke()
if((incrementalImage) == nil){
let rectPath:UIBezierPath = UIBezierPath(rect: self.bounds)
UIColor.whiteColor().setFill()
rectPath.fill()
}
incrementalImage?.drawAtPoint(CGPointZero)
path.stroke()
incrementalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
最佳答案
我查阅了有关如何从其 subview 引用 ViewController 的信息,我发现最好的选择是 StackOverflow 的回答,它说“遵循 MVC 模式,ViewController 知道它的 View ,但 View 不应该知道 ViewController。相反,您应该声明委托(delegate)协议(protocol)”(来源:Swift - How to pass a view controller's reference to a sub UIView class?)
因此,我认为解决方案是编写自定义委托(delegate)协议(protocol)并让 ViewController 遵守它。上述答案中的代码编写委托(delegate)协议(protocol)有点过时,但问题的开头在 Pure Swift class conforming to protocol with static method - issue with upcasting展示了如何正确编写适用于我的 Xcode 7.2 的协议(protocol)。
我的 Storyboard有一个这样的图表:
- 查看
- 我的 View (链接到您的代码)
- 我的 ImageView (背景是我选择的静态图像)
我将类 viewLine
重命名为 ViewLineUIView
,因为我认为这将是底层父类(super class)的更具描述性的名称。代码如下。
代码:
import UIKit
protocol ViewLineUIViewDelegate: class {
func onTouchesEnded(viewLine: ViewLineUIView)
}
class ViewController: UIViewController, ViewLineUIViewDelegate {
@IBOutlet weak var myView: UIView!
@IBOutlet weak var myImageView: UIImageView!
@IBOutlet weak var sliderValue: UISlider!
var viewLineDelegate: ViewLineUIView!
override func viewDidLoad() {
super.viewDidLoad()
viewLineDelegate = myView as? ViewLineUIView
viewLineDelegate!.delegate = self
//update lineWidth to initial value of slider
updateLineWidth()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func onTouchesEnded(viewLine: ViewLineUIView) {
myImageView!.alpha = 0.5
}
//Updating lineWidth!
@IBAction func onSliderChange(sender: UISlider) {
updateLineWidth()
}
func updateLineWidth() {
let drawView = myView as! ViewLineUIView
//you can change this "10" value to your max lineWidth
drawView.path.lineWidth = CGFloat(sliderValue.value*10)
print("New value is: " + String(drawView.path.lineWidth))
}
}
class ViewLineUIView: UIView {
weak var delegate: ViewLineUIViewDelegate?
let path=UIBezierPath()
var incrementalImage:UIImage?
var previousPoint:CGPoint = CGPoint.zero
var strokeColor:UIColor?
required init?(coder aDecoder: NSCoder) {
//Initialize lineWidth so that compiler doesn't complain
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect) {
incrementalImage?.drawInRect(rect)
path.stroke()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
path.moveToPoint(currentPoint)
previousPoint=currentPoint
self.setNeedsDisplay()
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
let midPoint = self.midPoint(previousPoint, p1: currentPoint)
path.addQuadCurveToPoint(midPoint,controlPoint: previousPoint)
previousPoint=currentPoint
path.moveToPoint(midPoint)
self.setNeedsDisplay()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.drawBitmap()
self.setNeedsDisplay()
path.removeAllPoints()
delegate?.onTouchesEnded(self)
}
func midPoint(p0:CGPoint,p1:CGPoint)->CGPoint {
let x=(p0.x+p1.x)/2
let y=(p0.y+p1.y)/2
return CGPoint(x: x, y: y)
}
func drawBitmap() {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 1)
strokeColor?.setStroke()
if((incrementalImage) == nil){
let rectPath:UIBezierPath = UIBezierPath(rect: self.bounds)
UIColor.whiteColor().setFill()
rectPath.fill()
}
incrementalImage?.drawAtPoint(CGPointZero)
path.stroke()
incrementalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
如您所见,编辑路径的 lineWidth 非常简单,您不需要创建另一个委托(delegate)协议(protocol)。 ViewController 可以直接访问它的 subview 。您应该只知道需要强制转换。
关于ios - 从 Swift 中的不同类访问 ViewController 中的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35319995/