Ios Swift:自定义视图层次结构
我正在尝试建立一个电影票务应用程序,我需要帮助我的视图层次结构。目前,我的cinemaView没有添加到VC中 下面是我如何尝试去做的。我有一个自定义seatView,它有两个属性(IsEmptable和seatNumber),还有一个自定义cinemaView,它有[seatView]作为属性(不同的电影院有不同的座位)。我的代码如下:Ios Swift:自定义视图层次结构,ios,swift,Ios,Swift,我正在尝试建立一个电影票务应用程序,我需要帮助我的视图层次结构。目前,我的cinemaView没有添加到VC中 下面是我如何尝试去做的。我有一个自定义seatView,它有两个属性(IsEmptable和seatNumber),还有一个自定义cinemaView,它有[seatView]作为属性(不同的电影院有不同的座位)。我的代码如下: //In my viewController class ViewController: UIViewController, UIScrollViewDele
//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中。谁能告诉我哪里出了问题?或者,如果此方法适用于此应用程序,甚至可能提供建议?谢谢。您需要在创建任何
ui视图时提供帧
override init(frame:CGRect)
将在指定自定义UIView
的帧时调用
我创建了一个与您类似的层次结构作为示例。看一看
而且xpo
必须确保其不会与先前的SeatView
重叠,即(新xpo+先前的SeatView宽度)
另外,在您的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")
}
}
嗯,你在这里做错了几件事
您正在子类化UIView
,但在自定义视图中,您正在将UIView
添加为子视图,并尝试将其视为实际视图
在你的CinemaView
课程中,你正在循环你的“座位”数组。。。但是您在分配数组之前执行此操作,因此不会创建任何座位
类似地,在SeatView
中,您试图基于.isemptain
属性设置背景色,但您是在设置属性之前进行的
您正试图使用UIScrollView
,但未正确设置约束
使用可视格式设置约束可能感觉方便或容易,但它有局限性。在特定情况下,您希望滚动视图的高度为主视图高度的1/2。使用VFL,您必须计算并显式设置常量,在帧更改时也必须重新计算该常量。使用滚动视图的.heightAnchor.constraint
,将其设置为视图的.heightAnchor
,并设置乘数:0.5
,无需任何计算即可获得50%
所以,有很多需要理解和思考。我对你的原始代码做了一些编辑。这应该被视为您学习的“起点”,而不是“插入完成的代码”:
我想,你好像没有把座位视图添加到电影院视图中。您已经在init方法中添加了座椅视图,并在之后进行了设置。因此,当您将SeatView设置为cinema view时,它只会添加属性,而不会添加视图。我想你应该创建一些函数,比如addSeats(),在里面,你可以在电影院视图中添加座椅视图,并重新验证这个视图。@Sunilluitel我想我在中为座椅中的座椅添加了,也就是我调用了addSubview(seat)
@Koh-你希望你的滚动视图是主视图高度的1/2吗?然后里面的“电影院”视图距离滚动视图的顶部60分,50分高,填充滚动视图的宽度?@DonMag yes。我希望cinemaView位于我的scrollView中。我的cinemaView的大小现在看起来很荒谬,因为我正在测试它,但是我会在以后更改cinemaView的大小以适应不同的电影院大小。谢谢你的解决方案。由于某种原因,cinemaView.backgroundColor
确实被调用了。我尝试在其他地方调用它,比如在CinemaView和ViewController中,但没有发生。
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
}
}