我正在尝试建立一个电影票务应用程序,我需要帮助我的视图层次结构。目前我的cinemaView没有加入VC。
以下是我尝试这样做的方式。我有一个自定义seatView有两个属性(isVacant和seatNumber)和一个自定义cinemaView有[seatView]作为属性(不同的电影院有不同的座位)。我的代码是这样的:
//In my viewController
class ViewController: UIViewController, UIScrollViewDelegate {
let scrollView = UIScrollView()
let cinema: CinemaView = {
let v = CinemaView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 10.0
scrollView.zoomScale = scrollView.minimumZoomScale
scrollView.delegate = self
scrollView.isScrollEnabled = true
scrollView.translatesAutoresizingMaskIntoConstraints = false
let seat1 = SeatView()
seat1.isVacant = false
seat1.seatNumber = "2A"
let seat2 = SeatView()
seat2.isVacant = true
seat2.seatNumber = "3B"
cinema.seats = [seat1, seat2]
view.addSubview(scrollView)
scrollView.addSubview(cinema)
let views = ["scrollView": scrollView, "v": cinema]
let screenHeight = view.frame.height
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[scrollView(\(screenHeight / 2))]", options: NSLayoutFormatOptions(), metrics: nil, views: views))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[scrollView]|", options: NSLayoutFormatOptions(), metrics: nil, views: views))
scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-60-[v(50)]", options: NSLayoutFormatOptions(), metrics: nil, views: views))
scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v]|", options: NSLayoutFormatOptions(), metrics: nil, views: views))
}
//At my custom cinemaView
class CinemaView: UIView {
var seats = [SeatView]()
var xPos: Int = 0
let cinemaView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(cinemaView)
cinemaView.backgroundColor = .black
let views = ["v": cinemaView]
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[v]|", options: NSLayoutFormatOptions(), metrics: nil, views: views))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v]|", options: NSLayoutFormatOptions(), metrics: nil, views: views))
for seat in seats {
cinemaView.addSubview(seat)
seat.frame = CGRect(x: xPos, y: 0, width: 20, height: 20)
xPos += 8
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//At my custom seatView
class SeatView: UIView {
var isVacant: Bool?
var seatNumber: String?
let seatView: UIView = {
let v = UIView()
v.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
v.layer.cornerRadius = 5
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(seatView)
seatView.backgroundColor = setupBackgroundColor()
}
func setupBackgroundColor() -> UIColor {
if let isVacant = isVacant {
if isVacant {
return UIColor.green
} else {
return UIColor.black
}
} else {
return UIColor.yellow
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
我的代码似乎没有将cinemaView添加到我的VC中。谁能指出我哪里出错了?或者甚至建议这种方法适合这种应用吗?感谢。
答案 0 :(得分:1)
您需要在创建任何frames
时提供UIView
。
override init(frame: CGRect)
的框架时,将调用 UIView
。
我创建了一个与您相似的层次结构作为示例。看看吧。
同样xPos
必须与之前的SeatView
不重叠,即(new xPos + previous SeatView width)
。
同样在您的SeatView
和CinemaView
中,您在另一个UIView
内添加UIView
,这是多余的。你不需要这样做。
示例:强>
class ViewController: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
let seat1 = SeatView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
let seat2 = SeatView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
let cinema = CinemaView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
cinema.seats = [seat1, seat2]
self.view.addSubview(cinema)
}
}
class CinemaView: UIView
{
var seats = [SeatView](){
didSet{
for seat in seats
{
seat.frame.origin.x = xPos
xPos += 100
self.addSubview(seat)
}
}
}
var xPos: CGFloat = 0
override init(frame: CGRect)
{
super.init(frame: frame)
self.backgroundColor = .black
}
required init?(coder aDecoder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
}
class SeatView: UIView
{
override init(frame: CGRect)
{
super.init(frame: frame)
self.backgroundColor = .red
}
required init?(coder aDecoder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
}
答案 1 :(得分:0)
嗯,你这里做错了几件事......
您正在为UIView
创建子类,但在自定义视图中,您要添加UIView
作为子视图,并尝试将其视为您的实际视图。
在你的CinemaView
课程中,你正在循环你的“座位”阵列......但你在分配阵列之前正在这样做所以没有座位会是创建
同样,在SeatView
中,您尝试根据.isVacant
属性设置背景颜色,但在设置属性之前这样做。
您正在尝试使用UIScrollView
,但没有正确设置约束。
使用可视化格式设置约束可能会感觉方便或简单,但它有限制。在您的特定情况下,您希望滚动视图是主视图高度的1/2。使用VFL,您必须计算并显式设置常量,这也必须在帧更改时重新计算。使用滚动视图.heightAnchor.constraint
,将其设置为等于视图的.heightAnchor
,设置multiplier: 0.5
可获得50%而无需任何计算。
所以,要理解很多,要考虑很多。我对您的原始代码进行了一些修改。这应该被视为您学习的“起点”,而不是“插入完成的代码”:
class CinemaViewController: UIViewController, UIScrollViewDelegate {
let scrollView: UIScrollView = {
let sv = UIScrollView()
sv.minimumZoomScale = 1.0
sv.maximumZoomScale = 10.0
sv.zoomScale = sv.minimumZoomScale
sv.isScrollEnabled = true
sv.translatesAutoresizingMaskIntoConstraints = false
return sv
}()
let cinema: CinemaView = {
let v = CinemaView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = UIColor.black
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
// set our background to yellow, so we can see where it is
view.backgroundColor = .yellow
// create 2 "SeatView" objects
let seat1 = SeatView()
seat1.isVacant = false
seat1.seatNumber = "2A"
let seat2 = SeatView()
seat2.isVacant = true
seat2.seatNumber = "3B"
// set the array of "seats" in the cinema view object
cinema.seats = [seat1, seat2]
// assign scroll view delegate
scrollView.delegate = self
// set scroll view background color, so we can see it
scrollView.backgroundColor = .blue
// add the scroll view to this view
view.addSubview(scrollView)
// pin scrollView to top, leading and trailing, with 8-pt padding
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8.0).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8.0).isActive = true
// set scrollView height to 50% of view height
scrollView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5).isActive = true
// add cinema view to the scroll view
scrollView.addSubview(cinema)
// pin cinema to top and leading of scrollView, with 8.0-pt padding
cinema.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 8.0).isActive = true
cinema.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 8.0).isActive = true
// set the width of cinema to scrollView width -16.0 (leaves 8.0-pts on each side)
cinema.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: -16.0).isActive = true
// cinema height set to constant of 60.0 (for now)
cinema.heightAnchor.constraint(equalToConstant: 60.0).isActive = true
// in order to use a scroll view, its .contentSize must be defined
// so, use the trailing and bottom anchor constraints of cinema to define the .contentSize
cinema.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: 0.0).isActive = true
cinema.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0.0).isActive = true
}
}
//At my custom cinemaView
class CinemaView: UIView {
// when the seats property is set,
// remove any existing seat views
// and add a new seat view for each seat
// Note: eventually, this will likely be done with Stack Views and / or constraints
// rather than calculated Rects
var seats = [SeatView]() {
didSet {
for v in self.subviews {
v.removeFromSuperview()
}
var seatRect = CGRect(x: 0, y: 0, width: 20, height: 20)
for seat in seats {
self.addSubview(seat)
seat.frame = seatRect
seatRect.origin.x += seatRect.size.width + 8
}
}
}
// we're not doing anything on init() - yet...
// un-comment the following if you need to add setup code
// see the similar functionality in SeatView class
/*
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
*/
// perform any common setup tasks here
func commonInit() -> Void {
//
}
}
//At my custom seatView
class SeatView: UIView {
// change the background color when .isVacant property is set
var isVacant: Bool = false {
didSet {
if isVacant {
self.backgroundColor = UIColor.green
} else {
self.backgroundColor = UIColor.red
}
}
}
// not used currently
var seatNumber: String?
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
// perform any common setup tasks here
func commonInit() -> Void {
self.layer.cornerRadius = 5
}
}