I'd like to create a pause menu but I don't know the simplest way to do this...
I think a simple way would be to pause all my SKActions, but I couldn't find any method in the reference.
Thanks for help.
Documentation says that parent SKView object has a paused property. Set it to YES to pause the scene.
Paused
A Boolean value that indicates whether the view’s scene animations are
paused.
#property(getter=isPaused, nonatomic) BOOL paused
Discussion If the
value is YES, then the scene’s content is fixed on screen. No actions
are executed and no physics simulation is performed."
//the parent SKView
spriteView = (SKView *) self.view;
//pause button
-(IBAction)goPauseButton {
if(!spriteView.paused){
spriteView.paused = YES;
}else{
spriteView.paused = NO;
}
}
You can also pause all the SKActions by setting the speed of the scene to zero-- this means that all the actions will stop, and you do not need to worry about them moving to where they would not have been if you did not pause
self.speed = 0;
easy as that
Related
I recently stumbled upon a problem where I have a view that can be rotated by the user. During the rotation it should, however, be 10% larger (scaled up).
I want that scaling to be animated but the rotation to be be visible immediately since I set it without animation in the gesture recognizer's callback.
Question: Is it possible to update an CGAffineTransform's rotation without intercepting the scale being animated, or is there no way around creating a wrapping view that gets scaled instead?
Edit:
I think a wrapper view for scaling would be the least error prone way.
If you desperately want to avoid that, you could try to create the scaling animation manually with an NSTimer. Maybe if you query the current transform value first and then modify it instead of replacing it by an independently created one (for the rotation and the scale), it could work.
I think an implicit UIView animation calculates all subsequent values in the beginning, so that would mess up your rotation.
Another way to go would be to lock the rotation while the scaling occurs. The downside is, that scaling and rotation wouldn't be simultaneously. Anyway you could create an iVar or property let's say rotationLocked and do sth. like this:
- (void)handlePan:(UIPanGestureRecognizer *)gr
{
if (gr.state == UIGestureRecognizerStateBegan)
{
self.rotationLocked = YES;
[UIView animateWithDuration:.2 animations:^{
[self scaleView];
}completion:^{ self.rotationLocked = NO; };
}
if (gr.state == UIGestureRecognizerStateChanged)
{
if (!self.rotationLocked){
// do the rotation
}
if (gr.state == UIGestureRecognizerStateEnded)
{
// do something else
}
I've got a view containing subviews of various types on it. At one point, I would like to disable all interactions with the view and subviews, and register instead taps from a gesture recognizer I place on the whole view:
tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:revealController action:#selectorrdoSomething:)];
tapGestureRecognizer.cancelsTouchesInView = YES;
While it sort of works, the view below still interacts to all the touches. I then tried adding:
tapGestureRecognizer.delaysTouchesBegan = YES;
tapGestureRecognizer.delaysTouchesEnded = YES;
It now works EXCEPT - when I tap over a UITextField, this receives the touch INSTEAD of the gesture recognizer. Why is this, how can I stop it? Any help is much appreciated :)
Sounds like what you want to do is set the view you don't want receiving the touches .userInteractionEnabled property to FALSE. Or I am misunderstanding something.
yourView.userInteractionEnabled = FALSE;
I've put a MPVolumeView over a movie I'm playing. The trouble is, whenever I adjust the vol using the MPVolumeView, then the standard grey volume overlay appears (the one that appears when you use the rocker switch on the iPhone). Is there a way to disable the standard grey overlay?
I might be a bit late, but I think I have something useful to add. If you're just looking for an answer, skip to How did I fix it?
What is MPVolumeView?
The MPVolumeView class is used to put a slider onscreen that controls the system volume. It's supposed to prevent the system volume overlay from appearing while it is onscreen, but sometimes does not. I ran into this issue when I added my own MPVolumeView to the view hierarchy, but still saw the overlay appear when I dragged the slider.
How does MPVolumeView tell when it is visible?
This is the question I asked myself. Somehow, the class detects whether or not it is visible, and tells the system to hide or display the system volume overlay accordingly. This is because Apple does not really want you using the class just to prevent the overlay from appearing, without actually displaying the slider UI to the user (as in myell0w's answer).
Here's how I believe MPVolumeView tries to check if it is really visible:
When the view is added to a superview, as detected by viewWillMoveToSuperview: and viewDidMoveToSuperview, it starts a short timer.
When the timer fires, the view traverses its view ancestor tree by recursively examining the superview property.
MPVolumewView checks that each of its ancestors has hidden = NO and alpha greater than some small value (likely 0.05).
There could be other checks that I'm not aware of, since this code is of course closed-source. The timer in step 1 is there so that code like the following will not "fool" the view:
MPVolumeView *volView = [[MPVolumeView alloc] init];
[self.view addSubview:volView];
volView.hidden = YES;
because it will check the hidden property not immediately, but in a bit, after it is already set to YES.
How did I figure all of this out? A key find was that the instance of MPVolumeView was calling isHidden on its superview, as shown in the following stack trace:
What was my problem?
In short, I did something like this:
- (void)viewDidLoad {
// Add an MPVolumeView to my view
self.volView = [[MPVolumeView alloc] init];
[self.view addSubview:self.volView];
self.volView.hidden = YES;
}
- (void)someButtonTouched {
// Show the MPVolumeView (and hopefully hide the system overlay)
self.volView.hidden = NO;
}
But when I dragged the slider of the newly revealed MPVolumeView, the overlay still appeared. I realized that this was because during the MPVolumeView's instantiation, its superview was hidden.
How did I fix it?
Once I had realized how the MPVolumeView class judged whether it was visible, I had an easy way to "fool" it. I added the following method to the class responsible for the MPVolumeView:
- (void)refreshVolumeView {
[self.volView willMoveToSuperview:self];
[self.volView didMoveToSuperview];
}
and called it each time I need to force the view to reevaluate whether it was visible. This method simply pretends to re-add the view to the hierarchy. Once I've satisfied the conditions that the view evaluates (each ancestor is not hidden or of very low alpha), I call it, and the overlay stops showing up. In my example code above, I would add one line:
- (void)viewDidLoad {
// Add an MPVolumeView to my view
self.volView = [[MPVolumeView alloc] init];
[self.view addSubview:self.volView];
self.volView.hidden = YES;
}
- (void)someButtonTouched {
// Show the MPVolumeView (and hopefully hide the system overlay)
self.volView.hidden = NO;
[self refreshVolumeView]; // <<< This line was added
}
Normally when a MPVolumeView is visible the HUD doesn't appear. I'm using the following method in my App and it is working fine:
+ (void)preventSystemVolumePopup {
// Prevent Audio-Change Popus
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(-2000., -2000., 0.f, 0.f)];
NSArray *windows = [UIApplication sharedApplication].windows;
volumeView.alpha = 0.1f;
volumeView.userInteractionEnabled = NO;
if (windows.count > 0) {
[[windows objectAtIndex:0] addSubview:volumeView];
}
}
It basically just adds a volume view to the first window at a position where nobody can see it and thus prevents the system volume HUD from showing. I wonder why you see this HUD, even though you put a volume view above your movie.
This may help.
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.volumeView.hidden = NO;
[self.volumeView willMoveToSuperview:self.volumeView.superview];
[self.volumeView didMoveToSuperview];
}
Easiest way to do this.....
- (void) viewDidLoad
{
[super viewDidLoad];
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame: CGRectZero];
[self.view addSubview: volumeView];
...
}
taken refrence from this thread applicationMusicPlayer volume notification
Hi everyone I'm french so scuse me for my english.My problem is the following: I have an image in the center of the screen called viewToRotate, then I have an image called flakeView that is created outside of the screen and then it is moving to the center, and every second a Timer does this(create a flakeView outside the screen and then move it to the center of the screen).
What I wanted to do was : if flakeView and viewToRotate collide reduce the alpha of viewToRotate to 0.5. But when flakeView appears on the screen the action of reducing the alpha is called without the collision of viewToRotate and flakeView, so they collide before they touches. I don't know why. How can I solve this please . Here is the code :
UIImageView* flakeView = [[[UIImageView alloc] initWithImage:flakeImage] autorelease];
// use the random() function to randomize up our flake attributes
int startY = round(random() % 320);
// set the flake start position
flakeView.center = CGPointMake(490, startY);
flakeView.alpha = 1;
// put the flake in our main view
[self.view addSubview:flakeView];
[UIView animateWithDuration:7
animations:^{
// set the postion where flake will move to
flakeView.center = viewToRotate.center;
}];
}
-(void)checkCollision{
if(CGRectIntersectsRect(flakeView.frame, viewToRotate.frame) == 1)
{
viewToRotate.alpha=0.5;
}
}
I would not suggest using a timer on viewDidLoad. I believe that you should set the timer at some other function. Even if you do not use viewDidLoad for anything else.
The other thing is the UIView animations. Even if you have a timer at every 60fps the attributes of the animated objects are not changed by the animation. So before you create the animation you set those properties once. And when you create the animation you set the same properties for the second time. And that's it. From now on while the animation is running if you do checks on the properties you will always get the second values.
To have a working code one option is to create the UIView animations (and perform the property checks) for every step at a certain time interval. Or use OpenGL.
Before getting too deep into this issue, please also make sure that your viewToRotate.frame is actually sized the way you expect it (see my comment).
Once you are certain about those attributes, you might want to check the collision on the current presentationLayer of your animated objects and not on their original state.
UIView.layer.presentationLayer
Returns a copy of
the layer containing all properties as
they were at the start of the current
transaction, with any active
animations applied.
So you might adapt your collision detection like this:
-(void)checkCollision
{
if(CGRectIntersectsRect(flakeView.layer.presentationLayer.frame, viewToRotate.layer.presentationLayer.frame) == 1)
{
viewToRotate.alpha=0.5;
}
}
Also consider using the CoreAnimation Layer method hitTest: instead of your handmade collision detection.
hitTest: Returns the farthest
descendant of the receiver in the
layer hierarchy (including itself)
that contains a specified point.
These are the following things you would want to check.
Dont init with image, use init with frame and then do
flakeView.image = ----; Because your image could be wide enough
initially , and hence colliding from the time you initialize.
Try alternatives to .center, like .frame.size.x , because I have had
problems with .center as well
You could probably NSLog the bounds of both ur imageviews before and
after reducing alpha
Is there a way to deactivate the decelerating of a UIScrollView?
I want to allow the user to scroll the canvas, but I don't want that the canvas continues scrolling after the user lifted the finger.
This can be done by utilizing the UIScrollView delegate method scrollViewWillBeginDecelerating to automatically set the content offset to the current screen position.
To implement:
Assign a delegate to your UIScrollView object if you have not already done so.
In your delegate's .m implementation file, add the following lines of code:
-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{
[scrollView setContentOffset:scrollView.contentOffset animated:YES];
}
Voila! No more auto-scroll.
For iOS 5.0 or later, there is a better method than calling setContentOffset:animated:.
Implement delegate method scrollViewWillEndDragging:withVelocity:targetContentOffset: in your .m file:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset {
targetContentOffset.pointee = scrollView.contentOffset;
}
Assigning the current offset to targetContentOffset stops the UIScrollView from auto-scrolling.
You can just turn up the deceleration rate very high. With an infinite rate, it would stop immediately. Try setting the rate to these constants:
scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
and
scrollView.decelerationRate = UIScrollViewDecelerationRateFast;
If fast still isn't fast enough for you, UIScrollViewDecelerationRateFast is just typedef'ed as a float, so you can just multiply it by a factor of 10 or so to speed it up even more.
Just set the decelerationRate property to 0
It will disable the auto scrolling property. But keep in mind the user interaction will become bad if scrollview contentsize is big.
Previous Swift version:↓
scrollView.decelerationRate = UIScrollView.DecelerationRate.fast
Current Swift 4.2 version code:↓
scrollView.decelerationRate = UIScrollViewDecelerationRateFast