Can I add custom UI Elements to UIActionSheet? - objective-c

I've successfully added Buttons to my UIActionSheet. I was wondering if I could add other elements, adjust the opacity, and alter the direction of the panel flying in (default comes in from below)with my UIActionSheet?
I am relatively new to iOS programming so any help would be greatly appreciated.

If you’re going to customize it to that degree, you’re better off just creating your own custom overlay view and adding whatever controls you need to it. Adjusting the animation direction in particular would be more trouble than it’s worth.
For more information on custom views and the view hierarchy, plus a useful section on animations (see the sidebar), check out the View Programming Guide for iOS.

Write implemention!
//.h
#import <UIKit/UIKit.h>
#interface UIImageActionSheet : UIActionSheet {
UIImage *titleImage;
}
-(id) initWithImage:(UIImage *)image
title:(NSString *)title
delegate:(id <UIActionSheetDelegate>)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles;
#end
//.m file
#import "UIImageActionSheet.h"
#implementation UIImageActionSheet
-(id) initWithImage:(UIImage *)image
title:(NSString *)title
delegate:(id <UIActionSheetDelegate>)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles{
self = [super initWithTitle:title delegate:delegate
cancelButtonTitle:cancelButtonTitle
destructiveButtonTitle:destructiveButtonTitle
otherButtonTitles:otherButtonTitles,nil];
if (self) {
titleImage=image;
[titleImage retain];
UIImageView *imageView = [[UIImageView alloc] initWithImage:titleImage];
imageView.frame = CGRectZero;
for (UIView *subView in self.subviews){
if (![subView isKindOfClass:[UILabel class]]) {
[self insertSubview:imageView aboveSubview:subView];
break;
}
}
[imageView release];
}
return self;
}
- (CGFloat) maxLabelYCoordinate {
// Determine maximum y-coordinate of labels
CGFloat maxY = 0;
for( UIView *view in self.subviews ){
if([view isKindOfClass:[UILabel class]]) {
CGRect viewFrame = [view frame];
CGFloat lowerY = viewFrame.origin.y + viewFrame.size.height;
if(lowerY > maxY)
maxY = lowerY;
}
}
return maxY;
}
-(void) layoutSubviews{
[super layoutSubviews];
CGRect frame = [self frame];
CGFloat labelMaxY = [self maxLabelYCoordinate];
for(UIView *view in self.subviews){
if (![view isKindOfClass:[UILabel class]]) {
if([view isKindOfClass:[UIImageView class]]){
CGRect viewFrame = CGRectMake((320 - titleImage.size.width)/2, labelMaxY + 10,
titleImage.size.width, titleImage.size.height);
[view setFrame:viewFrame];
}
else if(![view isKindOfClass:[UIImageView class]]) {
CGRect viewFrame = [view frame];
viewFrame.origin.y += titleImage.size.height+10;
[view setFrame:viewFrame];
}
}
}
frame.origin.y -= titleImage.size.height + 2.0;
frame.size.height += titleImage.size.height + 2.0;
[self setFrame:frame];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code.
}
*/
- (void)dealloc {
[super dealloc];
if (titleImage) {
[titleImage release];
}
}
#end

You have to create a custom overlay

Related

UITableViewCell UITapGestureRecognizer not responding

I am a beginner with Objective-C and I am working on existing code base.
In the following code, UITapGestureRecognizer doesn't seem to trigger tap method. I have tried adding
[self setUserInteractionEnabled:YES];
Can anyone help me figure out what is not working here.
This is my UITableViewCell implementation class:
#interface ELCAssetCell ()
#property(nonatomic, strong) NSArray * rowAssets;
#property(nonatomic, strong) NSMutableArray * rowViews;
#end
#implementation ELCAssetCell
#synthesize rowAssets;
- (id)initWithReuseIdentifier:(NSString *)_identifier cellWidth:(CGFloat)width {
if (self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_identifier]) {
self.rowViews = [[NSMutableArray alloc] init];
for (int i = 0; i < 4; i++) {
[self.rowViews addObject:[[AssetView alloc] initWithFrame:CGRectZero]];
}
for (AssetView * view in self.rowViews) {
[self addSubview:view];
}
_width = width;
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat itemWidth = _width / 4;
CGRect frame = CGRectMake(2, 2, itemWidth - 4, itemWidth - 4);
for (AssetView * view in self.rowViews) {
[view setFrame:frame];
[[view gestureRecognizers] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL
*stop) {
[view removeGestureRecognizer:obj];
}];
[view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(tap:)]];
frame.origin.x += itemWidth;
}
}
- (void)tap:(UITapGestureRecognizer *)gest {
[self.delegate assetPressed:[(AssetView *)[gest view] asset]];
[(AssetView *)[gest view] toggleSelection];
}
#end
The most likely problem is that you are adding the views to the cell itself -- they should be added to the cell's contentView.
Change:
for (AssetView * view in self.rowViews) {
[self addSubview:view];
}
to:
for (AssetView * view in self.rowViews) {
[self.contentView addSubview:view];
}
Aside from that, this looks absolutely terrible!
you should be using auto-layout instead of setting frames
layoutSubviews can be called multiple times... you should be adding the UITapGestureRecognizer when you create the views, not removing / re-adding every time layoutSubviews is called.

Obejctive C: Recursion(?) within Controller

I have got a problem with my WindowController for an App that's basically a list of items, sitting on a panel that can be opened from the menu bar.
To open the panel the user has to click on the App's Status item in the menubar. The app loads fine and everything works ok if the panel is open from the start (and you don't click the status item). However, if its hidden at launch and one clicks the statusitem to open the panel, the App starts eating away huge chunks of RAM without ever getting out of the loop that is creating this effect.
I have worked with some breakpoints to try to find the problem. It seems that some methods within my Window Controller keep calling each other creating an endless loop. But I can't figure out why.
Maybe one of you guys can spot the problem. If any other lines of code are of interest I will try to get them to you. However, for now this is the heart of the application. The rest does not contain that much logic (apart from the AppDelegate).
Here's the Controller's .m-file:
//
// UIController.m
// hourglass
//
// Created by Matze on 24/04/14.
// Copyright (c) 2014 hourglass. All rights reserved.
//
#import "UIController.h"
#implementation UIController
- (id)initWithDelegate:(id<UIControllerDelegate>)delegate {
self = [super initWithWindowNibName:#"UI"];
if (self != nil) {
_delegate = delegate;
}
return self;
}
- (void)deleteSelectedObjects {
NSArray *objectArray = [_Tasks selectedObjects];
for (int i = 0; i < [objectArray count]; i++) {
NSManagedObject *mo2delete = [objectArray objectAtIndex:i];
[[[NSApp delegate] managedObjectContext] deleteObject: mo2delete];
}
}
#pragma Actions
- (IBAction)buttonDelete:(id)sender {
NSUInteger row = [TableView rowForView:sender];
[TableView selectRowIndexes:[[NSIndexSet alloc] initWithIndex:row] byExtendingSelection:NO];
[self deleteSelectedObjects];
}
- (void)keyDown:(NSEvent *)event {
unichar key = [[event charactersIgnoringModifiers] characterAtIndex:0];
if(key == NSDeleteCharacter)
{
if([TableView selectedRow] == -1)
{
NSBeep();
}
BOOL isEditing = [[NSApp delegate]isEditing];
if (!isEditing)
{
[self deleteSelectedObjects];
return;
}
}
[super keyDown:event];
}
#pragma UI Drawing & Animation
- (void)awakeFromNib
{
[super awakeFromNib];
// Create Panel
NSPanel *panel = (id)[self window];
[panel setAcceptsMouseMovedEvents:YES];
[panel setLevel:NSPopUpMenuWindowLevel];
[panel setOpaque:NO];
[panel setBackgroundColor:[NSColor clearColor]];
// Resize Panel
NSRect panelRect = [[self window] frame];
panelRect.size.height = POPUP_HEIGHT;
[[self window] setFrame:panelRect display:NO];
}
- (NSRect)statusRectForWindow:(NSWindow *)window {
NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame];
NSRect statusRect = NSZeroRect;
statusItemView = nil;
if ([[self delegate] respondsToSelector:#selector(statusItemViewForUIController:)]) {
statusItemView = [[self delegate] statusItemViewForUIController:self];
}
if (statusItemView) {
statusRect = [statusItemView globalRect];
statusRect.origin.y = NSMinY(statusRect) - NSHeight(statusRect) - 2 ;
} else {
statusRect.size = NSMakeSize(STATUS_ITEM_VIEW_WIDTH, [[NSStatusBar systemStatusBar] thickness]);
statusRect.origin.x = roundf((NSWidth(screenRect) - NSWidth(statusRect)) / 2);
statusRect.origin.y = NSHeight(screenRect) - NSHeight(statusRect) * 2;
}
return statusRect;
}
- (void)setHasActivePanel:(BOOL)flag
{
if (_hasActivePanel != flag)
{
_hasActivePanel = flag;
if (_hasActivePanel)
{
[self openPanel];
}
else
{
[self closePanel];
}
}
}
- (void)windowWillClose:(NSNotification *)notification {
[self setHasActivePanel:NO];
}
- (void)windowDidResignKey:(NSNotification *)notification {
if ([[self window] isVisible]) {
[self setHasActivePanel:NO];
}
}
- (void)windowDidResize:(NSNotification *)notification {
NSWindow *panel = [self window];
NSRect statusRect = [self statusRectForWindow:panel];
NSRect panelRect = [panel frame];
CGFloat statusX = roundf(NSMidX(statusRect));
CGFloat panelX = statusX - NSMinX(panelRect);
CGFloat maxX = NSMaxX([[self backgroundView] bounds]);
CGFloat maxY = NSMaxY([[self backgroundView] bounds]);
self.backgroundView.triangle = panelX; // #Jan: why is a setter method not possible (i.e. setTriangle)
NSRect buttonRect = [[self buttonadd] frame];
buttonRect.size.width = BUTTON_SIZE;
buttonRect.size.height = buttonRect.size.width;
buttonRect.origin.x = maxX - buttonRect.size.width;// * 1.5;
buttonRect.origin.y = maxY - TRIANGLE_HEIGHT - buttonRect.size.height;// * 1.5;
[[self buttonadd] setFrame:buttonRect];
// NSRect listButtonRect = NSMakeRect(NSMinX([[self backgroundView] bounds]), buttonRect.origin.y, buttonRect.size.width, buttonRect.size.height) ;
// [[self buttonlist] setFrame:listButtonRect];
NSRect tableRect = [[self tableScrollView] frame];
tableRect.size.width = maxX;
tableRect.size.height = maxY - TRIANGLE_HEIGHT - buttonRect.size.height;
tableRect.origin.x = self.backgroundView.frame.origin.x;
tableRect.origin.y = maxY - POPUP_HEIGHT;
[[self tableScrollView] setFrame:tableRect];
}
- (void)cancelOperation:(id)sender {
[self setHasActivePanel:NO];
}
- (void)openPanel {
NSWindow *panel = [self window];
NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame];
NSRect statusRect = [self statusRectForWindow:panel];
NSRect panelRect = [panel frame];
panelRect.size.width = PANEL_WIDTH;
panelRect.origin.x = roundf(NSMidX(statusRect) - NSWidth(panelRect) / 2);
panelRect.origin.y = NSMaxY(statusRect) - NSHeight(panelRect);
[panel setAlphaValue:0];
[panel setFrame:statusRect display:YES];
[panel makeKeyAndOrderFront:nil];
NSTimeInterval openDuration = OPEN_DURATION;
// For testing
NSEvent *currentEvent = [NSApp currentEvent];
if ([currentEvent type] == NSLeftMouseDown) {
NSUInteger clearFlags = ([currentEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask); // #Jan
BOOL shiftPressed = (clearFlags == NSShiftKeyMask);
BOOL shiftOptionPressed = (clearFlags == (NSShiftKeyMask | NSAlternateKeyMask));
if (shiftPressed || shiftOptionPressed) {
openDuration *= 10;
if (shiftOptionPressed)
NSLog(#"Icon is at %#\n\tMenu is on screen %#\n\tWill be animated to %#",
NSStringFromRect(statusRect), NSStringFromRect(screenRect), NSStringFromRect(panelRect));
}
}
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:openDuration];
[[panel animator] setFrame:panelRect display:YES];
[[panel animator] setAlphaValue:1];
[NSAnimationContext endGrouping];
}
- (void)closePanel {
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:CLOSE_DURATION];
[[[self window] animator] setAlphaValue:0];
[NSAnimationContext endGrouping];
dispatch_after(dispatch_walltime(NULL, NSEC_PER_SEC * CLOSE_DURATION * 2), dispatch_get_main_queue(), ^{
[[self window] orderOut:nil];
});
}
- (NSColor*)colorForIndex:(NSInteger)index {
NSManagedObjectContext *context = [[NSApp delegate] managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Task"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error;
NSInteger itemCount = [context countForFetchRequest:fetchRequest error:&error];
float val = 0;
float brightness = 0.63;
if( itemCount < 11 )
{
val = brightness + ((0.1/10)*(index*3));
}
else
{
val = brightness + ((0.1/itemCount)*(index*(3)));
}
return [NSColor colorWithDeviceHue: 0.57
saturation: 0.67
brightness: val
alpha: 1
];
}
- (void)tableView:(NSTableView *)tableView
didAddRowView:(NSTableRowView *)rowView
forRow:(NSInteger)row {
rowView.backgroundColor = [self colorForIndex:row];
}
- (void) observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
[statusItemView setStatusContent:[object valueForKeyPath:keyPath]];
}
#end
and here's the .h file:
//
// UIController.h
// hourglass
//
// Created by Matze on 24/04/14.
// Copyright (c) 2014 hourglass. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "GlobalProperties.h"
#import "StatusItemView.h"
#import "BackgroundView.h"
#import "RFOverlayScrollView.h"
#class UIController;
#protocol UIControllerDelegate <NSObject>
#optional
- (StatusItemView *)statusItemViewForUIController:(UIController *)controller;
#end
#interface UIController : NSWindowController <NSWindowDelegate> {
IBOutlet NSTableView *TableView;
StatusItemView *statusItemView;
}
//TODO: Split Controller function for views into separate Controller Classes (i.e. BackgroundViewController)
#property (nonatomic, unsafe_unretained) IBOutlet BackgroundView *backgroundView;
#property (nonatomic, unsafe_unretained) IBOutlet RFOverlayScrollView *tableScrollView;
#property (strong) IBOutlet NSButton *buttonadd;
#property (strong) IBOutlet NSArrayController *Tasks;
#property (nonatomic) BOOL hasActivePanel;
#property (nonatomic, unsafe_unretained, readonly) id<UIControllerDelegate> delegate;
- (id) initWithDelegate:(id<UIControllerDelegate>)delegate;
- (void)openPanel;
- (void)closePanel;
- (void)deleteSelectedObjects;
- (NSColor*)colorForIndex:(NSInteger)index;
- (IBAction)buttonDelete:(id)sender;
#end
Any help is much appreciated!

Objective-C, Need help creating an AVAudioPlayer singleton

I'm working on a soundboard app, that has several pages of buttons to play sound effects with a stop button on every page should the user wish to manually interrupt the clip. I'm using avaudioplayer in each view to play the sound upon pressing the button for that clip. It works fine until the view is changed. If a user jumps to a new page the sound keeps playing and the stop button stops working even if they return to the original view. Pressing a sound button no longer interrupts the running sound resulting in two sounds over each other.
From googling and searching this site, I know the issue is that each view change creates a new instance of the player and the remedy is to create a singleton class. Unfortunately I have yet to find any further examples of how to actually do this. If someone could provide or point the way to a beginners guide for creating an avaudioplayer singleton I would really appreciate it. All I need to be able to do is pass the file name to the shared player and start play with a sound clip button and have the stop button stop sounds no matter what view the user is on. I am using the ios 5.1 sdk with storyboards and ARC enabled.
My solution, as used in one of my own projects, is posted beneath. Feel free to copy-and-paste, I intend to open-source this project once it's finished :)
A preview of the player can be seen on YouTube: http://www.youtube.com/watch?v=Q98DQ6iNTYM
AudioPlayer.h
#protocol AudioPlayerDelegate;
#interface AudioPlayer : NSObject
#property (nonatomic, assign, readonly) BOOL isPlaying;
#property (nonatomic, assign) id <AudioPlayerDelegate> delegate;
+ (AudioPlayer *)sharedAudioPlayer;
- (void)playAudioAtURL:(NSURL *)URL;
- (void)play;
- (void)pause;
#end
#protocol AudioPlayerDelegate <NSObject>
#optional
- (void)audioPlayerDidStartPlaying;
- (void)audioPlayerDidStartBuffering;
- (void)audioPlayerDidPause;
- (void)audioPlayerDidFinishPlaying;
#end
AudioPlayer.m
// import AVPlayer.h & AVPlayerItem.h
#interface AudioPlayer ()
- (void)playerItemDidFinishPlaying:(id)sender;
#end
#implementation AudioPlayer
{
AVPlayer *player;
}
#synthesize isPlaying, delegate;
+ (AudioPlayer *)sharedAudioPlayer
{
static dispatch_once_t pred;
static AudioPlayer *sharedAudioPlayer = nil;
dispatch_once(&pred, ^
{
sharedAudioPlayer = [[self alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:sharedAudioPlayer selector:#selector(playerItemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
});
return sharedAudioPlayer;
}
- (void)playAudioAtURL:(NSURL *)URL
{
if (player)
{
[player removeObserver:self forKeyPath:#"status"];
[player pause];
}
player = [AVPlayer playerWithURL:URL];
[player addObserver:self forKeyPath:#"status" options:0 context:nil];
if (delegate && [delegate respondsToSelector:#selector(audioPlayerDidStartBuffering)])
[delegate audioPlayerDidStartBuffering];
}
- (void)play
{
if (player)
{
[player play];
if (delegate && [delegate respondsToSelector:#selector(audioPlayerDidStartPlaying)])
[delegate audioPlayerDidStartPlaying];
}
}
- (void)pause
{
if (player)
{
[player pause];
if (delegate && [delegate respondsToSelector:#selector(audioPlayerDidPause)])
[delegate audioPlayerDidPause];
}
}
- (BOOL)isPlaying
{
DLog(#"%f", player.rate);
return (player.rate > 0);
}
#pragma mark - AV player
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == player && [keyPath isEqualToString:#"status"])
{
if (player.status == AVPlayerStatusReadyToPlay)
{
[self play];
}
}
}
#pragma mark - Private methods
- (void)playerItemDidFinishPlaying:(id)sender
{
DLog(#"%#", sender);
if (delegate && [delegate respondsToSelector:#selector(audioPlayerDidFinishPlaying)])
[delegate audioPlayerDidFinishPlaying];
}
#end
AudioPlayerViewController.h
extern NSString *const kAudioPlayerWillShowNotification;
extern NSString *const kAudioPlayerWillHideNotification;
#interface AudioPlayerViewController : UIViewController
#property (nonatomic, assign, readonly) BOOL isPlaying;
#property (nonatomic, assign, readonly) BOOL isPlayerVisible;
- (void)playAudioAtURL:(NSURL *)URL withTitle:(NSString *)title;
- (void)pause;
#end
AudioPlayerViewController.m
NSString *const kAudioPlayerWillShowNotification = #"kAudioPlayerWillShowNotification";
NSString *const kAudioPlayerWillHideNotification = #"kAudioPlayerWillHideNotification";
#interface AudioPlayerViewController () <AudioPlayerDelegate>
#property (nonatomic, strong) AudioPlayerView *playerView;
- (void)playButtonTouched:(id)sender;
- (void)closeButtonTouched:(id)sender;
- (void)hidePlayer;
#end
#implementation AudioPlayerViewController
#synthesize playerView, isPlaying, isPlayerVisible;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
playerView = [[AudioPlayerView alloc] initWithFrame:CGRectZero];
[AudioPlayer sharedAudioPlayer].delegate = self;
}
return self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
self.view = playerView;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
[playerView.playButton addTarget:self action:#selector(playButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
[playerView.closeButton addTarget:self action:#selector(closeButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Private methods
- (AudioPlayerView *)playerView
{
return (AudioPlayerView *)self.view;
}
- (void)hidePlayer
{
[[NSNotificationCenter defaultCenter] postNotificationName:kAudioPlayerWillHideNotification object:nil];
[self.playerView hidePlayer];
}
- (void)playButtonTouched:(id)sender
{
DLog(#"play / pause");
if ([AudioPlayer sharedAudioPlayer].isPlaying)
{
[[AudioPlayer sharedAudioPlayer] pause];
}
else
{
[[AudioPlayer sharedAudioPlayer] play];
}
[self.playerView showPlayer];
}
- (void)closeButtonTouched:(id)sender
{
DLog(#"close");
if ([AudioPlayer sharedAudioPlayer].isPlaying)
[[AudioPlayer sharedAudioPlayer] pause];
[self hidePlayer];
}
#pragma mark - Instance methods
- (void)playAudioAtURL:(NSURL *)URL withTitle:(NSString *)title
{
playerView.titleLabel.text = title;
[[AudioPlayer sharedAudioPlayer] playAudioAtURL:URL];
[[NSNotificationCenter defaultCenter] postNotificationName:kAudioPlayerWillShowNotification object:nil];
[playerView showPlayer];
}
- (void)pause
{
[[AudioPlayer sharedAudioPlayer] pause];
[[NSNotificationCenter defaultCenter] postNotificationName:kAudioPlayerWillHideNotification object:nil];
[playerView hidePlayer];
}
#pragma mark - Audio player delegate
- (void)audioPlayerDidStartPlaying
{
DLog(#"did start playing");
playerView.playButtonStyle = PlayButtonStylePause;
}
- (void)audioPlayerDidStartBuffering
{
DLog(#"did start buffering");
playerView.playButtonStyle = PlayButtonStyleActivity;
}
- (void)audioPlayerDidPause
{
DLog(#"did pause");
playerView.playButtonStyle = PlayButtonStylePlay;
}
- (void)audioPlayerDidFinishPlaying
{
[self hidePlayer];
}
#pragma mark - Properties
- (BOOL)isPlaying
{
return [AudioPlayer sharedAudioPlayer].isPlaying;
}
- (BOOL)isPlayerVisible
{
return !playerView.isPlayerHidden;
}
#end
AudioPlayerView.h
typedef enum
{
PlayButtonStylePlay = 0,
PlayButtonStylePause,
PlayButtonStyleActivity,
} PlayButtonStyle;
#interface AudioPlayerView : UIView
#property (nonatomic, strong) UIButton *playButton;
#property (nonatomic, strong) UIButton *closeButton;
#property (nonatomic, strong) UILabel *titleLabel;
#property (nonatomic, strong) UIActivityIndicatorView *activityView;
#property (nonatomic, assign) PlayButtonStyle playButtonStyle;
#property (nonatomic, assign, readonly) BOOL isPlayerHidden;
- (void)showPlayer;
- (void)hidePlayer;
#end
AudioPlayerView.m
#implementation AudioPlayerView
{
BOOL _isAnimating;
}
#synthesize playButton, closeButton, titleLabel, playButtonStyle, activityView, isPlayerHidden = _playerHidden;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"musicplayer_background.png"]];
_playerHidden = YES;
activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityView.frame = CGRectMake(0.0f, 0.0f, 30.0f, 30.0f);
[self addSubview:activityView];
playButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 30.0f, 30.0f)];
[playButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[playButton setBackgroundImage:[UIImage imageNamed:#"button_pause.png"] forState:UIControlStateNormal];
playButton.titleLabel.textAlignment = UITextAlignmentCenter;
[self addSubview:playButton];
closeButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 30.0f, 30.0f)];
[closeButton setBackgroundImage:[UIImage imageNamed:#"button_close.png"] forState:UIControlStateNormal];
[closeButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
closeButton.titleLabel.textAlignment = UITextAlignmentCenter;
[self addSubview:closeButton];
titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 240.0f, 30.0f)];
titleLabel.text = nil;
titleLabel.textAlignment = UITextAlignmentCenter;
titleLabel.font = [UIFont boldSystemFontOfSize:13.0f];
titleLabel.numberOfLines = 2;
titleLabel.textColor = [UIColor whiteColor];
titleLabel.backgroundColor = [UIColor clearColor];
[self addSubview:titleLabel];
}
return self;
}
- (void)layoutSubviews
{
#define PADDING 5.0f
DLog(#"%#", NSStringFromCGRect(self.bounds));
CGRect frame = self.bounds;
CGFloat y = frame.size.height / 2;
titleLabel.center = CGPointMake(frame.size.width / 2, y);
CGFloat x = titleLabel.frame.origin.x - (playButton.frame.size.width / 2) - PADDING;
playButton.center = CGPointMake(x, y);
activityView.center = CGPointMake(x, y);
x = titleLabel.frame.origin.x + titleLabel.frame.size.width + (closeButton.frame.size.width / 2) + PADDING;
closeButton.center = CGPointMake(x, y);
}
#pragma mark - Instance methods
- (void)showPlayer
{
if (_isAnimating || _playerHidden == NO)
return;
_isAnimating = YES;
[UIView
animateWithDuration:0.5f
animations:^
{
CGRect frame = self.frame;
frame.origin.y -= 40.0f;
self.frame = frame;
}
completion:^ (BOOL finished)
{
_isAnimating = NO;
_playerHidden = NO;
}];
}
- (void)hidePlayer
{
if (_isAnimating || _playerHidden)
return;
_isAnimating = YES;
[UIView
animateWithDuration:0.5f
animations:^
{
CGRect frame = self.frame;
frame.origin.y += 40.0f;
self.frame = frame;
}
completion:^ (BOOL finished)
{
_isAnimating = NO;
_playerHidden = YES;
}];
}
- (void)setPlayButtonStyle:(PlayButtonStyle)style
{
playButton.hidden = (style == PlayButtonStyleActivity);
activityView.hidden = (style != PlayButtonStyleActivity);
switch (style)
{
case PlayButtonStyleActivity:
{
[activityView startAnimating];
}
break;
case PlayButtonStylePause:
{
[activityView stopAnimating];
[playButton setBackgroundImage:[UIImage imageNamed:#"button_pause.png"] forState:UIControlStateNormal];
}
break;
case PlayButtonStylePlay:
default:
{
[activityView stopAnimating];
[playButton setBackgroundImage:[UIImage imageNamed:#"button_play.png"] forState:UIControlStateNormal];
}
break;
}
[self setNeedsLayout];
}
#end
AppDelegate - didFinishLaunching
// setup audio player
audioPlayer = [[AudioPlayerViewController alloc] init]; // public property ...
CGRect frame = self.window.rootViewController.view.frame;
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
CGFloat tabBarHeight = tabBarController.tabBar.frame.size.height;
audioPlayer.view.frame = CGRectMake(0.0f, frame.size.height - tabBarHeight, 320.0f, 40.0f);
[self.window.rootViewController.view insertSubview:audioPlayer.view belowSubview:tabBarController.tabBar];
From any view controller inside the app I start audio with the following code:
- (void)playAudioWithURL:(NSURL *)URL title:(NSString *)title
{
OnsNieuwsAppDelegate *appDelegate = (OnsNieuwsAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.audioPlayer playAudioAtURL:URL withTitle:title];
}
Assets
For the above example, the following assets can be used (button images are white, so hard to see against background):
Buttons:
Background:
There's a lot of discussion (and links to blogs, etc.) about singletons over at What should my Objective-C singleton look like?, and I see a fair number of tutorials as a result of this Google search: http://www.google.com/search?q=+cocoa+touch+singleton+tutorial, but the real answer to your question, I believe, is that you should do one of two things:
If you do want the sound for a particular view to continue playing when the user switches, create the player as you're doing now, but when the view (re)appears, check that a player exists, and don't make a new one.
If you want the sound to stop, then stop the sound when the view changes (i.e., in viewWillDisappear:).

UIView, UIScrollView and UITextFields problem calling Method

I have a view with several embedded UITextFields, this UIView is subordinated to a UIScrollView in IB. Each text field is supposed to invoke a method called updateText defined in the viewcontroller implementation file when the user is done editing the field. For some reason, the method updateText never gets invoked. Anyone have any ideas how to go about fixing this? The method fired off just fine when the UIScrollView was not present in the project but the keyboard would cover the text fields during input, which was annoying. Now my textfields move up above the keyboard when it appears, but won't fire off the method when done editing.
Here is my implementation file:
#import "MileMarkerViewController.h"
#implementation MileMarkerViewController
#synthesize scrollView,milemarkerLogDate,milemarkerDesc,milemarkerOdobeg,milemarkerOdoend,milemarkerBusiness,milemarkerPersonal,milemarker;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Initialization code
}
return self;
}
- (BOOL) textFieldShouldReturn: (UITextField*) theTextField {
return [theTextField resignFirstResponder];
}
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(keyboardWasShown:)
name: UIKeyboardDidShowNotification
object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(keyboardWasHidden:)
name: UIKeyboardDidHideNotification
object: nil];
keyboardShown = NO; // 1
[scrollView setContentSize: CGSizeMake( 320, 480)]; // 2
}
- (void)keyboardWasShown:(NSNotification*)aNotification {
if (keyboardShown) return;
NSDictionary* info = [aNotification userInfo];
// Get the size of the keyboard.
NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;
// Resize the scroll view (which is the root view of the window)
CGRect viewFrame = [scrollView frame];
viewFrame.size.height -= keyboardSize.height;
scrollView.frame = viewFrame;
// Scroll the active text field into view.
CGRect textFieldRect = [activeField frame];
[scrollView scrollRectToVisible:textFieldRect animated:YES];
keyboardShown = YES;
}
- (void)keyboardWasHidden:(NSNotification*)aNotification {
NSDictionary* info = [aNotification userInfo];
// Get the size of the keyboard.
NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;
// Reset the height of the scroll view to its original value
CGRect viewFrame = [scrollView frame];
viewFrame.size.height += keyboardSize.height;
[scrollView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
scrollView.frame = viewFrame;
keyboardShown = NO;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
activeField = textField;
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
activeField = nil;
}
- (IBAction)updateText:(id) sender {
NSLog(#"You just entered: %#",self.milemarkerLogDate.text);
self.milemarker.logdate = self.milemarkerLogDate.text;
self.milemarker.desc = self.milemarkerDesc.text;
self.milemarker.odobeg = self.milemarkerOdobeg.text;
self.milemarker.odoend = self.milemarkerOdoend.text;
self.milemarker.business = self.milemarkerBusiness.text;
self.milemarker.personal = self.milemarkerPersonal.text;
NSLog(#"Original textfield is set to: %#",self.milemarker.logdate);
[self.milemarker updateText];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)dealloc {
[super dealloc];
}
#end
I think you have already known a solution because of post date.
You can implement textFieldShouldReturn method and resign first responder from textField in the method.
textFieldDidEndEditing is called after textField resign first responder.

UITextField Example in Cocos2d

Can anyone please suggest some links for using UITextField in cocos2d.
I want to press on label, then the UITextField should get selected and I need to edit on that UITextField.
I'm doing this in a current project to allow for entering the number of the level to start playing at, so that's why my variables and methods are named the way they are; you should probably adjust these to make sense for you.
In your app controller, define this as an instance variable:
UITextField *levelEntryTextField;
Create it inside applicationDidFinishLaunching:
levelEntryTextField = [[UITextField alloc] initWithFrame:
CGRectMake(60, 165, 200, 90)];
[levelEntryTextField setDelegate:self];
Define a method to activate the text field. You should also declare it in the header file for your app controller.
- (void)specifyStartLevel
{
[levelEntryTextField setText:#""];
[window addSubview:levelEntryTextField];
[levelEntryTextField becomeFirstResponder];
}
This will make pressing "return" on the keypad end editing
- (BOOL)textFieldShouldReturn:(UITextField*)textField {
//Terminate editing
[textField resignFirstResponder];
return YES;
}
This is triggered when the editing is actually done.
- (void)textFieldDidEndEditing:(UITextField*)textField {
if (textField==levelEntryTextField) {
[levelEntryTextField endEditing:YES];
[levelEntryTextField removeFromSuperview];
// here is where you should do something with the data they entered
NSString *result = levelEntryTextField.text;
}
}
Now to actually set things in motion, you put this somewhere. I call this from within one of my Scene classes, in response to a user action:
[[[UIApplication sharedApplication] delegate] specifyStartLevel];
I took the example that Jack provided and actually created a working project, this was done using the Cocos2D 0.7.1 XCode Template, and then just editting the *AppDelegate.m/.h files, which are provided below in there entirety. I also modified some of what Jack said, because I feel that creating the UITextField in the appDidFinishLoading would utilize a bit too much memory, especially if the text field is not used all the time ... this solution creates the text field only when it is needed, the sample draws an empty Cocos2D Layer scene, and on screen touch, it displays the text field for you to start entering text into. It will spit out the result of what you entered to the Console - you can pass this to whatever is necessary in your own code.
the .h
#import <UIKit/UIKit.h>
#import "cocos2d.h"
#interface MYSCENE : Layer <UITextFieldDelegate>
{
UITextField *myText;
}
-(void)specificStartLevel;
#end
#interface textFieldTestAppDelegate : NSObject <UIAccelerometerDelegate, UIAlertViewDelegate, UITextFieldDelegate, UIApplicationDelegate>
{
UIWindow *window;
}
#end
and then the .m
#import "textFieldTestAppDelegate.h"
#implementation MYSCENE
-(id) init
{
self = [super init];
isTouchEnabled = YES;
return self;
}
-(BOOL)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self specifyStartLevel];
return kEventHandled;
}
-(void)specifyStartLevel {
myText = [[UITextField alloc] initWithFrame:CGRectMake(60, 165, 200, 90)];
[myText setDelegate:self];
[myText setText:#""];
[myText setTextColor: [UIColor colorWithRed:255 green:255 blue:255 alpha:1.0]];
[[[[Director sharedDirector] openGLView] window] addSubview:myText];
[myText becomeFirstResponder];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
[myText resignFirstResponder];
return YES;
}
-(void)textFieldDidEndEditing: (UITextField *)textField {
if(textField == myText) {
[myText endEditing:YES];
[myText removeFromSuperview];
NSString *result = myText.text;
NSLog([NSString stringWithFormat:#"entered: %#", result]);
} else {
NSLog(#"textField did not match myText");
}
}
-(void) dealloc
{
[super dealloc];
}
#end
#implementation textFieldTestAppDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[window setUserInteractionEnabled:YES];
[[Director sharedDirector] setDisplayFPS:YES];
[[Director sharedDirector] attachInWindow:window];
Scene *scene = [Scene node];
[scene addChild: [MYSCENE node]];
[window makeKeyAndVisible];
[[Director sharedDirector] runWithScene: scene];
}
-(void)dealloc
{
[super dealloc];
}
-(void) applicationWillResignActive:(UIApplication *)application
{
[[Director sharedDirector] pause];
}
-(void) applicationDidBecomeActive:(UIApplication *)application
{
[[Director sharedDirector] resume];
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
[[TextureMgr sharedTextureMgr] removeAllTextures];
}
#end
To add Text field in cocos2d as below code
first of all you add view in Scene and afetr add textfield add in view thats very easy.
-(id) init
{
if( (self=[super init]) )
{
// add view in scene
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 568)];
view.backgroundColor = [UIColor redColor];
// add textfield in view
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 140, 300, 30)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.font = [UIFont systemFontOfSize:15];
textField.placeholder = #"enter text";
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.keyboardType = UIKeyboardTypeDefault;
textField.returnKeyType = UIReturnKeyDone;
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.delegate = self;
[view addSubview:textField];
// add view in scene
[[[CCDirector sharedDirector] view] addSubview:view];
}
return self;
}
you can also use CCTextfield in cocos2d best example is https://github.com/iNinja/CCTextField
Try the following CCNode subclass, CCMenuItemTextField, to use text fields in cocos2d.
The class is directly subclassed from CCMenuItemSprite. When tapped, the "selected" method is called and a UITextField is added to the main window. After editing is done, "unselected" method is called and the UITextField is removed from screen. User's input is saved to a CCLabelTTF node, which position itself exactly as the original UITextField.
CCMenuItemTextField.h
#interface CCMenuItemTextField : CCMenuItemSprite<UITextFieldDelegate> {
UITextField *textField_;
CCLabelTTF *label_;
CGFloat paddingLeft_;
}
#property (readonly, nonatomic) UITextField *textField;
#property (readonly, nonatomic) CCLabelTTF *label;
#property (assign, nonatomic) CGFloat paddingLeft;
- (void)selected;
- (void)unselected;
- (void)setFontSize:(CGFloat)size;
- (NSString*)text;
- (void)setText:(NSString*)text;
#end
CCMenuItemTextField.m
#import "CCMenuItemTextField.h"
#implementation CCMenuItemTextField
#synthesize
textField = textField_,
label = label_,
paddingLeft = paddingLeft_;
- (id)init
{
CCSprite *normalSprite = [CCSprite spriteWithFile:#"text_field_background.png"];
CCSprite *selectedSprite = [CCSprite spriteWithFile:#"text_field_background.png"];
CCSprite *disabledSprite = [CCSprite spriteWithFile:#"text_field_background.png"];
return [self initWithNormalSprite:normalSprite selectedSprite:selectedSprite disabledSprite:disabledSprite];
}
- (id)initWithNormalSprite:(CCNode<CCRGBAProtocol> *)normalSprite
selectedSprite:(CCNode<CCRGBAProtocol> *)selectedSprite
disabledSprite:(CCNode<CCRGBAProtocol> *)disabledSprite
{
self = [super initWithNormalSprite:normalSprite
selectedSprite:selectedSprite
disabledSprite:disabledSprite
target:self
selector:#selector(selected)];
if (self) {
paddingLeft_ = 3.0;
textField_ = [[UITextField alloc] init];
[textField_ setTextColor:[UIColor blackColor]];
[textField_ setFont:[UIFont systemFontOfSize:18]];
label_ = [[CCLabelTTF node] retain];
[label_ setAnchorPoint:ccp(0,0.5)];
[label_ setFontSize:18];
[label_ setVisible:NO];
[label_ setColor:ccBLACK];
[self addChild:label_];
}
return self;
}
- (void)dealloc
{
[label_ release];
[textField_ release];
[super dealloc];
}
// --------------------------------
// Public
// --------------------------------
- (void)selected
{
[super selected];
[label_ setVisible:NO];
CGAffineTransform transform = [self nodeToWorldTransform];
float textFieldHeight = textField_.font.lineHeight;
float width = self.contentSize.width;
float height = self.contentSize.height;
float left = transform.tx + paddingLeft_;
float top = 480 - transform.ty - height + (height - textFieldHeight) / 2;
[textField_ setFrame:CGRectMake(left, top, width, height)];
[[[[CCDirector sharedDirector] view] window] addSubview:textField_];
[textField_ becomeFirstResponder];
[textField_ setDelegate:self];
}
- (void)unselected
{
[super unselected];
[label_ setVisible:YES];
[label_ setPosition:ccp(paddingLeft_, self.contentSize.height/2)];
NSString *text = textField_.text ? textField_.text : #"";
[label_ setString:text];
[textField_ resignFirstResponder];
[textField_ removeFromSuperview];
}
- (NSString*)text
{
return [label_ string];
}
- (void)setText:(NSString*)text
{
[label_ setString:text];
[textField_ setText:text];
}
// --------------------------------
// UITextFieldDelegate
// --------------------------------
- (BOOL)textFieldShouldReturn:(UITextField*)textField {
[self unselected];
return YES;
}
- (void)textFieldDidEndEditing:(UITextField*)textField {
[self unselected];
}
- (void)setFontSize:(CGFloat)size
{
[label_ setFontSize:size];
[textField_ setFont:[UIFont systemFontOfSize:size]];
}
// --------------------------------
// CCNode
// --------------------------------
- (void)onExitTransitionDidStart
{
[super onExitTransitionDidStart];
[self unselected];
}
#end