tvOS: detecting pause button press - uigesturerecognizer

I am trying to detect when a user presses the play/pause button on the remote. I have created a tap gesture recognizer and attached it to the view of a AVPlayerViewController subclass.
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(togglePlayPause:)];
tapGestureRecognizer.allowedPressTypes = #[#(UIPressTypePlayPause)];
[self.view addGestureRecognizer:tapGestureRecognizer];
- (void)togglePlayPause:(UITapGestureRecognizer *)tapGestureRecognizer
{
NSLog(#"Toggle play/pause");
if ([self playing])
{
NSLog(#" Pause");
[self.player pause];
}
else
{
NSLog(#" Play");
[self.player play];
}
}
The gesture fires fine when the "play" button is pressed but does not when the "pause" button is pressed. Any ideas why?

Related

NSButton with Mouse Down/Up and Key Down/Up

I need a NSButton that gives me 2 events, one when the button is pressed down (NSOnState) and one when the button is released (NSOffState) and so far i've got it working with the mouse (intercepting the mouseDown: event). But using a keyboard shortcut doesn't work, it fires a NSOnState once and then after a delay really often. Is there any way to get a button that fires NSOnState when pressed and NSOffState when released?
My current subclass of NSButton looks like this and unfortunately works using a delegate:
-(void)awakeFromNib {
[self setTarget:self];
[self setAction:#selector(buttonAction:)];
}
-(void)mouseDown:(NSEvent *)theEvent {
[_delegate button:self isPressed:YES];
[super mouseDown:theEvent];
}
-(void)buttonAction:(id)sender {
[_delegate button:self isPressed:NO];
}
The button can be set to send mouse events at both times by using -sendActionOn::
[self.button sendActionOn: NSLeftMouseDownMask | NSLeftMouseUpMask];
Handling keyboard events similarly seems more difficult. If you don't need the event exactly at the same time the highlight is removed from the button, you could override NSButton's -performKeyEquivalent: so that it will e.g. send the action twice.
- (BOOL) performKeyEquivalent: (NSEvent *) anEvent
{
if ([super performKeyEquivalent: anEvent])
{
[self sendAction: self.action to: self.target];
return YES;
}
return NO;
}
If you do need the event at the same time, I think you need to use a custom button cell (by creating a subclass of NSButtonCell and setting the button's cell in the initializer) and override its -highlight:withFrame:inView::
- (void)highlight:(BOOL)flag
withFrame:(NSRect)cellFrame
inView:(NSView *)controlView
{
[super highlight: flag withFrame:cellFrame inView:controlView];
if (flag)
{
// Action hasn't been sent yet.
}
else
{
// Action has been sent.
}
}

Remove first responder from a group of NSTextFields by pressing tab or clicking outside

I'm developing an app for MacOSX in Xcode
which is a screen with a group of NSTextFields selectable and editable all of them
Every time I press tab this changes from NSTextField to NSTextField in ordered way...
Now I want to remove textfield's first responder by clicking outside of any NSTextField or when I go to last NSTextField of the NSWindowController, lets call it descripcionBitacoraTextField
as far as I know there's a method called
- (void)controlTextDidEndEditing:(NSNotification *)aNotification
and I added there next code
- (void)controlTextDidEndEditing:(NSNotification *)aNotification{
NSTextField *textField = (NSTextField *)[aNotification object];
if (textField == self.descripcionBitacoraTextField) {
[[textField window] makeFirstResponder:nil];
}
}
which triggers when I finish editing any textField but when I press Tab button for finishing last NSTextField, it starts focusing my first NSTextField like an endless carrousel
for clicking outside:
-(void)mouseDown:(NSEvent *)event {
[self.window makeFirstResponder:nil];
}
if you want to exit when you tab last NSTextField you can:
-(BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector{
NSTextField *textField = (NSTextField *) control;
if (commandSelector == #selector(insertTab:) && (textField == self.descripcionBitacoraTextField)) {
[self.window makeFirstResponder:[[textView window]nextResponder]];
return YES;
}
else if (commandSelector == #selector(insertTab:)){
[self.window makeFirstResponder:[self.contentView viewWithTag:(textField.tag +1)]];
return YES;
}
return NO;
}

Hooking Event at NSWindow

I'm making popup tooltip in NSWindow, like following XCode tooltip
If user press a button, popup is shown. It is easy.
But after that, if user press any button in this window, popup should be hidden.
But if user press button, nswindow's mousedown: isn't be called. so nswindowcontroller can not receive that event.
How can nswindow can detect all event in window's region?
You can create a contextMenu for small window, that opens on your action.
*NOTE: in the image, that is a custom view, not a contextMenu.*
- (IBAction)button:(id)sender {
NSRect frame = [(NSButton *)sender frame];
NSPoint menuOrigin = [[(NSButton *)sender superview] convertPoint:NSMakePoint(frame.origin.x+80, frame.origin.y+frame.size.height-10)
toView:nil];
NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouseDown
location:menuOrigin
modifierFlags:NSLeftMouseDownMask // 0x100
timestamp:0.0
windowNumber:[[(NSButton *)sender window] windowNumber]
context:[[(NSButton *)sender window] graphicsContext]
eventNumber:0
clickCount:1
pressure:1];
NSMenu *menu = [[NSMenu alloc] init];
[menu setAutoenablesItems:NO];
[menu insertItemWithTitle:#"Add Favorite"
action:#selector(addFavorite:)
keyEquivalent:#""
atIndex:0];
[menu insertItem:[NSMenuItem separatorItem] atIndex:1];
[menu insertItemWithTitle:#"Manage Favorite"
action:#selector(manageFavorite:)
keyEquivalent:#""
atIndex:2];
[NSMenu popUpContextMenu:menu withEvent:event forView:(NSButton *)sender];
}
-(IBAction)addFavorite:(id)sender{
NSLog(#"add");
}
-(IBAction)manageFavorite:(id)sender{
NSLog(#"mangage");
}

How to set button selection and unselection image?

when i am touch the button to show selected image and again touch that button unselection image shown.
I am try this coding:
UIButton *btn=(UIButton*) sender;
if (btn.selected=YES)
{
[btn setImage: [UIImage imageNamed:#"reportsel.png"] forState:UIControlStateSelected];
}else{
[btn setImage:[UIImage imageNamed:#"reports.png"] forState:UIControlStateNormal];
}
Anytime click this button not went to else condition.
For Highlighted state, use:
[btnObj setImage:[UIImage imageNamed:#"imgName.png"] forState:UIControlStateHighlighted];
In Normal State, use:
[btnObj setBackgroundImage:[UIImage imageNamed:#"imgName1.png"] forState:UIControlStateNormal];

EXC_BAD_ACCESS on setImage occurs when pressing button, but not with asynchronous call to setImage

I have a button that, when selected, I want to use it to display an artwork image, but when not selected, I want to display a background image. The button is called the albumArtworkView button and is essentially a toggle between display modes. While in the selected state, new artwork is displayed periodically. In order for the displayed image to be a sharp image, I've found that the artwork must be resized to the bounds of the albumArtworkView button as shown in the lines of the following routine:
-(void) handleChangesToArtwork {
...
MPMediaItemArtwork *artwork = [currentItem valueForProperty: MPMediaItemPropertyArtwork];
if (artwork) {
artworkImage = [artwork imageWithSize: CGSizeMake (10, 10)]; // size for nav button
}
...
if (albumArtworkShowing) {
artworkImage = [artwork imageWithSize: albumArtworkView.bounds.size]; // resize artwork for albumArtworkView button
[albumArtworkView setImage:artworkImage forState: UIControlStateNormal];
}
...
}
Now artworkImage and albumArtworkView are defined as follows:
#interface RootViewController : UIViewController <...> {
UIImage *artworkImage;
IBOutlet UIButton *albumArtworkView;
}
-(IBAction) showAlbumArtwork:(id)sender;
#property (nonatomic, retain) UIImage *artworkImage;
#property (nonatomic, retain) IBOutlet UIButton *albumArtworkView;
Notice the definition of the showAlbumArtwork method to handle the button selection action. This method is implemented as follows:
-(IBAction) showAlbumArtwork:(id)sender {
if (albumArtworkShowing) {
[self setAlbumArtworkShowing:FALSE];
[albumArtworkView setImage:[UIImage imageNamed: #"backgroundImage.png"] forState: UIControlStateNormal];
}
else {
[self setAlbumArtworkShowing:TRUE];
if (artworkImage) {
[albumArtworkView setImage:artworkImage forState: UIControlStateNormal]; // Now change the look of the albumArtworkView (speaker button) to the newly sized artworkImage
}
else {
[albumArtworkView setImage:[UIImage imageNamed: #"no_artwork.png"] forState: UIControlStateNormal];
}
}
}
So, if I run the above code, there are no crashes. However, the first display of the artwork when I press the button is fuzzy (because as you can see from the logic above, it is using a cgsize of 10,10). But now that the albumArtworkView button has been selected and the albumArtworkShowing flag is now TRUE, every subsequent execution of handleChangesToArtwork resizes the artwork to the bounds of the albumArtworkView button and the images are no longer fuzzy.
If I modify the handleChangesToArtwork routine above to include an else when the albumArtworkShowing flag is FALSE as shown below:
-(void) handleChangesToArtwork {
...
if (albumArtworkShowing) {
...
}
else {
artworkImage = [artwork imageWithSize: albumArtworkView.bounds.size];
}
}
then that is when I get a EXC_BAD_ACCESS. This error occurs in the showAlbumArtwork method when the button is selected. Specifically it occurs on the line with the setImage.
I suspect that I must have some memory management issue, but I am not sure where.
Can anyone see the errors of my ways?
Change
artworkImage = [artwork imageWithSize: albumArtworkView.bounds.size];
to
self.artworkImage = [artwork imageWithSize: albumArtworkView.bounds.size];
This will make sure the artworkImage property's setter is used, which retains the instance. In your current code you assign an autoreleased UIImage to artworkImage without retaining it, causing the EXC_BAD_ACCESS.

Resources