G'day everyone,
I'm trying to interrogate the dragged object during the validate phase of drag and drop in SwiftUI, but haven't been able to make it work. Here's my validateDrop method:
func validateDrop(info: DropInfo) -> Bool {
print("Drop Validating")
print ("Dropping into slot where \(rosterPlayer!.givenName!) \(rosterPlayer!.surname!) is")
guard info.hasItemsConforming(to: [PlayerShirtUTT.uti.identifier]) else {
return false
}
let itemProviders = info.itemProviders(for: [PlayerShirtUTT.uti.identifier])
guard let itemProvider = itemProviders.first
else {
return false
}
print ("Lets check")
itemProvider.loadObject(ofClass: Player.self) { player, _ in
let player = player as? Player
// Do the player checks here
print ("Player check code")
}
return true
}
Exactly the same code in my performDrop method works fine... can anyone point me in the right direction here please?
If anyone else is looking for an answer to this, the answer is you can't.
Documentation reference:
https://developer.apple.com/documentation/uikit/drag_and_drop/making_a_view_into_a_drop_destination
The content of the dragged item is only available asynchronously after the drop is concluded (i.e. only in perdormDrop() ).
So, now I'm looking at ways to use the UTT as a distinguishing identifier for the same base data.
Related
I am using HERE-Android-SDK to build a simple navigation solution with offline maps.
In order to automatically center and rotate the map (depending on location and orientation of the user) I am using the PositioningManager class from the HERE-SDK. It seems that the orientation update is some seconds too late when an active navigation is running.
I am using the following code snippets to do so.
val positioningManager = PositioningManager.getInstance()
positioningManager.addListener(WeakReference(positionListener))
positioningManager.start(PositioningManager.LocationMethod.GPS)
var positionListener = object : PositioningManager.OnPositionChangedListener {
override fun onPositionFixChanged(
p0: PositioningManager.LocationMethod?,
p1: PositioningManager.LocationStatus?
) {
// do nothing here
}
override fun onPositionUpdated(
method: PositioningManager.LocationMethod?,
position: GeoPosition?,
isMapMatched: Boolean
) {
if (position == null) return
// update map center and orientation
}
}
override fun onPause() {
positioningManager.stop()
}
override fun onResume() {
positioningManager.start(PositioningManager.LocationMethod.GPS)
}
Is there anything I can do to avoid the too late orientation update?
Thanks for all of your help in advance!
Ok, I have looked EVERYWHERE and am trying here to simply extract an animation from a .dae imported into Xcode (or a .scn, whatever) so that I can run it on the model throughout my scene kit game. the problem is every way to do this that is referenced (including here Scenekit: Add animation to SCNNode from external Collada)
seems to be deprecated in iOS 11. So I have no way to animate any 3D model I put in my scene.
Right now I am able to display the model just still with this - I get the model from my dae and put it into my blank scn :
if let d = modelScene.rootNode.childNodes.first
{
theDude.node = d
theDude.setupNode() //this scales it down
}
func setupNode()
{
node.scale = SCNVector3(x: modifier, y: modifier, z: modifier)
}
//Then add to scene on tap
let clone = theDude.node.clone()
theDude.node = clone
self.sceneView.scene.rootNode.addChildNode(theDude.node)
theDude.node.position = hitPosition
This works. Trying to get it to run the animation that I added to it in Maya, however, does not. I added these extensions per Apple's example to my project:
https://developer.apple.com/library/content/samplecode/Fox/Listings/Swift_Common_SceneKitExtensions_swift.html
And was trying to do this as it says to, just with a cube as a basic test (from the above question):
func addAnim()
{
let characterScene = SCNScene(named: "art.scnassets/cubeAnimatedSkeleton.dae")!
let characterTopLevelNode = characterScene.rootNode.childNodes[0]
sceneView.scene.rootNode.addChildNode(characterTopLevelNode)
let idleAnimation = CAAnimation.animationWithSceneNamed("art.scnassets/cubeAnimatedSkeleton.dae")!
idleAnimation.usesSceneTimeBase = false
idleAnimation.repeatCount = Float.infinity
characterTopLevelNode.addAnimation(idleAnimation, forKey: "idle")
}
But with this CAAnimation.animationWithSceneNamed("art.scnassets/cubeAnimatedSkeleton.dae")! the whole thing does not work because this extension from APPLE:
extension CAAnimation {
class func animationWithSceneNamed(_ name: String) -> CAAnimation? {
var animation: CAAnimation?
if let scene = SCNScene(named: name) {
scene.rootNode.enumerateChildNodes({ (child, stop) in
if child.animationKeys.count > 0 {
animation = child.animation(forKey: child.animationKeys.first!) //ERROR
stop.initialize(to: true)
}
})
}
return animation
}
}
says that addAnimation for key was deprecated in iOS 11. Replacing that with animation = child.animationPlayer(forKey: child.animationKeys.first!) doesn't work, and I don't know what else to do.
What is wrong here?
Ok, I am working in Swift 3 playgrounds and need to move a sprite node to a certain point ONLY when the user's mouse is down, stopping when it's released. So far I have:
override func mouseDown(with event: NSEvent) {
mouseIsDown = true
}
override func mouseDragged(with event: NSEvent) {
}
override func mouseUp(with event: NSEvent) {
mouseIsDown = false
}
func moveGuy() {
let action = SKAction.move(to: CGPoint(x: size.width / 2,y: 200), duration: 2)
action.timingMode = .easeInEaseOut
guy.run(action)
}
//UPDATE
override func update(_ currentTime: CFTimeInterval) {
if(mouseIsDown)
{
moveGuy()
}
}
This works somewhat, the problem is only after I release the mouse (mouseIsDown is false) does the SKAction actually run (smoothly). I think this is because it is being called again and again.
Normally I would use a moveBy action in little increments, but I need my node to move to a specific point.
How can I make my node move on its way to a point only when the mouse is down?
When you call
guy.run(action)
sprite-kit will run the action on the guy until completion. You're correct, moveGuy() is being called again and again (every time the frame is update, i.e. every ~33ms assuming 30fps).
Try placing moveGuy() in mouseDown(). As soon as you click, the guy will move smoothly to his destination, but he won't stop if you stop clicking. You need to somehow stop the action. What you can do is replace
guy.run(action)
with
guy.run(action, withKey: "moveGuy")
This will associate a key with your action, that you can look up later on in mouseUp():
guy.removeAction(forKey: "moveGuy")
After this, your node will move to a point only when your mouse is down. But as you've pointed out, the node's movement is still irregular if you re-click. Try changing .easeInEaseOut to .linear. The movement will then be consistent, albeit abrupt when starting/stopping.
I highly recommend the reading documentation on SKActions to gain a better understanding of how to use them.
- (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:
(NSInteger)component {
if(thePickerView == self.countryPicker){
self.countryLbl.text = [self.responseArray objectAtIndex:row];
}
}
- (IBAction)countryDoneBtn:(id)sender {
// Picker first row selected on done button
[self.countryLbl setText:[NSString stringWithFormat:#"%#", [self.responseArray
objectAtIndex:[self.countryPicker selectedRowInComponent:0]]]];
[self myViewDown:self.countryView];
[self.durationView removeFromSuperview];
//[post selectState:[self.responseArray objectAtIndex:row ]];
}
i want to do this "[post selectState:[self.responseArray objectAtIndex:row]];"
but can't access "objectAtIndex:row" here in this "- (IBAction)countryDoneBtn:(id)sender"
method.
Please friend help me how can i access the row from this IBAction
Thanks in advance need your help i'm new in iphone development
The row variable is not available because the row you are looking for is only passed in the delegate method didSelectRow:inComponent of the picker view.
Based on you are trying to do, you can still get the selected row of the picker with the method selectedRowInComponent, which you have already used to set the text of the countryLbl.
So, just use the same method to get the object from your responseArray:
NSInteger selectedRow = [self.countryPicker selectedRowInComponent:0];
[post selectState:[self.responseArray objectAtIndex:selectedRow]];
I have a problem with my OpenGL Cocoa application - every time a keyUp / KeyDown event is fired, a system sound is being played... How can I disable this logic for my application?
I have a bad feeling that for some strange reason my application may treat a key press as an error and play system alert sound... Please help!
add to your NSView/NSWindow subclass
- (void)keyDown:(NSEvent *)theEvent {
and make exception on up and down keys, but for other [super keyDown:theEvent];
i think it's may sense
For me, the following has turned out to be the optimal solution:
override func awakeFromNib() {
// Do your setup here.
NSEvent.addLocalMonitorForEvents(matching: .keyDown) {
if keyDownPressed(with: $0) {
return nil
}
return $0
}
}
func keyDownPressed(with event: NSEvent) -> Bool {
print("caught a key down: \(event.keyCode)")
if event.keyCode == 125 {
//your code for arrow down here
return true
}
if event.keyCode == 126 {
//your code for arrow up here
return true
}
return false
}
Create a Cocoa Class, subclassing it from NSView
Set it as the class for your View instead of standard greyed-out NSView in storyboard
Add the following to your subclass implementation:
#implementation YourCustomNSView
- (BOOL)acceptsFirstResponder {
return YES;
}
- (void)keyDown:(NSEvent *)theEvent {
NSLog (#"keypress %#", theEvent);
// [super keyDown:theEvent]; // this line triggers system beep error, there's no beep without it
}
#end
Swift 5.6 solution
It's caused because of unhandled keydown events in your responder chain.
Make sure some NSView subclass in your responder chain overrides this and returns true.
override performKeyEquivalent(with event: NSEvent) -> Bool {}