I want to set my view to be a UITableView without adding to the main view, that is I don't want to call self.view.addSubview(tableView)
However, my loadView() does not seem to be working - the position and size of the tableView are ambiguous...
override func loadView() {
super.loadView()
let tv = UITableView(frame: self.view.frame)
tv.backgroundColor = Constants.Colors.translucentLightGrey
tv.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tv.dataSource = self
tv.delegate = self
tv.backgroundColor = .red
view = tv
tableView = tv
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0).isActive = true
tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -0).isActive = true
tableView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
}
How can I set the tableview as the view?
Related
I have created a scroll view and I have tried many different methods as you can see below, however I always get the same outcome where the scroll view moves horizontally. I want it to move vertically, but it is not. Also, the text view shows the entire message in one line and does not use multiple lines as was happening before I added the scroll view.
import UIKit
import SafariServices
class MainView: UIViewController {
let transition = MainDropMenuAnimation()
let scrollView = UIScrollView()
let scrollViewView = UIView()
let factView = QuickFact()
let socialMediaSV = SocialMediaSV()
let logo = UIImageView()
let aboutUs = UITextView()
let dropMenuButton = UIButton(type: .custom)
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(patternImage: #imageLiteral(resourceName: "HomeBackground"))
addQuickFactView()
setupScrollView()
setupNavBar()
}
func setupNavBar() {
navigationItem.title = "Home"
navigationController?.navigationBar.barTintColor = .clear
dropMenuButton.setImage(#imageLiteral(resourceName: "dropMenuButton"), for: .normal)
dropMenuButton.addTarget(self, action: #selector(handleDropMenu), for: .touchUpInside)
dropMenuButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
dropMenuButton.widthAnchor.constraint(equalTo: dropMenuButton.heightAnchor).isActive = true
let leftButton = UIBarButtonItem(customView: dropMenuButton)
self.navigationItem.leftBarButtonItem = leftButton
}
#objc func handleDropMenu() {
let dropMenu = DropViewContainer()
dropMenu.modalPresentationStyle = .overCurrentContext
dropMenu.transitioningDelegate = self
present(dropMenu, animated: true)
}
func addQuickFactView() {
addChild(factView)
view.addSubview(factView.view)
factView.didMove(toParent: self)
factView.view.translatesAutoresizingMaskIntoConstraints = false
factView.view.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
factView.view.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
factView.view.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
factView.view.heightAnchor.constraint(equalToConstant: 200).isActive = true
}
func setupScrollView() {
setupView()
scrollView.contentSize.height = 3000
view.addSubview(scrollView)
positionScrollView()
}
func positionScrollView() {
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: factView.view.bottomAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
func setupView() {
setupLogo()
setupAboutUs()
setupSocialMediaSV()
scrollView.addSubview(scrollViewView)
positionView()
}
func positionView() {
scrollViewView.translatesAutoresizingMaskIntoConstraints = false
scrollViewView.rightAnchor.constraint(equalTo: scrollView.rightAnchor).isActive = true
scrollViewView.leftAnchor.constraint(equalTo: scrollView.leftAnchor).isActive = true
scrollViewView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
scrollViewView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
}
func setupLogo() {
logo.image = #imageLiteral(resourceName: "Logo")
scrollViewView.addSubview(logo)
positionLogo()
}
func positionLogo() {
logo.translatesAutoresizingMaskIntoConstraints = false
logo.widthAnchor.constraint(equalToConstant: 200).isActive = true
logo.heightAnchor.constraint(equalToConstant: 200).isActive = true
logo.centerXAnchor.constraint(equalTo: scrollViewView.centerXAnchor).isActive = true
logo.topAnchor.constraint(equalTo: scrollViewView.topAnchor, constant: 20).isActive = true
}
func setupAboutUs() {
let aboutUsText = (NSMutableAttributedString(string: "About Us\n", attributes: [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 25)]))
aboutUsText.append(NSMutableAttributedString(string: "At Cleaner Together, we are commited to promoting recycling, reusing, and reducing (and of course composting), while spreading sanitization and cleanliness around the world. At the moment, we are just encouraging proper waste disposal, however with proper funding we have many projects we hope to accomplish.", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17), NSAttributedString.Key.foregroundColor: UIColor.black]))
aboutUs.attributedText = aboutUsText
aboutUs.textColor = .black
aboutUs.textAlignment = .left
aboutUs.isScrollEnabled = false
aboutUs.isEditable = false
aboutUs.backgroundColor = .init(white: 1.0, alpha: 0.5)
aboutUs.layer.cornerRadius = 20
scrollViewView.addSubview(aboutUs)
positionAboutUs()
}
func positionAboutUs() {
aboutUs.translatesAutoresizingMaskIntoConstraints = false
aboutUs.rightAnchor.constraint(equalTo: scrollViewView.rightAnchor, constant: -20).isActive = true
aboutUs.leftAnchor.constraint(equalTo: scrollViewView.leftAnchor, constant: 20).isActive = true
aboutUs.heightAnchor.constraint(equalToConstant: 200).isActive = true
aboutUs.topAnchor.constraint(equalTo: logo.bottomAnchor, constant: 20).isActive = true
}
func setupSocialMediaSV() {
addChild(socialMediaSV)
scrollViewView.addSubview(socialMediaSV.view)
socialMediaSV.didMove(toParent: self)
socialMediaSV.view.translatesAutoresizingMaskIntoConstraints = false
socialMediaSV.view.centerXAnchor.constraint(equalTo: scrollViewView.centerXAnchor).isActive = true
socialMediaSV.view.widthAnchor.constraint(equalToConstant: 240).isActive = true
socialMediaSV.view.topAnchor.constraint(equalTo: aboutUs.bottomAnchor, constant: 20).isActive = true
socialMediaSV.view.heightAnchor.constraint(equalToConstant: 40).isActive = true
}
}
extension MainView: UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
transition.isPresenting = true
return transition
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
transition.isPresenting = false
return transition
}
}
You should check your constraints and make sure that your scroll view has correct contentSize.
Make scrollViewView left and right anchors also equalTo viewController's view. In func positionView()
I have a scroll view in which I have a content view. I set the scroll view's top anchor to be just above the bottom of an image. I set the content view's top anchor to actually be at the bottom of the image. That way you can pull down on the content and reveal up to the bottom of the image without being able to pull the content view down any further. However, this is causing the content to jump.
Here is my code:
class HomeParallaxScrollViewController: UIViewController {
private let topImageView = UIImageView(image: UIImage(named: "cat"))
private let contentView = UIView()
private let scrollView = UIScrollView()
private let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .gray
topImageView.contentMode = .scaleAspectFill
contentView.backgroundColor = .white
label.text = "SOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT"
label.textColor = .black
label.numberOfLines = 0
[contentView, label, topImageView, scrollView].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
scrollView.addSubview(contentView)
contentView.addSubview(label)
view.addSubview(topImageView)
view.addSubview(scrollView)
NSLayoutConstraint.activate([
topImageView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
topImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
topImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
topImageView.heightAnchor.constraint(equalToConstant: 200),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor),
scrollView.topAnchor.constraint(equalTo: topImageView.bottomAnchor, constant: -30),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
contentView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
contentView.topAnchor.constraint(lessThanOrEqualTo: topImageView.bottomAnchor), //This is what's causing the glitch
label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
label.topAnchor.constraint(equalTo: contentView.topAnchor),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
}
}
And here is that is happening:
Trying to add another top constraint -- particularly to an element outside the scroll view -- is a bad idea, and, as you see, won't work. I'm sure you noticed auto-layout conflict messages being generated.
One approach is to implement scrollViewDidScroll delegate func:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// limit drag-down in the scroll view to the overlap size
scrollView.contentOffset.y = max(scrollView.contentOffset.y, -30)
}
As the user drags-down to scroll, it will stop at 30-points.
Here is your example, with slight modifications -- I don't have your .plBackgroundLightGray or .PLSemiboldFont and I added an image load for the top image view -- but this should run as-is:
// conform to UIScrollViewDelegate
class HomeParallaxScrollViewController: UIViewController, UIScrollViewDelegate {
private let topImageView = UIImageView(image: UIImage(named: "cat"))
private let contentView = UIView()
private let scrollView = UIScrollView()
private let label = UILabel()
// this will be the "overlap" of the scroll view and top image view
private var scrollOverlap: CGFloat = 30.0
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// limit drag-down in the scroll view to scrollOverlap points
scrollView.contentOffset.y = max(scrollView.contentOffset.y, -scrollOverlap)
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .lightGray // .plBackgroundLightGray
topImageView.contentMode = .scaleAspectFill
if let img = UIImage(named: "background") {
topImageView.image = img
}
contentView.backgroundColor = .white
label.text = "SOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT\n\n\nSOME\n\n\nRANDOM\n\n\nCONTENT"
label.font = UIFont.boldSystemFont(ofSize: 16) // .PLSemiboldFont(size: 16)
label.textColor = .black
label.numberOfLines = 0
[contentView, label, topImageView, scrollView].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
scrollView.addSubview(contentView)
contentView.addSubview(label)
view.addSubview(topImageView)
view.addSubview(scrollView)
NSLayoutConstraint.activate([
topImageView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
topImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
topImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
topImageView.heightAnchor.constraint(equalToConstant: 200),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor),
scrollView.topAnchor.constraint(equalTo: topImageView.bottomAnchor, constant: scrollOverlap),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
contentView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
// nope, not a good idea -- will cause constraint conflicts
//contentView.topAnchor.constraint(lessThanOrEqualTo: topImageView.bottomAnchor), //This is what's causing the glitch
label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
label.topAnchor.constraint(equalTo: contentView.topAnchor),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
// set delegate to self
scrollView.delegate = self
}
}
How to make a NSTextView scrollable ?
Problem:
Text View is displayed but is not scrollable. I have to resize the window to see more contents
Question:
How to make the text view scrollable.
Code:
class ViewController: NSViewController {
private let textView = NSTextView()
//MARK: Manage Views
override func viewDidLoad() {
super.viewDidLoad()
setupTextView()
}
private func setupTextView() {
textView.isEditable = false
view.addSubview(textView)
textView.translatesAutoresizingMaskIntoConstraints = false
textView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
textView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
textView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
textView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
}
NSTextView doesn't scroll, place the text view inside a NSScrollView. Class method scrollableTextView() of NSTextView returns a NSTextView in a NSScrollView.
private var textView:NSTextView?
private func setupTextView() {
let scrollView = NSTextView.scrollableTextView()
textView = scrollView.documentView as? NSTextView
textView?.isEditable = false
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
My UILabel is pinned to the top of the cell, just like UIImage but if the text below has f.e. 1 line (its also in UILabel) my top UILabel is in other place.
Here are my constraints and labels declaration. Thanks to anyone who will try to solve my problem :) I tried using sizeToFit method on my UILabels
var albumImage: UIImageView = {
let view = UIImageView()
view.translatesAutoresizingMaskIntoConstraints = false
view.contentMode = .scaleAspectFit
return view
}()
var albumName: UILabel = {
let view = UILabel()
view.translatesAutoresizingMaskIntoConstraints = false
view.numberOfLines = 0
view.sizeToFit()
return view
}()
var bandName: UILabel = {
let view = UILabel()
view.translatesAutoresizingMaskIntoConstraints = false
view.sizeToFit()
return view
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
drawLayout()
}
required init?(coder aDecoder: NSCoder) {
fatalError("ERROR")
}
func drawLayout(){
let guide = self.safeAreaLayoutGuide
//albumImage
addSubview(albumImage)
addSubview(albumName)
addSubview(bandName)
albumImage.heightAnchor.constraint(equalToConstant: 50).isActive = true
albumImage.widthAnchor.constraint(equalToConstant: 50).isActive = true
albumImage.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: 8).isActive = true
albumImage.topAnchor.constraint(equalTo: self.topAnchor, constant: 8).isActive = true
albumImage.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -8).isActive = true
//albumTitle
albumName.topAnchor.constraint(equalTo: bandName.bottomAnchor).isActive = true
albumName.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -8).isActive = true
albumName.leadingAnchor.constraint(equalTo: albumImage.trailingAnchor, constant: 8).isActive = true
albumName.trailingAnchor.constraint(equalTo: guide.trailingAnchor, constant: -8).isActive = true
//bandName
bandName.topAnchor.constraint(equalTo: albumImage.topAnchor).isActive = true
bandName.leadingAnchor.constraint(equalTo: albumImage.trailingAnchor, constant: 8).isActive = true
}
I have weird problem, because I can't fill whole area of super view using layout anchor
this is my code from custom UIView class:
private func setupTableView() {
addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
let margins = layoutMarginsGuide
let trailingAnchor = tableView.trailingAnchor.constraint(equalTo: margins.trailingAnchor)
let leadingAnchor = tableView.leadingAnchor.constraint(equalTo: margins.leadingAnchor)
let topAnchor = tableView.topAnchor.constraint(equalTo: margins.topAnchor)
let bottomAnchor = tableView.bottomAnchor.constraint(equalTo: margins.bottomAnchor)
NSLayoutConstraint.activate([trailingAnchor, leadingAnchor, topAnchor, bottomAnchor])
}
and in result I get weird margins on the left and right site:
You are laying out your tableView relative to the margins of the layoutMarginsGuide. If you want it to go to the edges of your UIView, then you need to use the anchors of the UIView:
private func setupTableView() {
addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
let trailingAnchor = tableView.trailingAnchor.constraint(equalTo: trailingAnchor)
let leadingAnchor = tableView.leadingAnchor.constraint(equalTo: leadingAnchor)
let topAnchor = tableView.topAnchor.constraint(equalTo: topAnchor)
let bottomAnchor = tableView.bottomAnchor.constraint(equalTo: bottomAnchor)
NSLayoutConstraint.activate([trailingAnchor, leadingAnchor, topAnchor, bottomAnchor])
}