Is Cocoa animator proxy unable to handle 0.5 points? - cocoa

I'm trying to move the origin of a custom view.
If I directly set the new origin for the frame, everything is working fine as expected.
[MyView setFrameOrigin:NSMakePoint(0.5, 0.5)];
If I try to animate the movement with the proxy animator.
[[MyView animator] setFrameOrigin:NSMakePoint(0.5, 0.5)];
The new origin will be (1, 1) instead of (0.5, 0.5).
Am I doing something wrong?
Is animator unable to handle 0.5 points?

My guess is the animator proxy is helpfully correcting a frame that would result in blurry edges and/or text. Drawing things across pixel borders (0.5, 0.5 vs. 1.0, 1.0 or 0.0, 0.0) is rarely useful unless you're trying to make something blurry (like a shadow, or glow).
You may very well have a good reason for doing this, but it's probably best to ask "why?"

Related

In SpriteKit, didEndContact occurs even though the sprites are still overlapping

Why? I can clearly see the two sprites are overlapping! I am killing myself for hours and hours over having the contacts precise and consistent, but can't find a way to do it. Either the didBeginContact or didEndContact is triggered in the wrong time. Does anyone have a consistent solution for this? I tried changing the anchorPoints to various positions (instead of (0.5, 0.5) I tried other values, like (0.5, 0)), but that seems to have messed all the things up pretty badly. I can't set sprites to have physicsBody rectangle based, because I have non-rectangular sprites (obviously). So my sprites' physicsBody-s are mostly texture based. I can see with my own two eyes that sprites are still overlapping and haven't ended the contact, and the event still triggers!!! Why is this happening? I have the scene being the contact delegate and everything else is properly connected. The sprites (let's call them SKSpriteNode A and SKSpriteNode B) that collide are on the scene and have contact bitmasks set properly for each other. The scene is the only contact delegate for the physicsWorld, so only the scene can trigger and go in the event handler, so I know it is working - at least some of the time. Code in scene:
-(void) didEndContact:(SKPhysicsContact *)contact {
NSLog(#"didEndContact occured!");
}
I have my custom class StaticLevelElement set so it extends SKSpriteNode:
#interface StaticLevelElement : SKSpriteNode
The B has been set as such StaticLevelElement with a triangular image:
StaticLevelElement * B = [StaticLevelElement spriteNodeWithImageNamed:#"triangle"];
I tried to set the B's physicsBody to have texture based physicsBody:
B.physicsBody = [SKPhysicsBody bodyWithTexture:[SKTexture textureWithImageNamed:#"triangle"] size:B.size];
And while the sprites A and B are still colliding and overlapping, the didEndContact occurs! I don't want it triggered when the sprites are still overlapping! How can I resolve this?
Try not to use the texture based physicsBody, but either the polygon based, or rectangle based physicsBody.

tvOS: Rounded corners for image view when focused

I have an image view that will get this awesome tvOS focus effect when the containing view gets focused.
The problem is - it should have rounded corners. Now this is easily done:
imageView.layer.cornerRadius = 5
imageView.layer.masksToBounds = true
I have to set either masksToBounds of the layer or clipsToBounds of the image view to true (which is basically the same), in order to clip the edges of the image - but as soon as I do this, the focus effect won't work any more, because it will get clipped as well.
I had more or less the same problem with buttons, but since the focus effect is much simpler than for the image view (only scaling and shadow), I just implemented it myself, but that is not an option for the image view, with all the effects applied (moving, shimmering, and so on...)
Is there an easier way? Did I miss something? I can't be the only trying to figure out how this works!? :)
I have found out an alternative solution. What one may do is to actually draw the image, clipping out the corners with an alpha channel. The image then gets scaled correctly when focused. That applied to the layer. Then, to have the alpha channel added to the other layers (like the one for the glowing effect) we need to set; "masksFocusEffectToContents = true".
I made an extension for it, based on this answer:
Swift 4.2
extension UIImageView {
func roundedImage(corners: UIRectCorner, radius: CGFloat) {
let rect = CGRect(origin:CGPoint(x: 0, y: 0), size: self.frame.size)
UIGraphicsBeginImageContextWithOptions(self.frame.size, false, 1)
UIBezierPath(
roundedRect: rect,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius)
).addClip()
self.draw(rect)
self.image = UIGraphicsGetImageFromCurrentImageContext()!
// Shadows - Change shadowOpacity to value > 0 to enable the shadows
self.layer.shadowOpacity = 0
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 10, height: 15)
self.layer.shadowRadius = 3
// This propagate the transparency to the the overlay layers,
// like the one for the glowing effect.
self.masksFocusEffectToContents = true
}
}
Then to apply the rounded corners call:
myImageView.adjustsImageWhenAncestorFocused = true
myImageView.clipToBounds = false
// masks all corners with a radius of 25 in myImageView
myImageView.roundedImage(corners: UIRectCorner.allCorners, radius: 25)
One can obviously modify roundedImage() to add the parameters to define the shadows at the calling time.
Downsides:
Borders behave like cornerRadius (they get drawn inside the image).
But I think I made it working somewhere, then investigating further I
lost the changes
I am not exactly sure this is the right way to do it. I am quite confident there must be some methods out there doing it in a couple of lines. In tvOS 11 Apple introduced the round badges (animatable and all), shown at WWDC 2017. I just can't find a sample for them.
Otherwise, tvOS 12 (beta for now) introduced the Lockup. I managed to implement them programmatically, as shown in this answer.
https://forums.developer.apple.com/thread/20513
We are also facing this same issue. When you round the corners, you can see the "shine" still has a rectange shape.
I showed the issue to the Dev Evangelists at the Tech Talks in Toronto and they said it's a bug. It's reported and open rdar://23846376
For 2022.
Note that you can just use UICardView on tvOS for the effect.
Simply put the UIImageView inside the card view.
Don't forget to actually turn OFF "adjust on ancestor focus" and "user interaction enabled" on the image view, or else it will "doubly expand" when the card view expands!
There's also a weird issue where you have to add 20 to the height of all card views to make them work neatly with and enclosed image view.

Scale NSView centered

I need to scale an NSView around it's center.
I tried using CATransform3DMakeScale and it worked to scale the view towards it's corner but I couldn't achieve to center it. I tried to set the layers anchor point to .5, .5 but that didn't work.
I tried using scaleUnitSquareToSize but I ran into the problem that this seems unresetable without a lot of work.
In the end I need to be able to set the scale of an NSView to something like 0.8 and have it zoom out around it's center and be able to set the scale to 1 again to reset it.
Added a frame fix for #fyasar's answer, works for me on MacOS:
CGRect frame = layer.frame;
layer.anchorPoint = CGPointMake(.5, .5);
layer.frame = frame; // Fix the location shift caused from anchor change
I also faced with smilar problem.
Please be sure exeute that line before construct CABasicAnimation.
layer.anchorPoint = CGPointMake(.5, .5);
So, that worked for me.
Good luck
If you can require 10.8, then you could call NSScrollView's function:
- (void)setMagnification:(CGFloat)magnification centeredAtPoint:(NSPoint)point

NSView free-angle rotation

I have NSView container (with NSImageView and some other custom subviews). How to set its rotation properly? I tried to set angle through setFrameRotation: and set rotation matrix in views layer. But in these cases subview image becomes downscaled and clipped.
Update:
If I set rotation via [myView setFrameRotation: angle]:
almost fine, except text frame (drawing via [NSString drawAtPoint:...] and rotation anchor is at left-bottom corner (I want at bottom-center, [myView setFrameOrigin:...] does nothing)
If I set rotation via myView.layer.transform = CATransform3DMakeRotation (angle, 0, 0, 1):
frame bound remains unrotated and clips subviews (but this approach is more suitable for view container)

NSTabView with background color

As discussed elsewhere, NSTabView does not have a setBackgroundColor method and subclassing NSTabView and using an drawRect to control it does no longer work - as it does not paint the top 10%, the bit just below the segmented control button.
Now I am a bit surprised by the amounts of work arounds I had to do solving this; see
code: https://github.com/dirkx/CustomizableTabView/blob/master/CustomizableTabView/CustomizableTabView.m
and am wondering if i went down the wrong path. And how to do this better & simpler:
The NSSegmentStyleTexturedSquare seems to yield me a semi-transparent segmented Control. Which means I need to do extra work to hide any bezel lines (line 240, 253).
is there a better way to do this ? I.e. negate its transparency ?
or is there a way I can use the actual/original segmented choise button ?
I find that the colours I need - like the [NSColor windowBackgroundColour] are not set to anything useful (i.e. that one is transparent) -- so right now I hardcode them (lines 87, 94).
Is there a better way to do this ?
I find I need a boatload of fluffy methods to keep things in sync ( line 128, 134, etc).
can this be avoided ?
I find that mimicking the cleverness on rescaling means I need to keep a constant eye on the segemented Control box and remove/resize it. And even then - it is not quite as good as the original
is there a better way to do this than line 157 -- i.e. hear about resizing ? Rather than do it all the time ?
The segementControl fades dark when focus is removed from the window - unlike the real McCoy.
can that easily be prevented ? is there a cheap way to track this ?
Or is this the wrong approach - and should I focus on just a transparent hole here - and let the NSTabViewItem draw a background ? But in any case - then I still have the issue with the Segemented COntrol box - or is there than a way to make that be the default again.
when trying this - I get stuck on the top 20-30 pixels being drawn in the 'real' windows background colour - which is 'transparent' - and hence the colour will not run all the way to the top or behind the segment bar and up to the bezel - but instead stop some 8 pixels below the bottom of the segment controls.
Feedback appreciated - as this feels so far off/suboptimal for such a simple things --
Thanks a lot. Brownie points for hacking/forking the github code :) :) :) As a line of running code says more than a thousand words.
Dw.
PSMTabBarControl is probably the best workaround for you. I have created several custom tab views, but cocoa does not play well with this control. PSMTabBarControl has been updated to support Xcode 4. https://github.com/ciaran/psmtabbarcontrol
Have you tried setting the background color of its underlying CALayer? (Make it a layer-backed view, if it isn't already, by setting wantsLayer = YES.)
If your situation can tolerate some fragility, a very simple and quick approach is to subclass NSTabView and manually adjust the frame of the item subviews. This gives each item a seamless yellow background:
- (void)drawRect:(NSRect)dirtyRect {
static const NSRect offsetRect = (NSRect) { -2, -16, 4, 18 };
NSRect rect = self.contentRect;
rect.origin.x += offsetRect.origin.x;
rect.origin.y += offsetRect.origin.y;
rect.size.width += offsetRect.size.width;
rect.size.height += offsetRect.size.height;
[[NSColor yellowColor] set];
NSRectFill(rect);
[super drawRect:dirtyRect];
}
A future change in the metrics of NSTabView would obviously be a problem so proceed at your own risk!

Resources