Not able to lay out Subviews on a custom UIView in Swift

送分小仙女□ 提交于 2019-12-13 03:33:13

问题


So I have created this custom container view which I am laying out using autolayout constraint.

    func configureSegmentContainerView() {
    segmentContainerView.topAnchor.constraint(equalTo: view.topAnchor, constant: 40).isActive = true
    segmentContainerView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8).isActive = true
    segmentContainerView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8).isActive = true
    segmentContainerView.heightAnchor.constraint(equalToConstant: 3).isActive = true 
    }

In the view controller, the viewDidLoad() is this:

    setupDataSource()
    segmentContainerView = ATCStorySegmentsView()
    view.addSubview(segmentContainerView)
    configureSegmentContainerView()
    segmentContainerView.translatesAutoresizingMaskIntoConstraints = false
    segmentContainerView.numberOfSegments = friendStory.count

Now once the data source is setup and I have the friendStory count, I am assigning it to segmentContainerView.numberofSegments

In segmentContainerview class this is what is happening:

    var numberOfSegments: Int? {
    didSet {
        addSegments()
    } 
  }

In addSegments(), I am adding UIViews depending upon the numberOfSegments this is the code for that:

 private func addSegments() {
    guard let numberOfSegments = numberOfSegments else { return }
    layoutIfNeeded()
    setNeedsLayout()
    for i in 0..<numberOfSegments {
        let segment = Segment()
        addSubview(segment.bottomSegment)
        addSubview(segment.topSegment)
        configureSegmentFrame(index: i, segmentView: segment)
        segmentsArray.append(segment)
    }
}

private func configureSegmentFrame(index: Int, segmentView: Segment) {
    guard let numberOfSegments = numberOfSegments else { return }
    let widthOfSegment : CGFloat = (self.frame.width - (padding * CGFloat(numberOfSegments - 1))) / CGFloat(numberOfSegments)

    let i = CGFloat(index)

    let segmentFrame = CGRect(x: i * (widthOfSegment + padding), y: 0, width: widthOfSegment, height: self.frame.height)
    segmentView.bottomSegment.frame = segmentFrame
    segmentView.topSegment.frame = segmentFrame
    segmentView.topSegment.frame.size.width = 0
}

**Question and Issue: ** Instead of getting 4 UIViews, I am getting 3, but the third one is not correctly placed and is going outside the parent container. How can I get these uiviews aligned correctly. I am guessing there is some issue with where setNeedsLayout() and layoutIfNeeded() needs to be called. Please help.

Segment is a struct with two properties - bottomSegment and topSegment. Both being UIView

You can see how just three UIView segments appear. I needs to 4 (numberOfSegments = 4) of these. Also I am giving the parent container constant of 8 and -8 for right and leftAnchor. so all 4 segments need to be placed within this view. As you can see in the picture above the last segment is going outside of the parent container.


回答1:


Try to call addSegments at onViewDidAppear. If it works, it means that in your code the view does not still have the correct frame.

For this to work you need to adapt the frames of the views, when the view controller's view changed:

override func viewDidLayoutSubviews() {
     super.viewDidLayoutSubviews()
     guard let numberOfSegments = numberOfSegments else { return }
     for i in 0..<numberOfSegments {
        configureSegmentFrame(index: i, segmentView: segment)
    }
}

You will probably have to do it cleaner, but it should work.




回答2:


The problem is that

let widthOfSegment : CGFloat = (self.frame.width ...

is being called too soon. You cannot do anything in that depends upon self having its frame until after it has its real frame.

For a UIView, that moment is after layoutSubviews has been called for the first time.



来源:https://stackoverflow.com/questions/56665550/not-able-to-lay-out-subviews-on-a-custom-uiview-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!