Menubar constraints in BigSur - swift

I have the following code that works fine in Mojave but it looks bad in BigSur(see the pic below) How can I push the icon to the left.
Sorry, I'm not good with writing constraints programmatically so the existing constrains might be wrong(but they worked on the prev versions of macos)
let itemImage = NSImage(named: "menubar3")
itemImage?.isTemplate = true
statusItem?.button?.image = itemImage
statusItem?.button?.imagePosition = NSControl.ImagePosition.imageLeft
stack = NSStackView(views: views)
stack?.translatesAutoresizingMaskIntoConstraints = false
statusItem?.button?.addSubview(stack!)
statusItem?.button?.addConstraint(NSLayoutConstraint(item: stack!, attribute: .leading, relatedBy: .equal, toItem: statusItem?.button, attribute: .leading, multiplier: 1, constant: 30))
statusItem?.button?.addConstraint(NSLayoutConstraint(item: stack!, attribute: .trailing, relatedBy: .equal, toItem: statusItem?.button, attribute: .trailing, multiplier: 1, constant: -5))
UPD
Not sure if it helps
var statusItem: NSStatusItem?
....
#objc func configureStatusItem() {
// Status Bar
var views: [StatusItemSectionView] = []
for item in statsViewModels {
if item.isValid {
let section = StatusItemSectionView(
frame: NSRect(),
viewModel: item
)
views.append(section)
}
}
let statusBar = NSStatusBar.system
statusItem = statusBar.statusItem(withLength: NSStatusItem.variableLength)
statusItem?.button?.action = #selector(self.statusBarButtonClicked(sender:))

Related

How to disable an NSTextField and make it uneditable? [isEditable property not working]

I'm getting the promo code input in NSTextField and on clicking apply the promo code is applied.
At this point, my text field should be uneditable until the remove promo code is pressed. if remove promo code button is pressed the text field becomes editable. This works just like Zomato coupon codes apply and remove.
I tried isEditable = false but that doesn't work
#IBOutlet weak var promoCodeValidity: NSTextField!
#IBOutlet weak var promoCode: NSTextField!
func applyCoupon(){
let couponCode = promoCode.stringValue
if let offer = bookingView!.applyOffer(offerCode:couponCode){
promoCodeValidity.stringValue="Offer Applied "+String(offer)+"% Off"
promoCode.isEditable=false
}
else{
promoCodeValidity.stringValue="Offer Code Invalid"
}
}
why isEditable doesn't work
Try toggling the isEnabled property of the text field and then change the isEnabled property of the text field.
i.e First disable the text field, then change the editable property of the text field and then again enable the text field.
Hope this solves your problem.
I have attached a small code sample also :)
class ViewController: NSViewController {
let textField = NSTextField()
let button = NSButton()
override func viewDidLoad() {
textField.translatesAutoresizingMaskIntoConstraints=false
textField.placeholderString = "ENTER PROMO CODE"
button.translatesAutoresizingMaskIntoConstraints=false
super.viewDidLoad()
textField.isEditable = true
button.action = #selector(buttonClicked(_:))
view.addSubview(textField)
view.addSubview(button)
NSLayoutConstraint(item: textField, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: textField, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: textField, attribute: .width, relatedBy: .equal, toItem: nil , attribute: .notAnAttribute, multiplier: 1.0, constant: 100).isActive = true
NSLayoutConstraint(item: button, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: button, attribute: .leading, relatedBy: .equal, toItem: textField, attribute: .trailing, multiplier: 1.0, constant: 20).isActive = true
NSLayoutConstraint(item: button, attribute: .width, relatedBy: .equal, toItem: nil , attribute: .notAnAttribute, multiplier: 1.0, constant: 50).isActive = true
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
#objc func buttonClicked(_ sender: Any) {
textField.isEnabled = false
textField.isEditable = false
textField.isEnabled = true
}
}
add extention:
extension UITextField
{
open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(UIResponderStandardEditActions.paste(_:)) || action == #selector(UIResponderStandardEditActions.cut(_:)) || action == #selector(UIResponderStandardEditActions.copy(_:)) || action == #selector(UIResponderStandardEditActions.select(_:)) || action == #selector(UIResponderStandardEditActions.selectAll(_:)) {
return false
}
return false
}
}
and:
textFiled.isEditable = false

Adding constraints in awakeFromNib() method

I have two custom views in my project which needs to be zoomed in the exact same proportion. So I decided to use UIScrollView for that and it fits perfectly.
I decided to develop a very simple class inherited from UIScrollView and inside of it I initialized all views structure. That way I'm avoiding any construction steps in the NIB file and my class can be used just by adding one view. But I faced an issue already on the stage of adding contentView.
Here's my class:
final class PlayerContentView: UIScrollView {
fileprivate var contentView: UIView!
override func awakeFromNib() {
super.awakeFromNib()
self.backgroundColor = .clear
setupScrollProperties()
setupContentView()
}
private func setupScrollProperties()
{
self.translatesAutoresizingMaskIntoConstraints = false
self.minimumZoomScale = 1.0
self.maximumZoomScale = 2.0
self.contentSize = frame.size
self.delegate = self
}
private func setupContentView()
{
contentView = UIView(frame: self.frame)
contentView.backgroundColor = .red
self.addSubview(contentView)
CommonSwiftUtility.setSideConstraints(superview: self, view: contentView)
CommonSwiftUtility.setSizeConstraints(superview: self, view: contentView)
}
func requireToFail(_ gestureRecognizer: UIPanGestureRecognizer) {
self.panGestureRecognizer.require(toFail: gestureRecognizer)
} }
And here're methods for adding constraints:
static func setSideConstraints(superview: UIView, view: UIView) {
let topConstraint: NSLayoutConstraint = NSLayoutConstraint(item: view,
attribute: .top,
relatedBy: .equal,
toItem: superview,
attribute: .top,
multiplier: 1.0, constant: 0.0)
let bottomConstraint: NSLayoutConstraint = NSLayoutConstraint(item: view,
attribute: .bottom,
relatedBy: .equal,
toItem: superview,
attribute: .bottom,
multiplier: 1.0, constant: 0.0)
let leadingConstraint: NSLayoutConstraint = NSLayoutConstraint(item: view,
attribute: .leading,
relatedBy: .equal,
toItem: superview,
attribute: .leading,
multiplier: 1.0, constant: 0.0)
let trailingConstraint: NSLayoutConstraint = NSLayoutConstraint(item: view,
attribute: .trailing,
relatedBy: .equal,
toItem: superview,
attribute: .trailing,
multiplier: 1.0, constant: 0.0)
superview.addConstraint(topConstraint)
superview.addConstraint(bottomConstraint)
superview.addConstraint(leadingConstraint)
superview.addConstraint(trailingConstraint)
}
static func setSizeConstraints(superview: UIView, view: UIView)
{
let wConstraint: NSLayoutConstraint = NSLayoutConstraint(item: view,
attribute: .width,
relatedBy: .equal,
toItem: superview,
attribute: .width,
multiplier: 1.0, constant: 0.0)
let hConstraint: NSLayoutConstraint = NSLayoutConstraint(item: view,
attribute: .height,
relatedBy: .equal,
toItem: superview,
attribute: .height,
multiplier: 1.0, constant: 0.0)
superview.addConstraint(wConstraint)
superview.addConstraint(hConstraint)
}
As you can see, I painted my contentView in red color in order to define it on the screen. After showing my PlayerContentView I get this:
PlayerContentView is stretched on the full screen so I'm expecting contentView to be full-size, but clearly it's not. Could someone please refer me to the solution of that issue? Thanks in advance!
Can you set
contentView.translatesAutoresizingMaskIntoConstraints = false

App window on top of all windows including others app windows

I like to have my NSWindow top of everything including other app windows. How this is possible?
This is how my custom NSWindow looks like?
override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask,
backing backingStoreType: NSWindow.BackingStoreType, defer flag: Bool) {
super.init(contentRect: contentRect, styleMask: NSWindow.StyleMask.borderless,
backing: NSWindow.BackingStoreType.buffered, defer: false)
// Manage window appearance and size
// this window manages video view controller
self.backgroundColor = NSColor.clear
self.alphaValue = CGFloat(AppSingleton.shared.getVideoOpacity()) / 100
self.isOpaque = false
self.collectionBehavior = .transient
}
And this how I open the NSWindowController from a button action
func openPlayerWindow(url: URL) {
let storyboard:NSStoryboard? = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: Bundle.main)
let playerWindowController = storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "SIPlayerWindowController")) as! PlayerWindowController
if let playerWindow = playerWindowController.window {
playerWindowController.showWindow(nil)
playerWindow.makeKeyAndOrderFront(self)
NSApp.activate(ignoringOtherApps: true)
let videoPlayerController = playerWindow.contentViewController as! VideoPlayerViewController
videoPlayerController.videoFile = url
}
}
PlayerView.swift
import Cocoa
import AVFoundation
class PlayerView: NSView {
override func hitTest(_ point: NSPoint) -> NSView? {
return nil;
}
}
This PlayerView immediately fill with CorePlayer in this func.
VideoViewController.swift
func playVideo(videoFile: URL) {
corePlayer.view().translatesAutoresizingMaskIntoConstraints = false
view.addSubview(corePlayer.view())
NSLayoutConstraint.init(item: corePlayer.view(), attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint.init(item: corePlayer.view(), attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint.init(item: corePlayer.view(), attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint.init(item: corePlayer.view(), attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0).isActive = true
corePlayer.playURL(videoFile.absoluteURL)
}
Try to use this
self.windowController?.showWindow(nil)
self.makeKeyAndOrderFront(self)
NSApp.activate(ignoringOtherApps: true)
I found the solution
self.ignoresMouseEvents = true;

UIPageControl has background on tvOS

In one of my games I am using a UICollectionView as the level select menu. I recently added a UIPageControl to it programatically.
/// Page control
func setupPageControl() {
pageControl.hidesForSinglePage = true
pageControl.numberOfPages = DataSource.worlds
pageControl.translatesAutoresizingMaskIntoConstraints = false
pageControl.currentPageIndicatorTintColor = DataSource.pageControlColors[pageControl.currentPage]
pageControl.pageIndicatorTintColor = UIColor.white.withAlphaComponent(0.8)
pageControl.addTarget(self, action: #selector(didPressPageControl), for: .valueChanged)
view.addSubview(pageControl)
let leading = NSLayoutConstraint(item: pageControl, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0)
let trailing = NSLayoutConstraint(item: pageControl, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)
let bottomConstant = Device.isPad ? view.frame.width / 9 : view.frame.width / 17
let bottom = NSLayoutConstraint(item: pageControl, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: -bottomConstant)
view.addConstraints([leading, trailing, bottom])
}
Everything is fine on iOS but on tvOS the PageController has a translucent background that stretches all across the screen.
How can I turn this off? I tried setting the pageControl background color but that does not seem to work.
As usual just when I post a question I find the answer a minute later.
You can remove the background on tvOS by calling this
#if os(tvOS)
for subview in pageControl.subviews {
let effectView = subview as? UIVisualEffectView
effectView?.removeFromSuperview()
}
#endif
Change background color for page control

Swift 2 Programmatically Constraints, i can't see the web view

i have a webkit and under the webkit there is another view... so i have three view = view, secondView(the one contain the WKWebView) and bannerView(with ADS). I added WKWebView to the secondView programmatically but bannerView and their constraints are set in storyboard. Now i need to set the constraints for WKWebView, i saw hundreds of tutorial, run without crash and problems but i can't see the WKWebView! how can i fix that ?
Code:
class ViewController: UIViewController {
#IBOutlet var bannerView: GADBannerView!
#IBOutlet var secondView: UIView!
var webView = WKWebView()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
print("Google Mobile Ads SDK version: " + GADRequest.sdkVersion())
//bannerView.adUnitID = ""
//bannerView.rootViewController = self
//var request = GADRequest()
//request.testDevices = ["kGADSimulatorID"]
//bannerView.loadRequest(request)
let preferences = WKPreferences()
preferences.javaScriptEnabled = true
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
webView.frame = CGRectMake(0, 0, 600, 543)
webView.customUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12"
let url = NSURL(string:"https://apple.com/")
let req = NSURLRequest(URL:url!)
self.webView.loadRequest(req)
secondView.addSubview(webView)
secondView.bringSubviewToFront(webView)
webView.translatesAutoresizingMaskIntoConstraints = false
let xConstraint = NSLayoutConstraint(item: webView, attribute: .CenterX, relatedBy: .Equal, toItem: secondView, attribute: .CenterX, multiplier: 1, constant: 0)
let yConstraint = NSLayoutConstraint(item: webView, attribute: .CenterY, relatedBy: .Equal, toItem: secondView, attribute: .CenterY, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: webView, attribute: .Bottom, relatedBy: .Equal, toItem: secondView, attribute: .Bottom, multiplier: 1, constant: 0)
secondView.addConstraints([xConstraint, yConstraint, bottomConstraint])
/*
let topConstraint = NSLayoutConstraint(item: webView, attribute: NSLayoutAttribute.TopMargin, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.BottomMargin, multiplier: 1, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: webView, attribute: NSLayoutAttribute.Leading , relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: -20)
let trailingConstraint = NSLayoutConstraint(item: webView, attribute: NSLayoutAttribute.Leading , relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: -20)
let bottomConstraints = NSLayoutConstraint(item: webView, attribute: NSLayoutAttribute.Bottom , relatedBy: NSLayoutRelation.Equal, toItem: self.bannerView, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)
*/
/* var LeftwebViewConstraints = NSLayoutConstraint(item: webView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Leading, multiplier: 1.0, constant: -20)
var RightwebViewConstraints = NSLayoutConstraint(item: webView, attribute: NSLayoutAttribute.TrailingMargin, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.TrailingMargin, multiplier: 1.0, constant: -20)
var BottomwebViewConstraints = NSLayoutConstraint(item: webView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: bannerView, attribute: NSLayoutAttribute.BottomMargin, multiplier: 1.0, constant: 0)
// view.addConstraints([LeftwebViewConstraints, RightwebViewConstraints, BottomwebViewConstraints])
NSLayoutConstraint.activateConstraints([LeftwebViewConstraints, RightwebViewConstraints, BottomwebViewConstraints])
*/
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Yes, it would appear that you are missing some constraints.
I might suggest adding all of the necessary constraints using VFL, which may be more intuitive:
secondView.addSubview(webView)
webView.translatesAutoresizingMaskIntoConstraints = false
let views = ["webView" : webView]
secondView.addSubview(webView)
secondView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[webView]|", options: [], metrics: nil, views: views))
secondView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[webView]|", options: [], metrics: nil, views: views))
This obviously assumes that the constraints for secondView were defined correctly in the first place. Check its frame before you start losing any sleep over the frame of the webView.
But note, I don't manually set the frame of the webView, but rather I simply defined both horizontal and vertical constraints.