Resizing NSScrollView - swift

How can I resize NSScrollView using Swift?
class MainViewController: NSViewController {
#IBOutlet weak var scrollView: NSScrollView!
override func viewDidLoad {
scrollView.setFrameOrigin(NSPoint(x: 340, y: 537))
scrollView.setFrameSize(CGSize(width: scrollView.contentSize.width, height: 102.0))
}
}
The above code works only if there are no constraints set. But, without constraints, the ScrollView doesn't stay in place when the window is resized.

If you are trying to set the document size (scrollable area) of a NSScrollView, then all we need to do is set the document view's size.
📌 Note: This assumes there are no constraints on the document view.
scrollView.documentView?.setFrameSize(NSSize(width: 576, height: 56))
If you are trying to scroll to a specific region, see scrollToVisible(_:).

So this worked for me since my ScrollView was positioned on the top left:
scrollView.setFrameOrigin(NSPoint(x: self.view.frame.minX + 340, y: self.view.frame.maxY - 172))
scrollView.setFrameSize(CGSize(width: scrollView.contentSize.width, height: 102.0))
And the below image shows the settings used in Size Inspector to enable auto resize and also to stay to the top-left of the window.

Related

How add Size and Position to ImageView in UITableView Cell?

I added a image to my UITableView Cell:
cell.imageView!.image = UIImage(named: "Default.png")
Everything works, the image is displayed. Now I want to give a custom size and position for the image, so I try it with this code:
cell.imageView!.frame = CGRect(x: 29, y: 17, width: 14, height: 13)
But for any reason it doesn't work. Any advices?
If your position will not change You can create frame in your TableViewCell
class TableViewCell: UITableViewCell {
#IBOutlet weak var imageView: UIImageView!
override func layoutSubviews() {
super.layoutSubviews()
self.imageView?.frame = CGRect(x: 12, y: 23, width: 12, height: 100)
}
}
You can change frame in tableview(cellForRowAt) but If frame will not change its a bad because cellForRowAt run when scrolling up - down or loading cell . You can define in UITableViewCell once.
Add a custom class for this custom tableViewCell.
Create a custom tableViewCell inside the tableView through the storyboard.
Add image inside this custom tableViewCell.
Add constraints (top, bottom, leading, trailing) to this image.
This way, you won't have to do anything programmatically and the image size issues will be taken care of by these constraints.
It'd be better if you do that frame related things in storyboard or Xib files itself. if you want them with static frame.
RunTime:
You can use NSLayoutConstraints
You can change the frame in draw(_ rect: CGRect) method.

swift NSCollectionView layout wrong after window resize

I have a NSCollectionView using sections and flow layout. Initial layout is fine but resizing the window causes the vertical position of the collection view items to move (relative to the top window boundary). The section breaks stay stationary relative to the top window boundary (good). But the items moving up causes them to overlap with the sections and eventually move up out of the window area as I decrease the height of the window.
I think this is related to how the mac uses the bottom as the origin of the coordinates. Resizing the window causes the bottom window boundary to move.
For reference here's where I configure my collection view, including standard flow layout.
fileprivate func configureCollectionView() {
let nib = NSNib(nibNamed: "MonitorViewItem", bundle: nil)
mapCollectionView.register(nib, forItemWithIdentifier: NSUserInterfaceItemIdentifier("MonitorViewItem"))
let flowLayout = NSCollectionViewFlowLayout()
flowLayout.itemSize = NSSize(width: 100.0, height: 40.0)
flowLayout.sectionInset = NSEdgeInsets(top: 25.0, left: 10.0, bottom: 10.0, right: 10.0)
flowLayout.minimumInteritemSpacing = 10.0
flowLayout.minimumLineSpacing = 10.0
mapCollectionView.collectionViewLayout = flowLayout
}
I tried invalidating the layout in my window resizing delegate function. My print statement confirms its being called as the window resizes, but invalidating the layout is not solving the issue.
extension MapWindowController: NSWindowDelegate {
func windowDidResize(_ notification: Notification) {
print("got resize")
mapCollectionView.collectionViewLayout!.invalidateLayout()
}
}
So far I have not attempted to subclass my view and override isFlipped.
Here's my window hierarchy in my .xib:
Window
View
Bordered Scroll View - Collection View
Clip View
Map Collection view
Collection View Flow layout
scroller
scroller
Any suggestions to fix the collection view item vertical positions as the nswindow is resized?

UIButton action is not triggered after constraint layouts changed

I have got an UIButton on a storyboard ViewController. When I load data into the form and the layout is significantly changing the button does not recognise the touch action.
I have figured out that when button is visible on the scrollview right after it if filled with data, the touch action works.
If the data too long and the button is not visible at first, just when it is scrolled into the display, the touch action does not work.
I was checking if something is above the button, but nothing. I have tried to change the zPosition of the button, not solved the problem.
What can be the issue?
I have made custom classes from the UIScrollView and the UIButton to check how the touches event triggered. It is showing the same behaviour, which is obvious. If the button is visible right at the beginning, the UIButton's touchesBegan event is triggered. If the button moves down and not visible at the beginning, it is never triggered, but the scrollview's touchesBegan is called instead.
Depending on the size of the data I load into the page sometimes the button is visible at the beginning, but the form can be still scrolled a bit. In this case the button still work, so it seems that this behaviour is not depending on if the scrollview is scrolled before or not, just on the initial visibility of the button.
Is there any layout or display refresh function which should be called to set back the behaviour to the button?
The code portion which ensures that the contentview is resized for the scroll if the filled data requires bigger space.
func fillFormWithData() {
dispDescription.text = jSonData[0]["advdescription"]
dispLongDescription.text = jSonData[0]["advlongdesc"]
priceandcurrency.text = jSonData[0]["advprice"]! + " " + jSonData[0]["advpricecur"]!
validitydate.text = jSonData[0]["advdate"]!
contentview.layoutIfNeeded()
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)
contentview.frame.size.height = contentRect.size.height
scrollview.contentSize = contentview.bounds.size
}
Ok, so another update. I have coloured the contentview background to blue and the scrollview background to white. When I load the data and resize the layout constraints, the contentview is resizing as expected, however now the scrollview is going to the bottom. After I scroll the view it is resizing to the original size which fits the screen. Now the button is only recognised when I touch the are which is blue behind. With the white background it is not recognised anymore, so it seems that the scrollview is hiding the button.
Let me get this clear the button is added in storyboard and it is a spritekit project?? If you are using zPosition?? Why don’t u connect the UIButton via the assistant editor as an IBAction then the action is always tied to the button.
You can also do it differently
Create an SKLabelNode and put it on the screen where you want to have the button and then set a name to it as myButton
override func touchesBegan(_ touches: Set<UITouch>, with event:
UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
let tappedNodes = nodes(at: location)
for node in tappedNodes {
if node.name == "myButton" {
// call your action here
}
}
}
}
EDIT 1:
You could also try auto resizing your scrollView.content this works also if you are adding any views via the app or programmatically
private func resizeScrollView(){
print("RESIZING THE SCROLLVIEW from \(scrollView.contentSize)")
for view in scrollView.subviews {
contentRect = contentRect.union(view.frame)
}
scrollView.contentSize = CGSize(width: contentRect.size.width, height: contentRect.size.height + 150)
print("THE CONTENT SIZE AFTER RESIZING IS: \(scrollView.contentSize)")
}
EDIT 2: I think I found the issue with your project. You need to move the MessageButton(UzenetButton) above DispDescription label in the object inspector in that way it will always be above your message textView.
At the moment the UzeneButton is at the very far back in your view hierarchy so if your textView is resizing whilst editing it covers the button that is why you cannot click on it.
See #Endre Olah,
To make situation more clear do one more thing, set clipToBound property of contentview to true.
you will notice that after loading of data your button not fully visible, it means it is shifting out of bound of its parentView (ContentView)
And that's why button is not taking your touch. However, if you carefully touch upper part of button it still do its job. Because upper part is still in bound of ContentView
Solution :
After loading of data you have to make sure that you increase height of ContentView such that button should never go out of bound of its parentView(ContentView).
FOR EXAMPLE
#IBOutlet var heightConstraintOfContentView : NSLayoutConstraint!
After loading of data
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)
heightConstraintOfContentView.constant = contentRect.size.height
contentView.layoutIfNeeded()
I use following steps when I need to use scrollview with dynamic content:
1) Firstly add a scrollView with top, bottom, trailing and leading is 0 to super view.
2) Add a view to scrollView and view's trailing, leading bottom and top space to scrollView can be set to 0 (or you can add margin optionally).
3) Now, you should add UI elements like buttons, labels with appropriate top, bottom, trailing and leading margins to each other.
4) Lastly, add equal height and equal width constraint to view with Safe Area:
and change equal height priority of view to 250:
It should solve your problem with UIScrollView.
Finally, I have found the solution in another chain, once it became clear that the scrollview's contentview is resizing on scroll event to the original size. (Not clear why this is like this, but that is the fact.)
So I had to add a height constraint to the contentview in the storyboard and create an outlet to it and adjust this constraint when the content size is changing, like this:
#IBOutlet weak var ContentViewHeight: NSLayoutConstraint!
func fillFormWithData() {
dispDescription.text = jSonData[0]["advdescription"]
dispLongDescription.text = jSonData[0]["advlongdesc"]
priceandcurrency.text = jSonData[0]["advprice"]! + " " + jSonData[0]["advpricecur"]!
validitydate.text = jSonData[0]["advdate"]!
contentview.layoutIfNeeded()
let contentRect = CGRect(x: 0, y: 0, width: scrollview.frame.width, height: uzenetbutton.frame.origin.y+uzenetbutton.frame.height+50)
contentview.bounds = contentRect
scrollview.contentSize = contentRect.size
----------- This is the key line to the success ----------
ContentViewHeight.constant = contentRect.size.height
----------------------------------------------------------
}
After this is added, it works perfectly.

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
}

Set scrollview size and position by code

I've added a scrollView in Main.storyboard and made it the same size as the view and set the backgroundcolor to blue.
But I'm having troubles with autolayout so I'm trying to deactivate the constraints by code (succeeded) and set the frame position and size with the following code inside viewDidLoad()
NSLayoutConstraint.deactivateConstraints(self.view.constraints())
self.scrollView.frame = CGRectMake(0.0, 100.0, 200.0, 200.0)
self.scrollView.backgroundColor = (UIColor.redColor())
When I run the code the colour changes to red (so I've got that going for me, which is nice) but the scrollView doesn't change position or size.
What is the right syntax to do this?
This will work if you set the frame in viewDidLayoutSubviews():
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.scrollView.frame = CGRect(x: 0.0, y: 100.0, width: 200.0, height: 200.0)
}
Trying to do this in viewDidLoad() will not work because scrollView is not yet in the view hierarchy at this point.
Note that you are only deactivating the constraints for the view and not its subviews in your code snippet. This may not be what you intended.
Also note that I'm not endorsing this as a way to fix constraint problems. ;-)