How to add NSTextFields to NSScrollView - swift

I want to add multiple NSTextFields to NSScrollView dynamically.
Code:
func addLabel(data: String)
{
let offset = labelCount*20
let label = NSTextField(frame: NSMakeRect(0, CGFloat(offset), 200, 20))
label.stringValue = data
scrollView.documentView?.addSubview(label)
labelCount += 1
// scrollView is IBOutlet
// labelCount is var to keep record of number of labels
}
Problem:
It adds the NSTextFields correctly to the NSScrollView but they are only added till the visible part is available. After the visible part of NSScrollView is full, no more NSTextFields are added to it.
I need to add NSTextFields even though the visible part is full and scroll to find others.
How can I do it?

It's something like the following.
scrollView.documentView?.setFrameSize(CGSize(width: CGFloat(labelCount) * 200, height: 20))

Related

How to add red dot badge in table view cell?

Try to add red dot badge for every unread data in inbox tableviewcell.
I try using cell.accessoryview to add badge
let size: CGFloat = 9
let width = max(size, 0.7 * size * 1) // perfect circle is smallest allowed
let badge = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: size))
badge.layer.cornerRadius = size / 2
badge.layer.masksToBounds = true
badge.textAlignment = .center
badge.textColor = UIColor.white
badge.backgroundColor = UIColor.red
if viewModel.sortedInboxItems[indexPath.section].isRead {
cell.accessoryView = badge
}
But if using cell.accessoryview it will change the display like image below (TIME in the right corner of the cell is moving forward). How to make it not change the display?
EDIT
Try to create dot as uilabel in custom uitableview cell like image below
But the result show like this image below. The red dot shape is not good enough? Can someone help with this issue ?
The accessoryView is not part of the contentView of the cell. If you set the accessoryView it will push the contentView over to make room for itself. More information on that can be found here; this diagram is helpful:
If you don't want it to do this, put your red dot into the cell itself instead of using the accessoryView. It's unclear how you've built your cells, but it looks like you've created a custom UITableViewCell, so you should be able to do this without trouble.
Or as commented above, you could include your time label in your accessory view alongside the red dot if applicable.
Consider using a UIView with corner radius just like you did with the label. To make sure that the shape is right (sizes have initialised properly) change its corner radius in an overriden layoutSubviews.
override func layoutSubviews() {
super.layoutSubviews()
badgeInboxView.layer.cornerRadius = badgeInboxView.frame.height/2
}

How do I add NSButtons from the top instead of from the bottom?

I am currently building a navigation left pane where buttons from the side are added dynamically. I have a NSView subclass that facilitates this
func addButton(_ service: String) {
let btn = NSButton()
btn.bezelStyle = .shadowlessSquare
btn.frame.size = NSSize(width: 48, height: 48)
btn.image = NSImage(named: service)
btn.imageScaling = .scaleAxesIndependently
btn.frame.origin = CGPoint(x: 0, y: self.currentY)
self.addSubview(btn)
self.currentY += 58
}
It works as desired but buttons are added from the bottom instead of the top:
Resulting App Screenshot
How do I make it so that new buttons are added from the top?
For reference, here's my storyboard with the "Servi" view containing the buttons.
Left Pane Storyboard
Y goes from bottom to top on macOS (the bottom is 0). So don't start with currentY at 0 or 10 or whatever you're starting with. Start with currentY set to one button height less than the view height, and then subtract 58 each time instead of adding.
So, you're getting something like this:
But if you do what I'm describing, you'll get something like this:
You could flip your view so that the coordinate system starts at the top left instead. Just create a new NSView subclass and override isFlipped
class FlippedView: NSView {
override var flipped:Bool {
get {
return true
}
}
}
Then add the new buttons to an instance of flippedview instead.

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.

Clickable buttons in a tableviews header

I have an app where there's a UITableView. I added buttons into the header like this:
var header = UIView(frame: .zero)
let text = UILabel(frame: .zero)
text.text = "Recent matchplayers"
text.font = .medium(14)
header.addSubview(text)
let recent = RecentContactsView()
header.addSubview(recent)
self.tableView.tableHeaderView = header
(I left out the code for constraints and stuff)
However, the buttons within RecentContactsView are not clickable. Is there a way to enable interaction within a table's header?
The buttons are not clickable because they are outside the bounds of one of heir superviews. I suspect this is because you are setting a frame of zero for the header view. Your header view’s frame needs to be large enough to cover the buttons so that they can receive touch events.

tvOS: UIScrollView doesn't scroll

I am trying to reproduce natively the TVML template that provides a grid of clickable images that extends beyond the screen's bounds. I am using a scroll view for this attempt, but I am unable to select elements that are added to the scroll view, but outside its visible area.
The sketch code using buttons for simplicity is as follows:
let dim = 50
for i in 0..<10 {
for j in 0..<10 {
let frame = CGRect(x: i * (dim + 10), y: j * (dim + 10), width: dim, height: dim)
let button = UIButton(type: .System)
button.frame = frame
myScrollView.panGestureRecognizer.allowedTouchTypes = [UITouchType.Indirect.rawValue]
myScrollView.addSubview(button)
}
}
The scroll view is sized such that only half of these buttons are visible. Why is the scroll view not scrolling to the buttons outside this area (using Siri remote)?
I thought the panGesture touchType might help, but it didn't.
Am I missing something obvious?
Set contentSize property to your scrollview. Make sure all components comes under given content size.
myScrollView.contentSize = CGSizeMake(1880, 2000)
It would actually be way easier to just use a UICollectionView. If you add an image to each cell, you'll get exactly the behavior you want after adjusting the collection view to what you want.
This tutorial kind of explains how it works. http://www.brianjcoleman.com/tutorial-collection-views-using-flow-layout/