我正在尝试使用UIView上的一些UISegementedControl创建一个相对简单的自定义视图(见下文),但我似乎无法使事情正常工作。
我为视图创建了XIB文件,并将文件所有者设置为自定义类(参见下文)。然后我通过CTRL-Dragging直接从右键单击文件所有者时弹出的面板链接@IBOutlets。
在代码中我还设置了UISegmentedControls的目标,但这些似乎永远不会被调用,同样如果我设置了isSelectionEnabled,分段控件永远不会在视图中被禁用。
我在这里做错了什么?
//
// ScheduleSelectorView.swift
//
//
// .
//
//
import UIKit
enum ScheduleWeeks: String {
case week1 = "Week 1",
week2 = "Week 2",
week3 = "week 3",
week4 = "week 4"
static let allValues = [week1,week2,week3,week4]
}
enum ScheduleDays: String {
case mon = "Mon",
tue = "Tue",
wed = "Wed",
thu = "Thu",
fri = "Fri",
sat = "Sat",
sun = "Sun"
static let allValues = [mon,tue,wed,thu,fri,sat,sun]
}
enum ScheduleAMPM: String {
case am = "AM",
pm = "PM"
static let allValues = [am, pm]
}
@objc
enum ScheduleSelectorValueType: Int {
case week, day, hour, minute, ampm, none
}
@objc
protocol ScheduleSelectorDelegate {
/// called when a value is changed in the selector
@objc
func valueChanged(type: ScheduleSelectorValueType, value: Any?)
}
@IBDesignable class ScheduleSelectorView: UIView {
let nibName = "ScheduleSelectorView"
@IBOutlet var delegate: ScheduleSelectorDelegate?
@IBOutlet var contentView: UIView!
@IBOutlet weak var weekSelector: UISegmentedControl!
@IBOutlet weak var daySelector: UISegmentedControl!
@IBOutlet weak var hourSelector: UISegmentedControl!
@IBOutlet weak var minuteSelector: UISegmentedControl!
@IBOutlet weak var ampmSelector: UISegmentedControl!
var selectors: [UISegmentedControl] = []
@IBInspectable
var timeInterval: Int = 15 {
didSet {
setupMinuteSelector()
}
}
var isSelectionEnabled: Bool = false {
didSet {
for selector in selectors {
DebugLog("isSelectionEnabled: \(isSelectionEnabled): \(selector.numberOfSegments)")
selector.isUserInteractionEnabled = isSelectionEnabled
}
}
}
struct Schedule {
var week:ScheduleWeeks = .week1
var day: ScheduleDays = .mon
var hour: Int = 0
var minute: Int = 0
var ampm: ScheduleAMPM = .am
init() {
}
init(week: ScheduleWeeks, day: ScheduleDays, hour: Int, minute: Int, ampm: ScheduleAMPM) {
self.week = week
self.day = day
self.hour = hour
self.minute = minute
self.ampm = ampm
}
}
var _schedule = Schedule()
var schedule: Schedule? {
return _schedule
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
DebugLog("init(coder)")
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
DebugLog("init(frame)")
}
func loadViewFromNib() -> UIView {
// grabs the appropriate bundle
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: nibName, bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
func commonInit() {
Bundle.main.loadNibNamed(nibName, owner: self, options: nil)
addSubview(contentView)
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
selectors = [weekSelector, daySelector, hourSelector, minuteSelector, ampmSelector]
setup()
}
func setup(){
setupWeekSelector()
setupDaySelector()
setupHourSelector()
setupMinuteSelector()
// Set targets for changes
self.weekSelector.addTarget(self, action: #selector(selectionDidChange(_:)), for: .valueChanged )
self.daySelector.addTarget(self, action: #selector(selectionDidChange(_:)), for: .valueChanged )
self.hourSelector.addTarget(self, action: #selector(selectionDidChange(_:)), for: .valueChanged )
self.minuteSelector.addTarget(self, action: #selector(selectionDidChange(_:)), for: .valueChanged )
self.ampmSelector.addTarget(self, action: #selector(selectionDidChange(_:)), for: .valueChanged )
}
func setupWeekSelector(){
DebugLog("setupWeekSelector")
weekSelector.removeAllSegments()
for (index, title) in ScheduleWeeks.allValues.enumerated() {
weekSelector.insertSegment(withTitle: title.rawValue, at: index, animated: true)
}
}
func setupDaySelector(){
daySelector.removeAllSegments()
for (index, title) in ScheduleDays.allValues.enumerated() {
daySelector.insertSegment(withTitle: title.rawValue, at: index, animated: true)
}
}
func setupHourSelector(){
hourSelector.removeAllSegments()
for t in 0..<12 {
hourSelector.insertSegment(withTitle: "\(t)", at: t, animated: true)
}
}
func setupMinuteSelector(){
minuteSelector?.removeAllSegments()
for t in stride(from: 0, through: 60, by: timeInterval) {
minuteSelector?.insertSegment(withTitle: "\(t)", at: t, animated: true)
}
}
@objc func selectionDidChange(_ selector: UISegmentedControl) {
var type: ScheduleSelectorValueType = .none
var value: Any? = nil
let index = selector.selectedSegmentIndex
switch selector {
case weekSelector:
type = .week
value = ScheduleWeeks.allValues[index]
_schedule.week = ScheduleWeeks.allValues[index]
case daySelector:
type = .day
value = ScheduleDays.allValues[index]
_schedule.day = ScheduleDays.allValues[index]
case hourSelector:
type = .hour
value = index
_schedule.hour = index
case minuteSelector:
type = .minute
value = index
_schedule.minute = index
case ampmSelector:
type = .ampm
value = ScheduleAMPM.allValues[index]
_schedule.ampm = ScheduleAMPM.allValues[index]
default:
type = .none
}
self.delegate?.valueChanged(type: type, value: value)
}
var valueString: String {
let week = (weekSelector.selectedSegmentIndex != UISegmentedControlNoSegment) ? weekSelector.selectedSegmentIndex : 0
let day = (daySelector.selectedSegmentIndex != UISegmentedControlNoSegment) ? daySelector.selectedSegmentIndex : 0
let hour = (hourSelector.selectedSegmentIndex != UISegmentedControlNoSegment) ? hourSelector.selectedSegmentIndex : 0
let minute = (minuteSelector.selectedSegmentIndex != UISegmentedControlNoSegment) ? minuteSelector.selectedSegmentIndex : 0
let ampm = (ampmSelector.selectedSegmentIndex != UISegmentedControlNoSegment) ? ampmSelector.selectedSegmentIndex : 0
let selection = "\(ScheduleWeeks.allValues[week]), \(ScheduleDays.allValues[day]) \(hour.padded2):\(minute.padded2) \(ScheduleAMPM.allValues[ampm])"
return selection
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
extension UISegmentedControl {
func setSelectionEnabled(_ enabled: Bool) {
for i in 0..<self.numberOfSegments {
self.setEnabled(enabled, forSegmentAt: i)
}
}
}
答案 0 :(得分:1)
我真的很难找到任何实际有效的答案,但最后我设法让它发挥作用。
我认为主要的解决方案来自我在这里找到的NibLoaderView。
iOS - How to initialize custom UIView with specific Frame from NIB
但是我必须做一些改变才能让它在IB中发挥作用。
import UIKit
// Usage: Subclass your UIView from NibLoadView to automatically load a xib with the same name as your class
@IBDesignable
class NibLoadingView: UIView {
@IBOutlet weak var view: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
nibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
nibSetup()
}
override open func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
nibSetup()
view?.prepareForInterfaceBuilder()
}
private func nibSetup() {
backgroundColor = .clear
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.translatesAutoresizingMaskIntoConstraints = true
addSubview(view)
view.anchorAllEdgesToSuperview()
}
private func loadViewFromNib() -> UIView {
let bundle = Bundle(for: type(of:self))
let nib = UINib(nibName: String(describing: type(of:self)), bundle: bundle)
let nibView = nib.instantiate(withOwner: self, options: nil).first as! UIView
return nibView
}
}
extension UIView {
func anchorAllEdgesToSuperview() {
self.translatesAutoresizingMaskIntoConstraints = false
if #available(iOS 9.0, *) {
addSuperviewConstraint(constraint: topAnchor.constraint(equalTo: (superview?.topAnchor)!))
addSuperviewConstraint(constraint: leftAnchor.constraint(equalTo: (superview?.leftAnchor)!))
addSuperviewConstraint(constraint: bottomAnchor.constraint(equalTo: (superview?.bottomAnchor)!))
addSuperviewConstraint(constraint: rightAnchor.constraint(equalTo: (superview?.rightAnchor)!))
}
else {
for attribute : NSLayoutAttribute in [.left, .top, .right, .bottom] {
anchorToSuperview(attribute: attribute)
}
}
}
func anchorToSuperview(attribute: NSLayoutAttribute) {
addSuperviewConstraint(constraint: NSLayoutConstraint(item: self, attribute: attribute, relatedBy: .equal, toItem: superview, attribute: attribute, multiplier: 1.0, constant: 0.0))
}
func addSuperviewConstraint(constraint: NSLayoutConstraint) {
superview?.addConstraint(constraint)
}
}
然后在子类中确保您拥有以下内容:
@IBDesignable class Designable: NibLoaderView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
我当然希望这能节省一些时间......
如果有兴趣的话,这里有一个可用的示例应用程序