Problems with UIScrollView size - ios

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
}
}

Related

How to Make TableView scroll inside ScrollView behave naturally

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
}
}
}

Set Height of UIView on the basis of the content inside

I am adding an OverlayView to a Controller. I have set all the constraints to my OverlayView except the bottom constraint. I have a button at the end of my view. I am setting the size of the OverlayView as button.frame.maxY + margin. But it's not setting up the right height.
override func layoutSubviews() {
sizeToFit()
var sizeThatFits: CGSize = bounds.size
sizeThatFits.width = UIScreen.main.bounds.size.width - popupSizeHorizontalMargin
sizeThatFits.height = getStartedButton.frame.maxY + popupBottomMargin
let newFrame = CGRect(x: popupOriginX, y: bounds.midY - sizeThatFits.height/2, width: sizeThatFits.width, height: sizeThatFits.height)
frame = newFrame
}
This can be accomplished according to this [inner elements are example]
OverlayView
-> label ------> top to overlayView ,left,right
-> button -----> top to label , left , right
-> label -----> top to button , left , right , bottom to overlayView
The overlay view or outer view can calculate its height based on the size of elements inside it and their intrinsic size. Instead of specifying height constraint for overlay view or bottom constraint, add bottom constraint of overlay view to the last element inside the overlay view. This will satisfy the constraints and your overlay view will expand based on its contents.
Simply ctrl drag from your overlay view to the last inner view and select Bottom Space to Container.
You need to override intrinsicContentSize in UIView and return your custom size:
class YourCustomView: UIView {
override var intrinsicContentSize: CGSize {
var someYourSize = CGSize()
// ... calculate your size
return someYourSize
}
}
It will automatically update YourCustomView size to your custom calculated size using autolayout or when you want to update size manually via code - call invalidateIntrinsicContentSize() on YourCustomView object

how to get current size of a subview when device size changes in swift?

I have to view: view_1 and view_2 . view_1 height is proportional to the main view controller height and I am adding view_2 programmatically as a subview of view_1 with a proportional height.
Problem
when the device size changes say from iPhone 6 to iPhone 5, the view_1 adjust correctly but its height I am passing to a function to draw its subview view_2 is still what was set in interface builder and so it is out of bounds in iPhone 4 moving from iPhone 6
Thus I want to know how can I get the correct size of a view that what resize automatically to fit the current device?
The size of the view isn't established until Auto Layout runs. Your first opportunity to get the correct size is in viewDidLayoutSubviews:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// access view size here
}
Here's a complete example that adds a second view as a subview of the first view. The red view was added in the Storyboard; it is centered horizontally and vertically and it's height/width is 50% of its superview.
The yellow view is added programmatically. It's frame is computed from the frame of the red view to be 50% of the width of the red view.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var view1: UIView!
var view2: UIView?
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if view2 == nil {
view2 = UIView()
view2?.backgroundColor = .yellowColor()
view1.addSubview(view2!)
}
let width = view1.frame.size.width
let height = view1.frame.size.height
let frame = CGRect(x: width * 0.25, y: height * 0.25, width: width * 0.5, height: height * 0.5)
view2?.frame = frame
}
}
Not that viewDidLayoutSubviews gets called multiple times, so you must take care not to add view2 every time it is called. That is why the code checks to see if view2 has been added.
Try this,you can find the screen size of device.
let screenSize: CGRect = UIScreen.mainScreen().bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
Try to do this in Viewdidload
First you need to set view one frame
view_1.frame = CGRectMake(0 , 0, self.view.frame.width, self.view.frame.height)
then set frame of view_2
view_2.frame = CGRectMake(0 , 0, view_1.frame.width, view_1.frame.height)

How to resize UITableView width to fit its content?

Is there possible way to adjust table view width by width of biggest text that should be set in the cellTitle label?
iOS 8 , SWIFT
public override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Set the popover tableview width to be max compressed size (assumes all cells visible)
let maxWidth = tableView.visibleCells.reduce(0.0) { (currentMax, cell) -> CGFloat in
return max(currentMax, cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).width)
}
var contentSize = tableView.contentSize
contentSize.width = maxWidth
tableView.contentSize = contentSize
tableView.bounds.size = contentSize
}
Set a width auto-layout constraint to the table view.
Set an outlet from the constraint to your code (ctrl+drag, just like a view).
When you have the size of the label (if the label also has auto-layout then you will have it at viewDidLayoutSubviews) set the width to the table like so:
- (void)viewDidLayoutSubviews {
self.myTableWidthConstraint.constant = self.myLabel.frame.size.width;
[self.myTableView updateConstraints];
[self.myTableView layoutIfNeeded];
}
You should be able to do that in the size inspector.

Swift: UITableView increments layoutSubviews() when scrolling

I have a table view with custom cell in Swift that contains a horizontal layout UIView. I have noticed that when scrolling the correctly positioned subview in the horizontal view starts to multiply. I guess this has something to do with layoutSubviews() being called when table scrolls and the fact tableview recycles its cells when hidden and shows them when needed, but ignores currently positioned subviews..
It looks something like this
There's already a similar question from before, but it has no good answer.
UIScrollview calling superviews layoutSubviews when scrolling?
Here's the code I'm using inside my custom cell for horizontal positioning:
class HorizontalLayout: UIView {
var xOffsets: [CGFloat] = []
override func layoutSubviews() {
var width: CGFloat = 0
for i in 0..<subviews.count {
var view = subviews[i] as UIView
view.layoutSubviews()
width += xOffsets[i]
view.frame.origin.x = width
width += view.frame.width
}
self.frame.size.width = width
}
override func addSubview(view: UIView) {
xOffsets.append(view.frame.origin.x)
super.addSubview(view)
}
func removeAll() {
for view in subviews {
view.removeFromSuperview()
}
xOffsets.removeAll(keepCapacity: false)
}
}
Taken from here: https://medium.com/swift-programming/dynamic-layouts-in-swift-b56cf8049b08
Using inside custom cell like so:
func loadStops(stops:[String]) {
for stop in stops {
// just testing purposes only
let view = UIView(frame: CGRectMake(10, 0, 40, 40))
view.backgroundColor = UIColor.redColor()
stopsView.addSubview(view)
}
}
Is there a way to fix this problem and prevent the subview of being multiplied when scrolling and perhaps a better way to position subviews horizontally in a tableview cell?

Resources