I have vertical scrollView with contentSize height larger than window height. But it doesn't scroll. It even doest scroll if I set scrollView.contentSize.height = 2000
Height of scrollView is calculated on viewWillAppear when I add childviewcontroller.
code is following
self.parentView.addSubview(gameInfoMainViewController!.view)
gameInfoMainViewController!.view.frame = self.parentView.bounds
gameInfoMainViewController!.view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
gameInfoMainViewController!.view.frame.size.height = gameInfoMainViewControllerHeight!
on line where subview is added a delegate method is being called which is
func passGameInfoTeamsViewControllerHeight(height:CGFloat) {
gameInfoTeamsViewControllerHeight = height
parentView.frame.size.height = gameInfoTeamsViewControllerHeight!
parentView.layoutIfNeeded()
scrollView.contentSize.height = gameInfoTeamsViewControllerHeight! + segmentedControll!.frame.height + headerView.frame.size.height + 64
}
The most strange thing is that scroll is working if I call this code again
self.parentView.addSubview(gameInfoMainViewController!.view)
gameInfoMainViewController!.view.frame = self.parentView.bounds
gameInfoMainViewController!.view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
gameInfoMainViewController!.view.frame.size.height = gameInfoMainViewControllerHeight!
Any ideas ?
Related
I need to do this app. The view hierarchy goes like this
UIScrollView
-UIView (Main View)
--UIView (Top View Container)
--UITableview
When scrolling up the Main View, If table view has many cells, the table view should go to the top, and once it reaches the top. The user should be able to scroll the table view cells. I was able to achieve it but it doesn't scroll naturally.
Attached my code https://github.com/iamshimak/FinchHomeScreenRedesign.git
First, never put tableview inside a scrollview, it's a bad practice. You could just use tableview header and embed any type of view do you want before the tableview cells.
here's a snipeste on how I deal with it:
//MARK: ConfigureTableView
private func configureTableView(){
let footerView = UIView()
footerView.frame.size.height = 50
footerView.backgroundColor = .white
self.tableView.tableFooterView = footerView
self.tableView.tableHeaderView = self.headerView
var newFrame = headerView.frame
newFrame.size.width = view.bounds.width
newFrame.size.height = 300
headerView.frame = newFrame
tableView.backgroundView = UIView()
tableView.backgroundView?.addSubview(backgroundTableView)
}
as you can see, I embedded a UIView as a footer and another UIView named headerView as a header
but if you insist of using a tableview inside a scrollview, you can try using a scrollview delegate and detech which scrollview is scrolling
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let yOffset = scrollView.contentOffset.y
if scrollView == self.scrollView {
if yOffset >= scrollViewContentHeight - screenHeight {
// logic when using scrollview
}
}
if scrollView == self.tableView {
if yOffset <= 0 {
// logic when using tableview scrollView
}
}
}
I am using auto layout.
I am loading UIView from xib.
All elements have static size except UITextView.
I've disabled scroll on UITextView
UITextView is filled with the text of different size on ViewDidLoad(). So it can be 1 line or 7 lines there for example.
I am loading this UIView with the following method:
fileprivate func setTableHeaderView() {
guard let _headerView = UINib(nibName: "TableHeaderView",
bundle: nil).instantiate(withOwner: self, options: nil)[0] as? UIView else { return }
tableView.tableHeaderView = UIView(frame:
CGRect(x: 0, y: 0, width: tableView.frame.width, height: _headerView.frame.size.height))
configureViewController() // here I set the text for UITextView
tableView.tableHeaderView?.addSubview(_headerView)
}
When I load this UIView the height is always the same both before and after layoutSubviews. Actually the size always is equal to the initial size of the xib that is set in the Size Inspector of XCode.
I want to UITextView to fit the text size and to have different xib UIView size that will depend on the size of UITextView + all other elements + constraints.
I've tried different ways to implement this but but none did not help. What I've tried:
to set constraints in different ways
to call layoutSubviews() forcibly and check the size of the resulted UIView
to check size of UIView after viewDidLayoutSubviews
translatesAutoresizingMaskIntoConstraints = true with autoresizingMask = .flexibleHeight
Is it possible to implement this idea in such way?
Try to override viewDidLayoutSubviewsMethod
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Dynamic sizing for the header view
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
var headerFrame = headerView.frame
// If we don't have this check, viewDidLayoutSubviews() will get
// repeatedly, causing the app to hang.
if height != headerFrame.size.height {
headerFrame.size.height = height
headerView.frame = headerFrame
tableView.tableHeaderView = headerView
}
}
}
I try at the moment to resize the UIScrollView dynamically like in Android with wrap_content as attribute.
The data comes over a SQL Query that i start in the override func viewDidLoad()
I tried the freeform size variant and the version with extension
extension UIScrollView {
func resizeScrollViewContentSize() {
var contentRect = CGRect.zero
for view in self.subviews {
contentRect = contentRect.union(view.frame)
}
self.contentSize = contentRect.size
}
}
But nothing helps. Has Someone an idea?
EDIT:
#Stephen J I didn't understand your answer, sorry :(
I have a subview, too but how I can say the Scrollview that equals his size? I tried it with CTRL + Drag the mouse on the Scrollview and the same in the other direction.
So it looks at my Storyboard
The idea is OK, but...
Your extension is looping through the subviews of the Scroll view, but your Scroll view contains only ONE subview - your ContentView... and that view contains a bunch of subviews. (Actually, the Scroll view's subviews property also contains the scrollIndicator bars, but that doesn't really factor in here).
What you want to do is loop through the subviews of your ContentView, then change its size, and then set the .contentSize of the Scroll view based on the ContentView.
So...
// init empty rect
var contentRect = CGRect.zero
// for each subview in the ** Content ** view - NOT in the Scroll view
for view in theContentView.subviews {
// union the view's rect with the "total" rect
contentRect = contentRect.union(view.frame)
}
// set the frame size of the Content view to the "total" rect size
theContentView.frame.size = contentRect.size
// increast the size of the "total" rect by the Content view's x,y offsets
contentRect.size.width += theContentView.frame.origin.x
contentRect.size.height += theContentView.frame.origin.y
// NOW we can set the contentSize of the Scroll view
theScrollView.contentSize = contentRect.size
Personally, I've found using auto-layout and constraints to make working with Scroll views really, really easy - easier than this method, because you don't have to keep re-calculating. But, if this works for you, great :)
Edit: Here is a complete working example. It:
creates a ScrollView sized to the full view
adds a ContentView without size
adds 30 labels vertically with 16 pts spacing
then calculates and sets the size of the ContentView and the .contentSize of the Scroll view based on the ContentView's subviews
//
// ViewController.swift
// SWScrollNoAutoLayout
//
// Created by Don Mag on 6/14/17.
// Copyright © 2017 DonMag. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let theScrollView = UIScrollView()
let theContentView = UIView()
theScrollView.frame = self.view.bounds
theScrollView.backgroundColor = .orange
theContentView.backgroundColor = .yellow
self.view.addSubview(theScrollView)
theScrollView.addSubview(theContentView)
var yOffset: CGFloat = 0.0
for i in 1...30 {
let lbl = UILabel()
lbl.text = "Label: \(i)"
lbl.backgroundColor = .cyan
lbl.sizeToFit()
lbl.frame.origin.y = yOffset
theContentView.addSubview(lbl)
yOffset += lbl.frame.size.height + 16
}
// init empty rect
var contentRect = CGRect.zero
// for each subview in the ** Content ** view - NOT in the Scroll view
for view in theContentView.subviews {
// union the view's rect with the "total" rect
contentRect = contentRect.union(view.frame)
}
// set the frame size of the Content view to the "total" rect size
theContentView.frame.size = contentRect.size
// increast the size of the "total" rect by the Content view's x,y offsets
contentRect.size.width += theContentView.frame.origin.x
contentRect.size.height += theContentView.frame.origin.y
// NOW we can set the contentSize of the Scroll view
theScrollView.contentSize = contentRect.size
}
}
I'm trying to create a UITableView with a header view using autolayout using storyboards. It looks fine in Xcode, but when I run the app, it does not look the same.
In Xcode:
In the app:
The image has a constraint for 150x150, and there are 8-high constraints between the top-image, image-middle label, middle description-label and description label-bottom.
Both labels have numberOfRows set to 0 and lineBreakMode set to ByWordWrapping.
I have tried settings the frame via:
if let headerView = self.tableView.tableHeaderView {
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
println("Setting height to \(height)")
var headerFrame = headerView.frame
headerFrame.size.height = height
headerView.frame = headerFrame
self.tableView.tableHeaderView = headerView
}
One of the original issues was that I had some erroneous constraints (that for some reason Xcode only started complaining about today), so I have removed those and set a contentHuggingPriority of 252 (higher than all others) on the app name label. When I resize the header view manually in the storyboard the image and app name label stay the same height, and the description label grows. It would appear that the apps uses the size of the header in the storyboard at run time, and doesn't get the height from its children.
Answering my own question here:
There are 2 steps that seem to get this to work. The first is in ViewDidLoad, and the second is in viewDidLayoutSubviews:
var headerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
if let currentTableHeaderView = self.tableView.tableHeaderView {
currentTableHeaderView.removeFromSuperview()
}
// Setting the table header view with a height of 0.01 fixes a bug that adds a gap between the
// tableHeaderView (once added) and the top row. See: http://stackoverflow.com/a/18938763/657676
self.tableView.tableHeaderView = UIView(frame: CGRectMake(0, 0, CGRectGetWidth(self.tableView.frame), 0.01))
self.headerView = AboutTableViewHeaderView(frame: CGRectZero)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let tableHeaderView = self.headerView {
var frame = CGRectZero
frame.size.width = self.tableView.bounds.size.width
frame.size.height = tableHeaderView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
if self.tableView.tableHeaderView == nil || !CGRectEqualToRect(frame, tableHeaderView.frame) {
tableHeaderView.frame = frame
tableHeaderView.layoutIfNeeded()
self.tableView.tableHeaderView = tableHeaderView
}
}
}
Hopefully that all makes sense. The viewDidLayoutSubview code is via http://osdir.com/ml/general/2014-06/msg19399.html
I'm attempting to add a scrollview behind cell contents in a UICollectionViewCell. However, once I add it, didSelectCell... does not work anymore. Any ideas?
func build(){
scrollView = UIScrollView(frame: self.bounds)
scrollView.scrollEnabled = true
//Move the cell contents into the scrollview
self.backgroundView = scrollView
self.contentView.removeFromSuperview()
scrollView.addSubview(self.contentView)
var contentSize = self.bounds
contentSize.size.width += 100
self.scrollView.contentSize = contentSize.size
}