How to position top in iOS swift?

630 Views Asked by At

I try to add a material swift card to the top of my view, but it always is shown too high. To set the height of the card fixes the problem but i don't want to set the height.

Here is what it looks like.

enter image description here

Here is a link to an image which shows how the card looks like normaly: https://camo.githubusercontent.com/f22d27c712a6fba12237a3e4b11f6e10c893d9ab/687474703a2f2f7777772e636f736d69636d696e642e636f6d2f676966732f77686974652f636172642e676966

And here is the code of my view:

import UIKit
import Material

class UserProfileView: UIView {


    fileprivate var card: Card!

    fileprivate var toolbar: Toolbar!
    fileprivate var moreButton: IconButton!

    fileprivate var contentView: UILabel!

    fileprivate var bottomBar: Bar!
    fileprivate var dateFormatter: DateFormatter!
    fileprivate var dateLabel: UILabel!
    fileprivate var favoriteButton: IconButton!

    convenience init(){
        self.init(frame: CGRect.zero)
        self.backgroundColor = UIColor(red:0.15, green:0.24, blue:0.37, alpha:1.0)

        prepareDateFormatter()
        prepareDateLabel()
        prepareFavoriteButton()
        prepareMoreButton()
        prepareToolbar()
        prepareContentView()
        prepareBottomBar()
        prepareImageCard()
        prepareMainView()
    }


    fileprivate func prepareMainView() {
        self.addSubview(self.card!)

        let views = [
            "card": self.card!
        ]
        self.card?.translatesAutoresizingMaskIntoConstraints = false
        let cardHorizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[card]-10-|", metrics: nil, views: views)
        let cardVerticalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[card]", metrics: nil, views: views)

        self.addConstraints(cardHorizontalConstraint)
        self.addConstraints(cardVerticalConstraint)
    }

}

extension UserProfileView {
    fileprivate func prepareDateFormatter() {
        dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .medium
        dateFormatter.timeStyle = .none
    }

    fileprivate func prepareDateLabel() {
        dateLabel = UILabel()
        dateLabel.font = RobotoFont.regular(with: 12)
        dateLabel.textColor = Color.blueGrey.base
        dateLabel.text = dateFormatter.string(from: Date.distantFuture)
    }

    fileprivate func prepareFavoriteButton() {
        favoriteButton = IconButton(image: Icon.favorite, tintColor: Color.red.base)
    }

    fileprivate func prepareMoreButton() {
        moreButton = IconButton(image: Icon.cm.moreVertical, tintColor: Color.blueGrey.base)
    }

    fileprivate func prepareToolbar() {
        toolbar = Toolbar(rightViews: [moreButton])

        toolbar.title = "Material"
        toolbar.titleLabel.textAlignment = .left

        toolbar.detail = "Build Beautiful Software"
        toolbar.detailLabel.textAlignment = .left
        toolbar.detailLabel.textColor = Color.blueGrey.base
    }

    fileprivate func prepareContentView() {
        contentView = UILabel()
        contentView.numberOfLines = 0
        contentView.text = "Material is an animation and graphics framework that is used to create beautiful applications."
        contentView.font = RobotoFont.regular(with: 14)
    }

    fileprivate func prepareBottomBar() {
        let clipboardButton = IconButton(image: UIImage(named: "clipboard_darken1.png"))
        let dashboardButton = IconButton(image: UIImage(named: "dashboard_darken1.png"))
        let bookmarkButton = IconButton(image: UIImage(named: "bookmark_darken1.png"))
        let dotsButton = IconButton(image: UIImage(named: "dots_darken1.png"))

        bottomBar = Bar()
        bottomBar.centerViews = [clipboardButton, dashboardButton, bookmarkButton, dotsButton]
    }

    fileprivate func prepareImageCard() {
        card = Card()

        card.toolbar = toolbar
        card.toolbarEdgeInsetsPreset = .square3
        card.toolbarEdgeInsets.bottom = 0
        card.toolbarEdgeInsets.right = 8

        card.contentView = contentView
        card.contentViewEdgeInsetsPreset = .wideRectangle3

        card.bottomBar = bottomBar
        card.bottomBarEdgeInsetsPreset = .wideRectangle2
    }
}

Here is the code of the controller where the view is loaded:

import UIKit
import Material

class UserProfileViewController: UIViewController {

    override func loadView(){
        self.view = UserProfileView()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

Does anyone know what's the Problem?

2

There are 2 best solutions below

1
On

Try adjusting this:

views["topLayoutGuide"] = topLayoutGuide
let cardVerticalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|[topLayoutGuide]-10-[card]", metrics: nil, views: views)

Another option is to replace this

fileprivate func prepareMainView() {
    self.addSubview(self.card!)

    let views = [
        "card": self.card!
    ]
    self.card?.translatesAutoresizingMaskIntoConstraints = false
    let cardHorizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[card]-10-|", metrics: nil, views: views)
    let cardVerticalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[card]", metrics: nil, views: views)

    self.addConstraints(cardHorizontalConstraint)
    self.addConstraints(cardVerticalConstraint)
}

with

fileprivate func prepareMainView() {
    view.layout(card!).horizontally(left: 10, right: 10).top(10)
}

That's it :)

Edit

Update to Material 2.4.3 to have this work perfectly.

0
On

The problem seems to be that status bar is 20 points high and view controller's view is pinned to the screen top. Your card 10 points below superview's top, so it ends up under status bar (10 points below status bar's bottom edge).

The solution is to use UIViewController's topLayoutGuide:

override func loadView() {
    // this will create default blank view and set it to the 'view' property
    super.loadView()

    let userProfileView = UserProfileView()
    view.addSubview(userProfileView)

    // pin userProfileView left and right edge to superview's left and right edges 
    // its top to view controller's topLayoutGuide
    // and its bottom to view controller's bottomLayoutGuide
}