Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
170 views
in Technique[技术] by (71.8m points)

ios - How to Address the Current View vs Superview confusion (Swift)

Using superview in the class paints the entire screen but I only want to paint the smaller subview (whose dimensions are defined by v.frame).

How do I have the class operate only on the "current view"?

@IBOutlet var storyboardView: UIView!

func selectView() {
    var v = UIView()
    switch viewchoice {
        case false:
            v = View1class()
        case true:
            v = View2class()
    }
    v.frame = CGRect(x: 20, y: 50, width: storyboardView.frame.width - 40, height: storyboardView.frame.height - 100)
    storyboardView.addSubview(v)
}

class View1class: UIView {
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        superview!.backgroundColor = .red
    }
}


class View2class: UIView {
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        superview!.backgroundColor = .blue
    }
}

I tried using self instead of superview but that doesn't work.

EDIT: If I wanted to paint the entire screen, could I skip creating the subview and assign the class to storyboardView?

question from:https://stackoverflow.com/questions/65645944/how-to-address-the-current-view-vs-superview-confusion-swift

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If you override draw(_ rect: CGRect) in a subclass, it is up to you to draw the view content. Setting .backgroundColor there will have no effect.

This is a common structure for a UIView subclass:

class View1Class: UIView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        self.backgroundColor = .red
        // do any other view setup here, such as
        //  adding subviews, adding sublayers, etc
    }
    
}

Edit

Here is an example of two custom views - the first one uses shape layers, the second one overrides draw():

MyFirstView class

class MyFirstView: UIView {
    
    let boxLayer = CAShapeLayer()
    let circleLayer = CAShapeLayer()
    let lineLayer = CAShapeLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        self.backgroundColor = .systemYellow

        layer.addSublayer(boxLayer)
        layer.addSublayer(circleLayer)
        layer.addSublayer(lineLayer)
        
        boxLayer.fillColor = UIColor.red.cgColor
        circleLayer.fillColor = UIColor.blue.cgColor
        lineLayer.strokeColor = UIColor.green.cgColor
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        // centered rectangle, half height and width
        let halfWidth: CGFloat = bounds.width * 0.5
        let halfHeight: CGFloat = bounds.height * 0.5
        let boxRect: CGRect = CGRect(x: halfWidth * 0.5, y: halfHeight * 0.5, width: halfWidth, height: halfHeight)
        let boxPath: UIBezierPath = UIBezierPath(rect: boxRect)
        boxLayer.path = boxPath.cgPath
        
        // circle centered in box, 3/4ths of the shorter of width or height
        let wh: CGFloat = min(boxRect.width, boxRect.height) * 0.75
        let circleRect: CGRect = CGRect(x: boxRect.midX - wh * 0.5, y: boxRect.midY - wh * 0.5, width: wh, height: wh)
        let circlePath: UIBezierPath = UIBezierPath(ovalIn: circleRect)
        circleLayer.path = circlePath.cgPath
        
        // diagonal line from top-left to bottom-right
        let linePath: UIBezierPath = UIBezierPath()
        linePath.move(to: .zero)
        linePath.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
        lineLayer.path = linePath.cgPath
        
    }
    
}

MySecondView class

class MySecondView: UIView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        self.backgroundColor = .systemTeal
    }

    override func draw(_ rect: CGRect) {
        
        // centered rectangle, half height and width
        let halfWidth: CGFloat = rect.width * 0.5
        let halfHeight: CGFloat = rect.height * 0.5
        let boxRect: CGRect = CGRect(x: halfWidth * 0.5, y: halfHeight * 0.5, width: halfWidth, height: halfHeight)
        let boxPath: UIBezierPath = UIBezierPath(rect: boxRect)
        
        UIColor.red.setFill()
        boxPath.fill()
        
        // circle centered in box, 3/4ths of the shorter of width or height
        let wh: CGFloat = min(boxRect.width, boxRect.height) * 0.75
        let circleRect: CGRect = CGRect(x: boxRect.midX - wh * 0.5, y: boxRect.midY - wh * 0.5, width: wh, height: wh)
        let circlePath: UIBezierPath = UIBezierPath(ovalIn: circleRect)
        
        UIColor.blue.setFill()
        circlePath.fill()
        
        // diagonal line from top-left to bottom-right
        let linePath: UIBezierPath = UIBezierPath()
        linePath.move(to: .zero)
        linePath.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        
        UIColor.green.setStroke()
        linePath.stroke()
        
    }

    override func layoutSubviews() {
        setNeedsDisplay()
    }
    
}

Example view controller

class CustomViewsViewController: UIViewController {
    
    let firstView = MyFirstView()
    let secondView = MySecondView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        [firstView, secondView].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)
        }
        
        // respect safe area
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // firstView Top / Leading / Trailing to view (safe-area)
            firstView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            firstView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
            firstView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),

            // firstView Height
            firstView.heightAnchor.constraint(equalToConstant: 150.0),
            
            // secondView Leading / Trailing to view (safe-area)
            secondView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 60.0),
            secondView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -60.0),

            // secondView Top 20-pts from firstView Bottom
            secondView.topAnchor.constraint(equalTo: firstView.bottomAnchor, constant: 20.0),

            // secondView Bottom to View Bottom (safe-area)
            secondView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),

        ])
        
    }
    
}

Output - first view has .systemYellow background, second view has .systemTeal background:

enter image description here

and rotated:

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...