I want to create an animation with CALayers.
I have a parent layer with multiple sublayers and I would like to zoom in and scroll.
First I trying to zoom on the parent layer, as follows:
let transformAnimation = CABasicAnimation(keyPath: "bounds.size.width")
transformAnimation.duration = 2.3
transformAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transformAnimation.toValue = 650*2
transformAnimation.beginTime = CACurrentMediaTime() + 4
transformAnimation.autoreverses = false
transformAnimation.isRemovedOnCompletion = false
transformAnimation.fillMode = kCAFillModeForwards
parentLayer.add(transformAnimation, forKey: "transformAnimation")
//
let transformAnimation2 = CABasicAnimation(keyPath: "bounds.size.height")
transformAnimation2.duration = 2.3
transformAnimation2.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transformAnimation2.toValue = 650*2 //CGAffineTransform.identity
transformAnimation2.beginTime = CACurrentMediaTime() + 4
transformAnimation2.autoreverses = false
transformAnimation2.isRemovedOnCompletion = false
transformAnimation2.fillMode = kCAFillModeForwards
parentLayer.add(transformAnimation2, forKey: "transformAnimation2")
When the animation is applied, the sublayers are left in wrong position and size. Should I also apply the animation to them?
How can I do this?
Thanks!
I'm guessing that you're updating width and height of one layer and you're wondering whether the bounds of sublayers will also change. No, you'll probably have to animate those separately, too. But rather than initiating separate animations, you can them with a CAAnimationGroup.
If these were views, you could define constraints that coordinate the resizing of subviews more gracefully. But with layers, you're going to have to do this yourself. (There might be reasons why you're doing it the way you are, but it's not clear from the question.)
Related
My question is a duplicate of this question asked 4 years ago, but it was never answered.
I have an NSSplitView with two subviews. The right subview has a label I want to center horizontally and vertically. The basic skeleton looks like this:
let window = /* ... */
let blankView = NSView(frame: .zero)
let customView = NSView(frame: .zero)
// set background colors
let title = NSTextField(labelWithString: "Title")
customView.addSubview(title)
let splitView = NSSplitView(frame: .zero)
splitView.isVertical = true
splitView.addSubview(blankView)
splitView.addSubview(customView)
window.contentView = splitView
Then I added in the Auto Layout code:
customView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
title.centerXAnchor.constraint(equalTo: customView.centerXAnchor),
title.centerYAnchor.constraint(equalTo: customView.centerYAnchor),
])
but now the slider can't be adjusted and the window can only be resized horizontally. The right view remains fixed in size.
I've tried various combinations of translatesAutoresizingMaskIntoConstraints =, setContentHuggingPriority(:for:) and setHoldingPriority(:forSubviewAt:) but nothing works.
I can recreate this view in Interface Builder with no problems, but I don't know how to do it programmatically.
Set translatesAutoresizingMaskIntoConstraints of the subview to false.
title.translatesAutoresizingMaskIntoConstraints = false
From the documentation of translatesAutoresizingMaskIntoConstraints:
When this property is set to true, the view’s superview looks at the view’s autoresizing mask, produces constraints that implement it, and adds those constraints to itself (the superview). If your view has flexible constraints that require dynamic adjustment, set this property to false and apply the constraints yourself.
I'm developing a magnifying glass like application for mac. My goal is to be able to pinpoint individual pixels when zoomed in. I'm using this code in mouseMoved(with event: NSEvent):
let captureSize = self.frame.size.width / 9 //9 is the scale factor
let screenFrame = (NSScreen.main()?.frame)!
let x = floor(point.x) - floor(captureSize / 2)
let y = screenFrame.size.height - floor(point.y) - floor(captureSize / 2)
let windowID = CGWindowID(self.windowNumber)
cgImageExample = CGWindowListCreateImage(CGRect(x: x, y: y, width: captureSize,
height: captureSize), CGWindowListOption.optionOnScreenBelowWindow, windowID,
CGWindowImageOption.bestResolution)
The creation of the cgImage takes place in the CGWindowListCreateImage method. When I later draw this in an NSView, the result looks like this:
It looks blurred / like some anti-aliasing was applied during the creation of the cgImage. My goal is to get a razor sharp representation of each pixel. Can anyone point me in the right direction?
Ok, I figured it out. It was a matter of setting the interpolation quality to none on the drawing context:
context.interpolationQuality = .none
Result:
On request some more code:
//get the context
guard let context = NSGraphicsContext.current()?.cgContext else { return }
//get the CGImage
let image: CGImage = //pass the result from CGWindowListCreateImage call
//draw
context.draw(image, in: (CGRect of choice))
I have an MKMapView in a window, and pitchEnabled is true (and I've confirmed this in the debugger). The "3D" thingy in the middle of the compass is grayed out, and clicking or dragging it does nothing. Option-dragging the map (like I do in Maps.app) doesn't do anything, either.
From my interpretation of the docs, setting pitchEnabled should let me use the 3D view, like Maps.app does. Am I mistaken? Is there something else I need to do to allow my users to get a 3D map view?
You can get close to the experience of 3D mode by adjusting the camera angle from which you view the map and making buildings visible. The example below allows you view the Eiffel Tower in 3D:
viewDidLoad() {
super.viewDidLoad()
mapView.mapType = MKMapType.Standard
mapView.showsBuildings = true // displays buildings
let eiffelTowerCoordinates = CLLocationCoordinate2DMake(48.85815, 2.29452)
mapView.region = MKCoordinateRegionMakeWithDistance(eiffelTowerCoordinates, 1000, 100) // sets the visible region of the map
// create a 3D Camera
let mapCamera = MKMapCamera()
mapCamera.centerCoordinate = eiffelTowerCoordinates
mapCamera.pitch = 45
mapCamera.altitude = 500 // example altitude
mapCamera.heading = 45
// set the camera property
mapView.camera = mapCamera
}
example from: this question
Since OS X El Capitan v10.11 they added a new map type: "3D flyover mode"
For some reason this option doesn't show up in XCode attributes inspector of the mapview. You have to set it programmatically. This makes the map look and behave as the one seen in the maps app.
self.mapView.mapType = MKMapTypeSatelliteFlyover;
I was able to do this in swift on iOS 11:
mapView.mapType = .hybridFlyover
That is giving me the 3D view.
Use this setup method to configure you MapView in viewDidLoad.
func setup() {
objMapView.showsUserLocation = true
objMapView.delegate = self
objMapView.showsBuildings = true
objMapView.mapType = .hybridFlyover
objLocationManager.startUpdatingLocation()
if let center = self.objLocationManager.location?.coordinate {
let currentLocationCoordinates = CLLocationCoordinate2DMake(center.latitude, center.longitude)
objMapView.region = MKCoordinateRegion.init(center: currentLocationCoordinates, latitudinalMeters: 1000, longitudinalMeters: 100)
// create a 3D Camera
let mapCamera = MKMapCamera()
mapCamera.centerCoordinate = currentLocationCoordinates
mapCamera.pitch = 45
mapCamera.altitude = 100
mapCamera.heading = 45
// set the camera property
objMapView.camera = mapCamera
}
}
In above code snippet:
mapType property hybridFlyover displays satellite map along with location names if available.
MkMapCamera instance helps in creating 3D view of map. altitude property determine altitude from where location is to be projected.
Check below screenshot for output:
I am making a game where the main character rotates, however, I want to use an SKTexture to set custom boundaries to the character sprite node. However, when I do this, my character does not rotate. When I use a regular circleOfRadius (because my sprite is round, but no perfectly round) it rotates, but is not accurate on collisions. Here is my code:
var mainSpriteTexture = SKTexture(imageNamed: "Main")
mainSprite = SKSpriteNode(texture: mainSpriteTexture)
mainSprite.setScale(0.2)
mainSprite.position = CGPoint(x: self.frame.width / 2, y: 100)
mainSprite.physicsBody = SKPhysicsBody(texture: mainSpriteTexture, size: mainSprite.size)
mainSprite.physicsBody?.categoryBitMask = PhysicsCatagory.player
mainSprite.physicsBody?.collisionBitMask = PhysicsCatagory.platform | PhysicsCatagory.ground
mainSprite.physicsBody?.contactTestBitMask = PhysicsCatagory.platform | PhysicsCatagory.ground | PhysicsCatagory.score
mainSprite.physicsBody?.affectedByGravity = true
mainSprite.physicsBody?.dynamic = true
mainSprite.physicsBody?.allowsRotation = true
self.addChild(mainSprite)
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
updateSpritePosition()
if gameStarted == true {
if died == false {
mainSprite.physicsBody?.velocity = CGVectorMake(direction, (mainSprite.physicsBody?.velocity.dy)!)
}
else if died == true {
mainSprite.physicsBody?.velocity = CGVectorMake(0, (mainSprite.physicsBody?.velocity.dy)!)
}
}
Here is the shape I am using: http://imgur.com/JCeEAbv
Not really sure how you rotate your sprite, or move it, but if I give it a certain default rotation and drop it on the surface, it rotates for me as it should (I used a picture you have provided). This way, it will not land perfectly on the ground (zRotation 0.0).
Try to use this:
mainSprite.zRotation = 0.1 //note that these are radians
and drop it on a flat surface.
Same thing you could probably achieve by applying a small force or impulse which should affect sprite's zRotation property... What you are going to use, depends on how you move your node actually - using physics, or by changing its position property directly (see my comment about mixing physics & manual node movement for important details).
I am trying to render 3D bar chart in SCNView using ScreenKit framework.
My rendering code is,
int height=10,y=0,x=0;
for (int i=0; i<10; i++) {
SCNBox *box1 = [SCNBox boxWithWidth:4 height:height length:2 chamferRadius:0];
boxNode1 = [SCNNode nodeWithGeometry:box1];
boxNode1.position = SCNVector3Make(x, y, 0);
SCNMaterial *material = [SCNMaterial material];
material.diffuse.contents = (NSColor *)[self.colorArray objectAtIndex:i%6];
material.specular.contents = [NSColor whiteColor];
material.shininess = 1.0;
box1.materials = #[material];
//boxNode1.transform = rot;
[scene.rootNode addChildNode:boxNode1];
x+=6;
height+=10;
y += 5 ;
}
I can render but while re-sizing the view the chart bars goes to the center of the view.
I need to render the chart, which cover the margins of the view and when Re-size it have to change accordingly. The image(s) below shows my problem.
Original Image:
Image where less stretching of both windows:
Can anyone please help me to fix the issue.
The the windows in the image that you had linked to in your original question was very stretched and that made it very hard to see what was going on. When I took that image and made the windows less stretched it was easier to have some idea of what is going on.
I think that you are seeing a general resizing issue. Either you are using springs and struts and have configured flexible margins on the left and right or you are using auto layout with a centered view with fixed width.
I assume that the red boxes that I have drawn in the image below is the bounds of your scene view in both these cases. You can easily see if this is the case by giving the scene view a different background color and resize it again.
My solution to your problem would be to change how your view resizes as the window resizes, to better meet your expectations.