Ios IBInspectable和从xib为Interface Builder加载视图时出现问题
我有一个自定义类,它有自己的.xib。我正在尝试合并IBInspectable,以便在IB中更改其背景和子视图背景的颜色 在IB中,当我将Ios IBInspectable和从xib为Interface Builder加载视图时出现问题,ios,interface-builder,ibdesignable,ibinspectable,Ios,Interface Builder,Ibdesignable,Ibinspectable,我有一个自定义类,它有自己的.xib。我正在尝试合并IBInspectable,以便在IB中更改其背景和子视图背景的颜色 在IB中,当我将'Custom Class'留空,并添加用户定义的运行时属性'bgColor',然后尝试运行该应用程序时,我得到“…该类与键bgColor的键值编码不兼容。”该应用程序运行时不会崩溃,但不会将该颜色应用于视图 当我将'Custom Class'设置为的“AxesView”并运行时,应用程序会因线程1:EXC_BAD_ACCESS(code=2,address)
'Custom Class'
留空,并添加用户定义的运行时属性'bgColor'
,然后尝试运行该应用程序时,我得到“…该类与键bgColor的键值编码不兼容。”
该应用程序运行时不会崩溃,但不会将该颜色应用于视图
当我将'Custom Class'
设置为的“AxesView”
并运行时,应用程序会因线程1:EXC_BAD_ACCESS(code=2,address)
而崩溃,并在NibLoadableExtension.swift的函数setupFromNib()
中突出显示行“guard let view=Self.nib.instantiate…”
有没有办法让这些东西一起工作,或者这是一种非此即彼的情况
视图中的控制器:
var axesView = AxesView()
override func viewDidLoad() {
super.viewDidLoad()
axesView.frame = self.view.bounds
self.view.addSubview(axesView)
}
全视图控制器。swift
var axesView = AxesView()
override func viewDidLoad() {
super.viewDidLoad()
axesView.frame = self.view.bounds
axesView.bgColor = .clear
axesView.lineColor = .red
self.view.addSubview(axesView)
axesView.contentView.translatesAutoresizingMaskIntoConstraints = false
axesView.contentView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0).isActive = true
axesView.contentView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0).isActive = true
axesView.contentView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0).isActive = true
axesView.contentView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first! as UITouch
let p = touch.location(in: self.view)
axesView.vLine.center.x = p.x
axesView.hLine.center.y = p.y
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first! as UITouch
let p = touch.location(in: self.view)
axesView.vLine.center.x = p.x
axesView.hLine.center.y = p.y
self.view.setNeedsDisplay()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touchesMoved(touches, with: event)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
touchesEnded(touches, with: event)
}
@IBDesignable class AxesView: UIView, NibLoadable {
@IBOutlet var contentView: UIView!
@IBOutlet weak var hLine: UIView!
@IBOutlet weak var vLine: UIView!
@IBInspectable var bgColor: UIColor = UIColor.white {
didSet {
contentView.backgroundColor = bgColor
}
}
@IBInspectable var lineColor: UIColor = UIColor.cyan {
didSet {
hLine.backgroundColor = lineColor
vLine.backgroundColor = lineColor
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupFromNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupFromNib()
}
}
public protocol NibLoadable {
static var nibName: String { get }
}
public extension NibLoadable where Self: UIView {
static var nibName: String {
return String(describing: Self.self) // defaults to the name of the class implementing this protocol.
}
static var nib: UINib {
let bundle = Bundle(for: Self.self)
return UINib(nibName: Self.nibName, bundle: bundle)
}
func setupFromNib() {
guard let view = Self.nib.instantiate(withOwner: self, options: nil).first as? UIView else { fatalError("Error loading \(self) from nib") }
addSubview(view)
}
}
NibLoadableExtension.swift
var axesView = AxesView()
override func viewDidLoad() {
super.viewDidLoad()
axesView.frame = self.view.bounds
axesView.bgColor = .clear
axesView.lineColor = .red
self.view.addSubview(axesView)
axesView.contentView.translatesAutoresizingMaskIntoConstraints = false
axesView.contentView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0).isActive = true
axesView.contentView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0).isActive = true
axesView.contentView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0).isActive = true
axesView.contentView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first! as UITouch
let p = touch.location(in: self.view)
axesView.vLine.center.x = p.x
axesView.hLine.center.y = p.y
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first! as UITouch
let p = touch.location(in: self.view)
axesView.vLine.center.x = p.x
axesView.hLine.center.y = p.y
self.view.setNeedsDisplay()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touchesMoved(touches, with: event)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
touchesEnded(touches, with: event)
}
@IBDesignable class AxesView: UIView, NibLoadable {
@IBOutlet var contentView: UIView!
@IBOutlet weak var hLine: UIView!
@IBOutlet weak var vLine: UIView!
@IBInspectable var bgColor: UIColor = UIColor.white {
didSet {
contentView.backgroundColor = bgColor
}
}
@IBInspectable var lineColor: UIColor = UIColor.cyan {
didSet {
hLine.backgroundColor = lineColor
vLine.backgroundColor = lineColor
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupFromNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupFromNib()
}
}
public protocol NibLoadable {
static var nibName: String { get }
}
public extension NibLoadable where Self: UIView {
static var nibName: String {
return String(describing: Self.self) // defaults to the name of the class implementing this protocol.
}
static var nib: UINib {
let bundle = Bundle(for: Self.self)
return UINib(nibName: Self.nibName, bundle: bundle)
}
func setupFromNib() {
guard let view = Self.nib.instantiate(withOwner: self, options: nil).first as? UIView else { fatalError("Error loading \(self) from nib") }
addSubview(view)
}
}
您的代码运行良好(大部分情况下)
确保在正确的对象上设置了类:
将setupFromNib()
func更改为:
func setupFromNib() {
guard let view = Self.nib.instantiate(withOwner: self, options: nil).first as? UIView else { fatalError("Error loading \(self) from nib") }
addSubview(view)
view.frame = self.bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// layout code...
}
以下是在IB中添加到视图控制器的外观:
下面是通过代码显示的情况:
class AxesTestViewController: UIViewController {
var axesView = AxesView()
override func viewDidLoad() {
super.viewDidLoad()
axesView.frame = self.view.bounds
axesView.bgColor = .blue
axesView.lineColor = .red
self.view.addSubview(axesView)
}
}
编辑
在评论中讨论后,这里是一种使用“可拖动”交叉线的方法来实现此@IBDesignable
xib
这将使用约束并修改centerX和centerY上的.constant
,以移动线。我还将您的touch…
funcs移动到自定义视图中,以使事情更加有序
下面是完整的示例代码,包括nibloable
代码(为了比较,我将控件重命名为TapAxesView
):
编辑2
也许值得一试。。。仅通过代码查看自定义@IBDesignable
视图。。。无需xib
文件(或nib加载)。此外,它使用CALayer
作为“交叉线”,而不是子视图。让它更轻一点
@IBDesignable
类LayerAxesView:UIView{
var hLine:CALayer=CALayer()
变量vLine:CALayer=CALayer()
var curX:CGFloat=-1.0
变量curY:CGFloat=-1.0
让线宽:CGFloat=4.0
@IBInspectable var bgColor:UIColor=UIColor.white{
迪塞特{
self.backgroundColor=bgColor
}
}
@IBInspectable var lineColor:UIColor=UIColor.cyan{
迪塞特{
hLine.backgroundColor=lineColor.cgColor
vLine.backgroundColor=lineColor.cgColor
}
}
重写初始化(帧:CGRect){
super.init(frame:frame)
commonInit()
}
必需的初始化?(编码器aDecoder:NSCoder){
super.init(编码者:aDecoder)
commonInit()
}
重写func prepareForInterfaceBuilder(){
commonInit()
}
func commonInit()->Void{
如果hLine.superlayer==nil{
layer.addSublayer(hLine)
图层。添加子图层(vLine)
hLine.backgroundColor=lineColor.cgColor
vLine.backgroundColor=lineColor.cgColor
背景颜色=背景颜色
}
}
覆盖func布局子视图(){
//如果curX和curY尚未设置,
//例如在init上或在故事板/IB中使用时,
//初始化到视图中心
如果curX==-1{
curX=bounds.midX
curY=bounds.midY
}
hLine.frame=CGRect(x:bounds.minX,y:curY-lineWidth*0.5,width:bounds.maxX,height:lineWidth)
vLine.frame=CGRect(x:curX-lineWidth*0.5,y:bounds.minY,width:lineWidth,height:bounds.maxY)
}
func updateCenter(u点:CGPoint)->Void{
//防止中心移动到边界之外
curX=max(最小值(bounds.maxX,point.x),bounds.minX)
curY=max(min(bounds.maxY,point.y),bounds.minY)
//禁用CALayer的内置动画
CATransaction.begin()
CATTransaction.setDisableActions(true)
setNeedsLayout()
layoutIfNeeded()
CATransaction.commit()
}
覆盖func TouchesBegind(Touchs:Set,带有事件:UIEvent?){
让touch=touch.first!作为UITouch
让p=触摸位置(in:self)
更新中心(p)
}
覆盖功能触摸移动(touchs:Set,带有事件:UIEvent?){
让touch=touch.first!作为UITouch
让p=触摸位置(in:self)
更新中心(p)
}
覆盖函数touchesend(touchs:Set,带有事件:UIEvent?){
触摸移动(触摸,带有:事件)
}
}
类TapAxesTestViewController:UIViewController{
var axesView:LayerAxesView={
设v=LayerAxesView()
v、 translatesAutoresizingMaskIntoConstraints=false
v、 lineColor=.red
v、 bgColor=UIColor.blue.带字母组件(0.5)
返回v
}()
重写func viewDidLoad(){
super.viewDidLoad()
self.view.addSubview(axesView)
//尊重安全区
设g=视图。安全区域布局指南
//用40分“填充”将axesView约束到安全区域
NSLayoutConstraint.activate([
AxeView.topAnchor.constraint(等式:g.topAnchor,常数:40.0),
AxeView.leadingAnchor.constraint(等式:g.leadingAnchor,常数:40.0),
AxeView.trailingAnchor.constraint(等式:g.trailingAnchor,常数:-40.0),
AxeView.bottomAnchor.constraint(等式:g.bottomAnchor,常数:-40.0),
])
}
}
我明白你的意思了。但是,当我把这个想法放在更大的范围内时,我遇到了很多不同的问题。我想我可能需要把我的问题扩大一点。开始比较好吗