I am transferring an app for iOS to a toolbar app in OSX. Although I am using swift, the objects are rather different. I am having one major problem, however, that I cannot seem to overcome.
The code below produces the NSButton shown, but I cannot get rid of the grey background. masktobound has no effect. I have tried masking each corner individually, no effect. I just want a simple round button.
I also have several buttons with rounded corners, however these also show the light grey background.
Any pointers? Sample code would be appreciated.
let connectButton = NSButton.init(title: NSLocalizedString(" ", comment: "OnButtonAccessibility"), target: self, action: #selector(toggle))
connectButton.wantsLayer = true
connectButton.isBordered = false
connectButton.layer?.masksToBounds=true
if #available(OSX 10.13, *) {
connectButton.layer?.maskedCorners=[.layerMaxXMaxYCorner]
} else {
connectButton.layer?.backgroundColor = NSColor.blue.cgColor
connectButton.layer?.cornerRadius=80
connectButton.layer?.borderColor=DarkerBlue.cgColor
connectButton.layer?.borderWidth=3
(connectButton.cell as! NSButtonCell).isBordered=false
(connectButton.cell as! NSButtonCell).backgroundColor=NSColor.clear
connectButton.isTransparent=true
connectButton.frame=CGRect(x: 80, y: self.view.frame.size.height-260, width: 160, height: 160)
connectButton.tag=1002
self.view.addSubview(connectButton)
It appears that you must at least touch the NSButton.cell to have it conform to the button style. The backgroundstyle used seems to make no difference is you have the button filled or containing an image.
connectButton.cell?.backgroundStyle=NSView.BackgroundStyle.dark
Related
I have a UIView with a UILabel for which, I'd like allow the user to dynamically change the font size. The code below almost works, but the problem is that after the new UIFont is assigned to the label, it doesn't immediately show in the UI. Instead, some other UI activity is required to make it show up.
What I'm looking for is a technique where the font change will show up immediately after the gesture is over.
Starting with the technique shown in this tutorial, I added a gesture recognizer to the UIScrollView. In the associated UIViewController, I implemented handlePinch(UIpinchGestureRecognizer).
Inside that function, I take action only when the gesture begins and ends (no attempt to animate). If the user indicated zoom, I increase the font by 4 points. If the user indicated a shrink, I decrease the font by 4 points. This all works, except for the fact that the screen does not reflect the change until another UI function is executed. I have only tested this on the simulator, but I presume it would be the same on a real device.
I have tried setNeedsDisplay and setNeedsLayout and several other odd things on both the UILabel as well as the view that was passed to the handlePinch() function.
#IBAction func handlePinch(_ gesture: UIPinchGestureRecognizer) {
guard let gestureView = gesture.view else {
return;
}
gestureView.transform = gestureView.transform.scaledBy(x: gesture.scale, y: gesture.scale)
if (gesture.state == UIPinchGestureRecognizer.State.began) {
pinchD = gestureView.transform.d
print("pinch started ", pinchD)
}
if (gesture.state == UIPinchGestureRecognizer.State.ended) {
print("pinch ended ", gestureView.transform.d)
print("compare:", pinchD, gestureView.transform.d)
let larger = gestureView.transform.d > pinchD
let fontSize = multiLineLabel.font.pointSize
if (larger) {
if (fontSize < 28) {
let calculatedFont = UIFont(name: multiLineLabel.font.fontName, size: fontSize + 4)
print("bigger fontSize", fontSize + 4);
multiLineLabel.font = calculatedFont
}
} else {
if (fontSize > 12) {
let calculatedFont = UIFont(name: multiLineLabel.font.fontName, size: fontSize - 4)
print("smaller fontSize", fontSize - 4);
multiLineLabel.font = calculatedFont
}
}
}
}
What needs to be done after the calculatedFont is applied to the UILabel to make it show immediately in the app?
ADDITIONAL CLARIFICATION:
handlePinch() runs as expected; every time a pinch gesture ends, I see bigger fontSize... or smaller fontSize... logged.
After the logging, the simulator screen font size remains the same until I do one of several things. One thing that causes the font size to change is if I swipe to the next item. Before the animation starts, the font increases. The font changes also if I hit the back button (the font change shows briefly before the other view appears).
It turns out that my presumption was incorrect:
I have only tested this on the simulator, but I presume it would be the same on a real device.
I believe that was NOT correct.
I'm testing on a very, very old iMac and the simulator is bogged down such that it takes 15 or 30 seconds to update the screen!
So I conclude that the code is working fine after all.
I found this question with a solution to my problem but it still has some misbehavior when I'm using it.
How to only show bottom border of UITextField in Swift
In my Project it seems like the bottom border doesn't know the correct width of my UITextField and is longer than my UITextField. The UITextField has constraints to the SaveArea on the left and right and a constraint to the text above. I would say that the width is defined by the constraints at run time so that the code in the extension should be able to get the correct width. But the way my code is getting the width seems to be wrong. Can someone help me?
Thanks in advance :)
I know you found a workaround but just thought I might add a fix for this if you still were considering using this.
So it seems that your set up was fine but it works a little bit differently on different device sizes.
self.frame.size.width in the extension is not always returning back the correct width of the UITextField in some devices and on orientation changes.
So to get this to work, here are the small changes I made:
extension UITextField
{
func addBottomBorder() {
let bottomLine = CALayer()
// The border should be inside the text field
// so I changed frame.size.height + 5 to
// frame.size.height - 1
bottomLine.frame = CGRect(x: 0,
y: frame.size.height-1,
width: frame.size.width,
height: 1)
bottomLine.backgroundColor = UIColor.black.cgColor
borderStyle = .none
layer.addSublayer(bottomLine)
// Add this so the layer does not go beyond the
// bounds of the text field
layer.masksToBounds = true
}
}
After this, the result should be as you hope:
Hope all are safe in this pandemic situation.
I have been trying to design an application similar to SnapChat, I am stucked in an issue since a week for which I am not getting any library from gitHub or any code reference from stackOverFlow.
I have to draw various emoji lines using swipe gesture on an UIImageView for which I have used UIGraphicsGetCurrentContext()
The issue I am facing is to managing equal space between the emojis.
I am attaching the screenshot of my work done till now.
Any help would be appreciated.
Thanks in advance
func drawLineFrom(_ fromPoint: CGPoint, toPoint: CGPoint) {
// isDrawingEmoji is used as a boolean to manage simple line drawing or emoji drawing.
if isDrawingEmoji == true {
UIGraphicsBeginImageContext(topImageView.frame.size)
let context = UIGraphicsGetCurrentContext()
context?.setAlpha(1.0)
topImageView.image?.draw(in: self.img.frame)
if let emoji = selectedEmoji.cgImage {
context?.draw(emoji , in: CGRect(x: toPoint.x , y: toPoint.y, width: 50, height: 50))
}
topImageView.clipsToBounds = true
topImageView.image = UIGraphicsGetImageFromCurrentImageContext()
topImageView.alpha = 1.0
UIGraphicsEndImageContext()
}
I assume you are using a pan gesture recognizer rather than a swipe gesture recognizer?
You need to write code that takes the points you receive from the gesture recognizer and treat them as the endpoints of a line segment. You would then apply your emoji evenly along the space between the points at a regular interval.
If you want more detailed help than that you will need to post your current drawing code.
I am creating a SpriteKit game and want to be able to take advantage of textAlerts - like all the games I grew up playing. I also want them to be flexible so I can subclass them and add them throughout my game - I am not sure how to do this and so would be very grateful of any advice.
There are a number of ways that I have started to look into:
Use another SKScene
The idea here would be to add another scene immediately on top of our current one. This would have a faded out background and would be configured with the text to be displayed. This seems like the wrong approach
Use an SKNode
I could create a custom node and initialise it with my specific text. I would then disable movement and add the node at the bottom of the screen. I would then customise the actions that occur when it is tapped.
Use an SKLabel
SKLabels are designed to show text so these seem like a promising place to look. The issue is that I want to add an image into the popup view (this a headshot of the person you are talking to) and so it doesn't feel like I should be able to inject an image in.
Use something else
I don't know what this might be. Is what I am trying to do easy or harder than I think?
My problem is that I come from a swift background so am struggling to convert to a SpriteKit mindset. In Swift I would put together a custom UIView with all the UIKit components and add it to the screen. In SpriteKit we don't have the same tools so I don't know the right combinations to put together what I want.
Ideally I want to be able to configure the text popup with an array of text so that a conversation can be had with the user tapping for each new line.
Edit 1: What I have tried so far
Based on #ElTomatos comment I have experimented with adding a SKSpriteNode and an SKLabelNode on top of each other using the following code:
guard let camera = camera else { return }
let dialogueBackground = SKSpriteNode(texture: nil, color: .red, size: CGSize(width: screenSize.width / camera.xScale, height: screenSize.height / 3 / camera.xScale))
dialogueBackground.anchorPoint = CGPoint(x: 0, y: 0)
dialogueBackground.zPosition = 50
dialogueBackground.position = CGPoint(x: -screenSize.width, y: -screenSize.height)
camera.addChild(dialogueBackground)
let label = SKLabelNode(text: "Hello world")
label.zPosition = 100
label.position = CGPoint(x: -screenSize.width, y: 100 - screenSize.height)
camera.addChild(label)
As you can see the view doesn't go to the edge of the screen. Is this something to do with the safe area? It's difficult to get the width and height as the camera doesn't have a CGSize we can use.
I have created a circle using Bezier path as well as i created tap events to check whether the layer has been tapped or not, it works fine until i increase the size of lineWidth of CAShapeLayer. By tapping on the lineWidth, sometimes it is detected and sometimes it is not detected.
I searched stackoverflow about the problem which i was having but i am unable to solve it. The problem remains the same, i am unable to detect certain taps on my layer(lineWidth area).
I just want to detect taps on the lineWidth of CAShapeLayer, i have been searching everywhere but couldn't find a proper solution for it. Most of the answers are in outdated languages. I would really appreciate if anyone could give an example to solve my issue. Swift 4.
https://i.imgur.com/194Aljn.png
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapDetected(tapRecognizer:)))
self.addGestureRecognizer(tapRecognizer)
#objc public func tapDetected(tapRecognizer:UITapGestureRecognizer) {
let tapLocation:CGPoint = tapRecognizer.location(in: self)
self.hitTest(tapLocation: CGPoint(x: tapLocation.x, y: tapLocation.y))
}
private func hitTest(tapLocation:CGPoint) {
if layer.path?.contains(tapLocation) == true {
print("Do something")
} else {
print("Nothing Found")
}
}
The problem is that the line stroke is not really part of the path - is it is just parts of its display. You can convert the path to be an larger path containing the stroke by using some CGPath methods:
let pathWithLineStroke = UIBezierPath.init(cgPath: path.cgPath.copy(strokingWithWidth: 2.0, lineCap: CGLineCap.butt, lineJoin: .bevel, miterLimit: 1.0));
Of course replace the the width, lineCap, lineJoin, and miterLimit with your actual values.
I'd recommend doing this earlier in your code, and then just drawing the path that already has the strokes built in, instead of setting those properies on the CALayer.
Hope that helps. Good luck.