No scrollbars appear when adding a custom view via addSubview to NSScrollView - swift

I dynamically want to add a custom NSView as a content of a NSScrollView via code in runtime.
So I added a NSScrollView to my NSWindow, created an outlet to this NSScrollView and add my custom view.
#IBOutlet var myScrollView: NSView!
#IBOutlet var myCustomView: NSView!
myScrollView.addSubview(myCustomView)
This works fine (the content of myCustomView is shown in the NSScrollView) but the NSScrollView scrollbars are disabled and the content (that is larger than the NSScrollView) cannot be scrolled.
Is there something I am missing?
Thanks!

To add scrollable content to a NSScrollView you should set documentView and not via addSubview(_:)
let myView = MyView(frame: <somerect>)
scrollView.documentView = myView
If scrolling is still not working you may need to specify contentSize
Docs for NSScrollView

Related

My ScrollView is not scrolling vertically

I'm writing an app in Xcode 9 with Swift 4 and I've added a UIScrollview to a view which is intended to show a jPeg which is 3030 pixels in height. I've added the scrollview to my view and assigned the delegate in Outlets in IB. I've attached the IBOutlet called scrollView to the UIScrollview and added a UIImageView with the jPeg to the UIScrollview. I've set the size of the UIScrollView to 375W and 620H and then set the UIImageView to 375W and 3030H. this should complete the work in Interface builder.
In the Controller I've added UIScrollViewDelegate to the Class and added the code below to ViewDidLoad
//scrollView.delegate = self
scrollView.contentSize = CGSize(width: 375, height: 3040)
I've commented out the delegate line as I've done that in IB. When I run the app, the screen comes upon with the image but when I try to scroll it barely scrolls more than one screen. What have I missed?
You need to add a UIView inside your scrollview and then add that view top/bottom/leading/trailing 0 to scrollview then add your image view inside view and add image view bottom constraint to that view, So your scroll view will work properly.
Please refer below image for more details.
You have to place your scroll view inside a UIView and another UIView inside your scroll view.
Outer view Constraints: Leading,trailing,top and bottom - 0
Scroll view Constraints: Leading,trailing,top and bottom - 0
Inner view Constraints: Leading,trailling and top to Superview, Equal width to Outer view , Bottom space to -250 and Height equals 900(Height of your content)
Set your contentsize now.
You can implement as below image screen shots
//Height Constant of image
#IBOutlet weak var ConstHeight: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 11.0, *) {
self.scrollView.contentInsetAdjustmentBehavior = .never
}else{
self.automaticallyAdjustsScrollViewInsets = false
}
//You can change height on here too
self.ConstHeight.constant = 800
}

Flipping the positions of items in a UIStackView

I have a UIStackView, created in Interface Builder that contains two views. Now I'm trying to programatically change the order of these views (exchange their positions, so to speak).
Is there an easy fix for this that DOES NOT use Interface Builder to accomplish this?
Thanks :).
Create a layout with 2 UIViews in a UIStackView like so:
Create an outlet for your UIStackView to your UIViewController. Call addArrangedSubview on your UIStackView in viewDidLoad to change the order. See snippet below.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var stackView: UIStackView!
override func viewDidLoad() {
super.viewDidLoad()
// Switches order of the stackView
stackView.addArrangedSubview(self.stackView.subviews[0])
}
}
This should be the result:
The addArrangedSubview takes the given view and adds it to the end of the arrangedSubviews array. In our case we take the red view at index[0] and add it on the end (right) of the UIStackView.
You can change the view semantic of UIStackView from Unspecified to Force Right-to-Left to swap the position of of nested view.
you can use addArragnedSubview to reorder the views.
Only addArragnedSubview is needed because when adding the view to a new parent it is removed from the old parent.
if self.viewsSwitched{
stackview.addArrangedSubview(self.stackview.subviews[0])
self.viewsSwitched = false
}else{
stackview.addArrangedSubview(self.stackview.subviews[1])
self.viewsSwitched = true
}
This code exchanges the two views inside the stackview by each call

Scroll a view programmatically

I have a text view and I would like to scroll it programmatically (along my video playback). I created an outlet in my ViewController:
#IBOutlet weak var scrollView: NSScrollView!
How can I use it to scroll to a specific character range of my text content?
Try use method scroll(to:) from NSClipView (doc) class.
let point: NSPoint ...
scrollview.documentView.scroll(point)

Making UIScrollView with an UIImageView scale content automatically using Swift, autolayout and SnapKit

I have a view controller set up in Interface Builder with the following view structure:
- UIView
* UIScrollView
* UIImageView
I want to assign an image to UIImageView so, that the scroll view (and it's content size) will adopt the same width than in the image and automatically calculate the height of the content size according to the image aspect ratio. (This makes the image vertically scrollable inside the UIScrollView.)
I'm using Swift and Interface Builder + SnapKit for managing autolayout constraints.
I managed to make the constraints using SnapKit in the following way:
In Interface Builder, select the view controller and create all missing constraints by selecting Editor / Resolve Auto Layout Issues / Add Missing Constraints
Manually select all generated constraints and select Placeholder / Remove at build time from Attributes Inspector
Assign UIScrollView and UIImageView outlets to the view controller
Assign an image to the UIImageView
Then implement the view controller as follows:
import UIKit
import SnapKit
class ViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.snp.makeConstraints { (make) in
make.edges.equalTo(view)
}
let ratio = imageView.image!.size.height / imageView.image!.size.width
imageView.snp.makeConstraints { (make) in
make.top.equalTo(0.0)
make.bottom.equalTo(scrollView.snp.bottom)
make.width.equalTo(view.snp.width)
make.height.equalTo(scrollView.snp.width).multipliedBy(ratio)
}
}
}

Set of UIImageView.Image re-positions parent view

I have a UIView and added a UIImageView as child to it. I later change the position of the UIView via another UIButton event.
If I change the image of the UIImageView the UIView - inc. all shields - moves back to the initial position.
Could anyone maybe explain me what is going on here :-D How do I keep the new position of the UIView ?
Here a image screen I took to visualize the issue
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var number: UIImageView!
#IBOutlet weak var popup: UIView!
#IBAction func openPopup(sender: UIButton) {
self.popup.center = sender.center
//old position: (190.5, 124.0) - new Position: (173.0, 414.0)
}
#IBAction func updateImage(sender: UIButton) {
self.number.image = UIImage(named: "img-1")
}
}
Update:
I found out that above code works if I deactivate autolayout. Here is a solution to do this with auto layout:
Auto Layout center UIView above another UIView at its center
Are you sure of that? Did you check by logging popup.frame.origin after updateImage being called? Have you properly set clipsToBounds and contentMode properties for number uiimageview?
I found out that above code works if I deactivate "Use Auto Layout" in Interface Builder Document section at tab File Inspector.
In addition here is a working solution to the issue using auto layout and constraints:
Auto Layout center UIView above another UIView at its center