MKpolyline not visible at MKMapKit - mkmapview

I have a problem with my MKPolyline.
I have added this code but I see no line. I get the coordinates form a webserver with a http-request. I save the coordinates as a double and show with that my annotations.
in the viewcontroller.h
#property (nonatomic, retain) MKPolyline *routeLine;
#property (nonatomic, retain) MKPolylineView *routeLineView;
in the viewcontroller.m
CLLocationCoordinate2D coordinateArray[7];
coordinateArray[0] = CLLocationCoordinate2DMake(theCoordinate0.latitude, theCoordinate0.longitude);
coordinateArray[1] = CLLocationCoordinate2DMake(theCoordinate1.latitude, theCoordinate1.longitude);
coordinateArray[2] = CLLocationCoordinate2DMake(theCoordinate2.latitude, theCoordinate2.longitude);
coordinateArray[3] = CLLocationCoordinate2DMake(theCoordinate3.latitude, theCoordinate3.longitude);
coordinateArray[4] = CLLocationCoordinate2DMake(theCoordinate4.latitude, theCoordinate4.longitude);
coordinateArray[5] = CLLocationCoordinate2DMake(theCoordinate5.latitude, theCoordinate5.longitude);
coordinateArray[6] = CLLocationCoordinate2DMake(theCoordinate6.latitude, theCoordinate6.longitude);
self.routeLine = [MKPolyline polylineWithCoordinates:coordinateArray count:7];
[self.mapView setVisibleMapRect:[self.routeLine boundingMapRect]]; //If you want the route to be visible
[self.mapView addOverlay:self.routeLine];
-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
if(overlay == self.routeLine)
{
if(nil == self.routeLineView)
{
self.routeLineView = [[[MKPolylineView alloc] initWithPolyline:self.routeLine]autorelease];
self.routeLineView.fillColor = [UIColor redColor];
self.routeLineView.strokeColor = [UIColor redColor];
self.routeLineView.lineWidth = 10;
}
return self.routeLineView;
}
return nil;
}

Have you verified that your mapview is connected to the mapview on screen (the IBOutlet in Interface Builder)? the next thing to check is that you've set the delegate. Check this by putting a breakpoint or a debug statement in the viewForOverlay function.
P.S. with that code you're only ever going to be able to draw one line. It relies on self.routeLine and self.routeLineView and you only have one of each of those.

Related

How to record perfect loops in iOS and Xcode

I've been struggling with this for about a year now trying to pin down my problem and represent it for others to see.
I've been writing an app that depends on 'GarageBand' like recording. That is, I want to record the user for exactly 8 beats, and then I want them to be able to loop this. I am playing a metronome for the user at the same time (User would be wearing head phones hearing the metronome, recording into the mic on their device)
I can manage to turn on recording for about 4.8 seconds (.6*8 beats), and the timer says it ran for 4.8 seconds, however my audio recording is always a bit shorter than 4.8. It's like 4.78, or 4.71 which causes a the loop to go out of whack.
I've experimented with AVAudioRecorder,AudioQueue, and AudioUnits thinking one the latter methods might result in solving my problem.
I am using NSTimer to fire off every .6 seconds playing a short blip for the metronome. After 4 beats, the metronome timer's function, turns on the recorder metronnome which waits for 4.6 seconds the stops recording.
I'm using time intervals to time how long the metro runs (looks pretty tight at 4.800xxx) and comparing this to the duration of the audio file which is always different.
I wish I could attach my project, but I guess I'll just have to settle with attaching my header and implementation. To test you'll have to make a project with the following IB characteristics:
Record, Play, Stop buttons
Song/Track duration label
Timer duration label
Debug label
If you launch the app, then hit record, you are 'counted in' with 4 beats, then the recorder starts. Tap your finger on the desk until the recorder stops. After 8 more beats (12 in total) the recorder stops.
You can see in the displays that the recorded track is a little shorter than 4.8 seconds, and in some cases, a lot shorter, causing the audio to not loop properly.
Does anyone know what I can do to tighten this up? Thanks for reading.
Here's my code:
//
// ViewController.h
// speakagain
//
// Created by NOTHING on 2014-03-18.
//
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "CoreAudio/CoreAudioTypes.h"
#import <AudioToolbox/AudioQueue.h>
#import <AudioToolbox/AudioFile.h>
#import <AVFoundation/AVFoundation.h>
#interface ViewController : UIViewController
{
IBOutlet UIButton *btnRecord;
IBOutlet UIButton *btnPlay;
IBOutlet UIButton *btnStop;
IBOutlet UILabel *debugLabel;
IBOutlet UILabel *timerDuration;
IBOutlet UILabel *songDuration;
//UILabel *labelDebug;
struct AQRecorderState {
AudioStreamBasicDescription mDataFormat;
AudioQueueRef mQueue;
AudioQueueBufferRef mBuffers[kNumberBuffers];
AudioFileID mAudioFile;
UInt32 bufferByteSize;
SInt64 mCurrentPacket;
bool mIsRunning; // 8
};
struct AQRecorderState aqData;
AVAudioPlayer *audioPlayer;
NSString *songName;
NSTimer *recordTimer;
NSTimer *metroTimer;
NSTimeInterval startTime, endTime, elapsedTime;
int inputBuffer;
int beatNumber;
}
#property (nonatomic, retain) IBOutlet UIButton *btnRecord;
#property (nonatomic, retain) IBOutlet UIButton *btnPlay;
#property (nonatomic, retain) IBOutlet UIButton *btnStop;
#property (nonatomic, retain) IBOutlet UILabel *debugLabel;
#property (nonatomic, retain) IBOutlet UILabel *timerDuration;
#property (nonatomic, retain) IBOutlet UILabel *songDuration;
- (IBAction) record;
- (IBAction) stop;
- (IBAction) play;
static void HandleInputBuffer (void *aqData,AudioQueueRef inAQ,AudioQueueBufferRef inBuffer,const AudioTimeStamp *inStartTime, UInt32 inNumPackets,const AudioStreamPacketDescription *inPacketDesc);
#end
Implementation:
//
// ViewController.m
// speakagain
//
// Created by NOTHING on 2014-03-18.
//
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize btnPlay, btnRecord,btnStop,songDuration, timerDuration, debugLabel;
- (void)viewDidLoad
{
debugLabel.text = #"";
songName =[[NSString alloc ]init];
//NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//NSString *documentsDirectory = [paths objectAtIndex:0];
songName = #"TestingQueue.caf";
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)prepareAudioQueue
{
//struct AQRecorderState *pAqData;
inputBuffer=0;
aqData.mDataFormat.mFormatID = kAudioFormatLinearPCM;
aqData.mDataFormat.mSampleRate = 44100.0;
aqData.mDataFormat.mChannelsPerFrame = 1;
aqData.mDataFormat.mBitsPerChannel = 16;
aqData.mDataFormat.mBytesPerPacket =
aqData.mDataFormat.mBytesPerFrame = aqData.mDataFormat.mChannelsPerFrame * sizeof (SInt16);
aqData.mDataFormat.mFramesPerPacket = 1;
// AudioFileTypeID fileType = kAudioFileAIFFType;
AudioFileTypeID fileType = kAudioFileCAFType;
aqData.mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian| kLinearPCMFormatFlagIsSignedInteger| kLinearPCMFormatFlagIsPacked;
AudioQueueNewInput (&aqData.mDataFormat,HandleInputBuffer, &aqData,NULL, kCFRunLoopCommonModes, 0,&aqData.mQueue);
UInt32 dataFormatSize = sizeof (aqData.mDataFormat);
// in Mac OS X, instead use
// kAudioConverterCurrentInputStreamDescription
AudioQueueGetProperty (aqData.mQueue,kAudioQueueProperty_StreamDescription,&aqData.mDataFormat,&dataFormatSize);
//Verify
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *txtPath = [documentsDirectory stringByAppendingPathComponent:songName];
NSLog(#"INITIALIZING FILE");
if ([fileManager fileExistsAtPath:txtPath] == YES) {
NSLog(#"PREVIOUS FILE REMOVED");
[fileManager removeItemAtPath:txtPath error:nil];
}
const char *filePath = [txtPath UTF8String];
CFURLRef audioFileURL = CFURLCreateFromFileSystemRepresentation ( NULL,(const UInt8 *) filePath,strlen (filePath),false );
AudioFileCreateWithURL (audioFileURL,fileType,&aqData.mDataFormat, kAudioFileFlags_EraseFile,&aqData.mAudioFile );
DeriveBufferSize (aqData.mQueue,aqData.mDataFormat,0.5,&aqData.bufferByteSize);
for (int i = 0; i < kNumberBuffers; ++i)
{
AudioQueueAllocateBuffer (aqData.mQueue,aqData.bufferByteSize,&aqData.mBuffers[i]);
AudioQueueEnqueueBuffer (aqData.mQueue,aqData.mBuffers[i], 0,NULL );
}
}
- (void) metronomeFire
{
if(beatNumber < 5)
{
//count in time.
// just play the metro beep but don't start recording
debugLabel.text = #"count in (1,2,3,4)";
[self playSound];
}
if(beatNumber == 5)
{
//start recording
aqData.mCurrentPacket = 0;
aqData.mIsRunning = true;
startTime = [NSDate timeIntervalSinceReferenceDate];
recordTimer = [NSTimer scheduledTimerWithTimeInterval:4.8 target:self selector:#selector(killTimer) userInfo:nil repeats:NO];
AudioQueueStart (aqData.mQueue,NULL);
debugLabel.text = #"Recording for 8 beats (1,2,3,4 1,2,3,4)";
[self playSound];
}
else if (beatNumber < 12)
{ //play metronome from beats 6-16
[self playSound];
}
if(beatNumber == 12)
{
[metroTimer invalidate]; metroTimer = nil;
[self playSound];
}
beatNumber++;
}
- (IBAction) play
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *txtPath = [documentsDirectory stringByAppendingPathComponent:songName];
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#",txtPath]];
if (audioPlayer)
{
[audioPlayer stop];
audioPlayer = nil;
}
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if (audioPlayer == nil)
{
NSLog(#"%#",[error description]);
}
else
{
[audioPlayer play];
[audioPlayer setNumberOfLoops:-1];
}
}
- (void) killTimer
{
//this is the timer function. Runs once after 4.8 seconds.
[self stop];
}
- (IBAction) stop
{
if (audioPlayer)
{
[audioPlayer stop];
audioPlayer = nil;
}
else
{
if(metroTimer)
{
[metroTimer invalidate];metroTimer = nil;
}
//Stop the audio queue
AudioQueueStop (aqData.mQueue,true);
aqData.mIsRunning = false;
AudioQueueDispose (aqData.mQueue,true);
AudioFileClose (aqData.mAudioFile);
//Get elapsed time of timer
endTime = [NSDate timeIntervalSinceReferenceDate];
elapsedTime = endTime - startTime;
//Get elapsed time of audio file
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
songName,
nil];
NSURL *audioFileURL = [NSURL fileURLWithPathComponents:pathComponents];
AVURLAsset* audioAsset = [AVURLAsset URLAssetWithURL:audioFileURL options:nil];
CMTime audioDuration = audioAsset.duration;
float audioDurationSeconds = CMTimeGetSeconds(audioDuration);
//Log values
NSLog(#"Track Duration: %f",audioDurationSeconds);
NSLog(#"Timer Duration: %.6f", elapsedTime);
//Show values on GUI too
songDuration.text = [NSString stringWithFormat: #"Track Duration: %f",audioDurationSeconds];
timerDuration.text = [NSString stringWithFormat:#"Timer Duration: %#",[NSString stringWithFormat: #"%.6f", elapsedTime]];
debugLabel.text = #"Why is the duration of the track less than the duration the timer ran?";
}
}
-(void) playSound
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"blip2" ofType:#"aif"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:path], &soundID);
AudioServicesPlaySystemSound (soundID);
}
- (IBAction) record
{
[self prepareAudioQueue];
songDuration.text = #"";
timerDuration.text = #"";
//debugLabel.text = #"Please wait 12 beats (The first four are count in)";
//init beat number
beatNumber = 1;
//safe guard
if(aqData.mIsRunning)
{
AudioQueueStop (aqData.mQueue,true);
aqData.mIsRunning = false;
AudioQueueDispose (aqData.mQueue,true);
AudioFileClose (aqData.mAudioFile);
}
//start count in (metro will start recording)
//aqData.mCurrentPacket = 0;
//aqData.mIsRunning = true;
startTime = [NSDate timeIntervalSinceReferenceDate];
metroTimer = [NSTimer scheduledTimerWithTimeInterval:.6 target:self selector:#selector(metronomeFire) userInfo:nil repeats:YES];
//recordTimer = [NSTimer scheduledTimerWithTimeInterval:4.8 target:self selector:#selector(killTimer) userInfo:nil repeats:NO];
//AudioQueueStart (aqData.mQueue,NULL);
}
static void HandleInputBuffer (void *aqData,AudioQueueRef inAQ,AudioQueueBufferRef inBuffer,const AudioTimeStamp *inStartTime,UInt32 inNumPackets,const AudioStreamPacketDescription *inPacketDesc)
{
//boiler plate
NSLog(#"HandleInputBuffer");
struct AQRecorderState *pAqData = (struct AQRecorderState *) aqData;
if (inNumPackets == 0 && pAqData->mDataFormat.mBytesPerPacket != 0)
inNumPackets = inBuffer->mAudioDataByteSize / pAqData->mDataFormat.mBytesPerPacket;
if (AudioFileWritePackets (pAqData->mAudioFile,false,inBuffer->mAudioDataByteSize,inPacketDesc,pAqData->mCurrentPacket,&inNumPackets,inBuffer->mAudioData) == noErr)
{
pAqData->mCurrentPacket += inNumPackets;
}
if (pAqData->mIsRunning == 0)
return;
AudioQueueEnqueueBuffer (pAqData->mQueue,inBuffer,0,NULL);
}
void DeriveBufferSize(AudioQueueRef audioQueue,AudioStreamBasicDescription ASBDescription,Float64 seconds,UInt32 *outBufferSize)
{
//boiler plate
static const int maxBufferSize = 0x50000;
int maxPacketSize = ASBDescription.mBytesPerPacket;
if(maxPacketSize == 0)
{
UInt32 maxVBRPacketSize = sizeof(maxPacketSize);
AudioQueueGetProperty(audioQueue, kAudioQueueProperty_MaximumOutputPacketSize, &maxPacketSize, &maxVBRPacketSize);
NSLog(#"max buffer = %d",maxPacketSize);
}
Float64 numBytesForTime = ASBDescription.mSampleRate * maxPacketSize * seconds;
*outBufferSize = (UInt32)(numBytesForTime < maxBufferSize ? numBytesForTime : maxBufferSize);
}
OSStatus SetMagicCookieForFile (AudioQueueRef inQueue, AudioFileID inFile)
{
//boiler plate
OSStatus result = noErr;
UInt32 cookieSize;
if (AudioQueueGetPropertySize (inQueue,kAudioQueueProperty_MagicCookie,&cookieSize) == noErr)
{
char* magicCookie =(char *) malloc (cookieSize);
if (AudioQueueGetProperty (inQueue,kAudioQueueProperty_MagicCookie,magicCookie,&cookieSize) == noErr)
{
result = AudioFileSetProperty (inFile,kAudioFilePropertyMagicCookieData,cookieSize,magicCookie);
}
free (magicCookie);
}
return result;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This is a big topic so I doubt you'll get an answer big enough to re-architect the code that you've provided. However, I can give you links that will supply the vast majority of what you require.
First thing is NSTimer would never work due to synchronisation issues. Also, forget AudioQueue and AVAudioRecorder. Only AudioUnit is low level enough for your needs.
Have a look at my answer here:
iOS Stream Audio from one iOS Device to Another
But the true goldmine - and knowledge that you will need to be intimately familiar with - is Tasty Pixel's blog. Tasty Pixel being the vendor of Loopy HD, but also someone that is kind enough to share some pretty in depth knowledge.
See:
A simple, fast circular buffer implementation for audio processing
Developing Loopy, Part 2: Implementation
and
Using RemoteIO audio unit
Finally, make sure you are familiar with packets, frames, samples, etc. Everything needs to sync perfectly.

Several and different custom Pins in the same mapView

This is my question....
I have a mapView and i fill the view with several custom pins.
I would different custom pins in my mapView.
I have tried with an IF condition but don't work.
I don't understand how the called to method works.
Follow the code.
Vi allego il codice.
//Customization of my pins
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation(id<MKAnnotation>)annotation{
static NSString *identifier = #"";
MKAnnotationView *pin = [ mappa dequeueReusableAnnotationViewWithIdentifier:identifier ];
//OLD COORDINATES
if(newcoordinate == FALSE){
pin = [[[ MKAnnotationView alloc ] initWithAnnotation:annotation reuseIdentifier:identifier ]autorelease];
pin.image = [ UIImage imageNamed:#"old.png" ]
}
// NEW COORDINATES
else ( newcoordinate == TRUE){
pin = [[[ MKAnnotationView alloc ] initWithAnnotation:annotation reuseIdentifier:identifier ]autorelease];
pin.image = [ UIImage imageNamed:#"new.png" ];
}
pin.canShowCallout = YES;
//CALLOUT INFO
UIImage *image = [UIImage imageNamed:#"informations.png"];
UIImageView *imgView = [[[UIImageView alloc] initWithImage:image]autorelease];
pin.leftCalloutAccessoryView = imgView;
pin.annotation = annotation;
return pin;}
The result is... several pin in the same mapView but with the same customization.
:/
Thank you.
SOLVED.
I have added a new property in MyAnnotation class:
#interface MyAnnotation : NSObject <MKAnnotation>
{
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
BOOL isNew; // <------- My solution
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, assign) BOOL isNew ; <--------- My solution
Today i have learned what are the properties.

Having Placemark/Annotation in the center of your mapView, even if you scroll

I've spent many hours trying to figure how to do this:
Having a placemark/annotation in the centerCoordinate of your mapView, when you scroll the map, the placemark should always stays in the center.
I've seen another app doing this too!
Found my question in How to add annotation on center of map view in iPhone?
There's the answer :
If you want to use an actual annotation instead of just a regular view positioned above the center of the map view, you can:
use an annotation class with a settable coordinate property (pre-defined MKPointAnnotation class eg). This avoids having to remove and add the annotation when the center changes.
create the annotation in viewDidLoad
keep a reference to it in a property, say centerAnnotation
update its coordinate (and title, etc) in the map view's regionDidChangeAnimated delegate method (make sure map view's delegate property is set)
Example:
#interface SomeViewController : UIViewController <MKMapViewDelegate> {
MKPointAnnotation *centerAnnotation;
}
#property (nonatomic, retain) MKPointAnnotation *centerAnnotation;
#end
#implementation SomeViewController
#synthesize centerAnnotation;
- (void)viewDidLoad {
[super viewDidLoad];
MKPointAnnotation *pa = [[MKPointAnnotation alloc] init];
pa.coordinate = mapView.centerCoordinate;
pa.title = #"Map Center";
pa.subtitle = [NSString stringWithFormat:#"%f, %f", pa.coordinate.latitude, pa.coordinate.longitude];
[mapView addAnnotation:pa];
self.centerAnnotation = pa;
[pa release];
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
centerAnnotation.coordinate = mapView.centerCoordinate;
centerAnnotation.subtitle = [NSString stringWithFormat:#"%f, %f", centerAnnotation.coordinate.latitude, centerAnnotation.coordinate.longitude];
}
- (void)dealloc {
[centerAnnotation release];
[super dealloc];
}
#end
Now this will move the annotation but not smoothly. If you need the annotation to move more smoothly, you can add a UIPanGestureRecognizer and UIPinchGestureRecognizer to the map view and also update the annotation in the gesture handler:
// (Also add UIGestureRecognizerDelegate to the interface.)
// In viewDidLoad:
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
panGesture.delegate = self;
[mapView addGestureRecognizer:panGesture];
[panGesture release];
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
pinchGesture.delegate = self;
[mapView addGestureRecognizer:pinchGesture];
[pinchGesture release];
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
centerAnnotation.coordinate = mapView.centerCoordinate;
centerAnnotation.subtitle = [NSString stringWithFormat:#"%f, %f", centerAnnotation.coordinate.latitude, centerAnnotation.coordinate.longitude];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
//let the map view's and our gesture recognizers work at the same time...
return YES;
}

navigationItem not showing on popoverController

The navigationbar is failing to appear, works fine in a UITableView, but fails inside a popoverController
Initiate a popover popoverController in UIViewController
-(IBAction) btnShowMovies:(id) sender {
if (self.popoverController == nil) {
teamAController *movies =
[[teamAController alloc]
initWithNibName:#"teamAController"
bundle:[NSBundle mainBundle]];
UIPopoverController *popover =
[[UIPopoverController alloc] initWithContentViewController:movies];
popover.delegate = self;
[movies release];
self.popoverController = popover;
[popover release];
}
CGRect popoverRect = [self.view convertRect:[btn frame]
fromView:[btn superview]];
popoverRect.size.width = MIN(popoverRect.size.width, 100);
[self.popoverController
presentPopoverFromRect:popoverRect
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionDown
animated:YES];
}
teamAController.h
#interface teamAController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
UITableView *tableView;
NSArray *theArray;
}
#property (nonatomic, retain) NSArray *theArray;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
-(void) createArray;
teamAController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title= #"FooBarExtreme";
self.contentSizeForViewInPopover = CGSizeMake(250.0, 300.0);
[self createArray];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
Everything works, I have lovely table with images etc, correct sized and placed popover just no title bar..... ?
I found the solution/problem by following the tutorial at http://mobiforge.com/designing/story/using-popoverview-ipad-app-development.
Worth noting that I found this the most comprehensive one on creating uiPopoverController with uiNavigationBar elements from UIButtons.
The issue is that the popover itself belongs to the view that calls it. The content is derived from the xlib/view you load into it. But not the titlebar. You call that in the parent view view.
This code is in the main view and is called from the UIButton
// BookMarksViewController is the class that contains the code/xib for the popover's content
// Of overarching importance is creating it as a UITableViewController
if (self.popoverController == nil) {
BookMarksViewController *bookMarksViewController =
[[BookMarksViewController alloc]
initWithNibName:#"BookMarksViewController"
bundle:[NSBundle mainBundle]];
// Here's the rub: because in effect this view is controlling the popover
// we have to assign nav bar stuff here. Sigh.
bookMarksViewController.navigationItem.title = #"Territories";
UINavigationController *navController =
[[UINavigationController alloc]
initWithRootViewController:bookMarksViewController];
bookMarksViewController.contentSizeForViewInPopover = CGSizeMake(320, 400);
UIPopoverController *popover =
[[UIPopoverController alloc]
initWithContentViewController:navController];
popover.delegate = self;
[bookMarksViewController release];
[navController release];
self.popoverController = popover;
[popover release];
}
CGRect sourceRect = [self.view convertRect:[btn frame] fromView:[btn superview]];
[self.popoverController presentPopoverFromRect:sourceRect
inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];

Display datepicker on tapping on textfield

How can I display a datetimepicker control on tap of a textbox?
I have a user interface that has arrival and departure text fields, and when a user clicks on arrival textbox it should bring up a datetimepicker control up instead of a keyboard and the same with the departure textbox.
You can use inputView and inputAccessoryView properties of the text field for this. Create the date picker and set it to the input views of the two text fields. Also create another view for the Done button and it as their accessory view. You will need that button to dismiss the input view.
The Done button must be wired up to function which basically does this –
if ( [textField1 isFirstResponder] ) {
[textField1 resignFirstResponder];
} else if ( [textField2 isFirstResponder] ) {
[textField2 resignFirstResponder];
}
Another option would be to subclass UITextField and override inputView and inputAccessoryView. This is the way to go when there are loads of them.
Example
#interface CustomKeyboardAppDelegate : NSObject <UIApplicationDelegate> {
...
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITextField *textField;
#property (nonatomic, retain) IBOutlet UIToolbar *accessoryView;
#property (nonatomic, retain) IBOutlet UIDatePicker *customInput;
- (IBAction)dateChanged:(id)sender;
- (IBAction)doneEditing:(id)sender;
#end
In the XIB, Pull out a UIToolbar and a UIDatePicker but don't attach it to the view. Connect the outlets appropriately. dateChanged: responds to changes in the date picker and doneEditing: is called when the Done button in the tool bar is clicked. Connect them too. The methods are implemented as listed below.
#implementation CustomKeyboardAppDelegate
#synthesize window=_window;
#synthesize textField = _textField;
#synthesize accessoryView = _accessoryView;
#synthesize customInput = _customInput;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.textField.inputView = self.customInput;
self.textField.inputAccessoryView = self.accessoryView;
...
}
...
- (IBAction)dateChanged:(id)sender {
UIDatePicker *picker = (UIDatePicker *)sender;
self.textField.text = [NSString stringWithFormat:#"%#", picker.date];
}
- (IBAction)doneEditing:(id)sender {
[self.textField resignFirstResponder];
}
#end
The last two methods will bloat up as more text fields depend on this picker.
Very simple, in ViewController.h put the UITextFieldDelegate after in viewDidLoad.
txtFecha.delegate = self;
datePicker = [[UIDatePicker alloc]init];
[datePicker setDatePickerMode:UIDatePickerModeDate];
self.txtFecha.inputView = datePicker;
In viewDidLoad of ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
UIDatePicker *datePicker = [[UIDatePicker alloc]init];
[datePicker setDate:[NSDate date]];
datePicker.datePickerMode = UIDatePickerModeDate;
[datePicker addTarget:self action:#selector(dateTextField:) forControlEvents:UIControlEventValueChanged];
[txtFieldBranchYear setInputView:datePicker];
}
Add one method in your ViewController
-(void) dateTextField:(id)sender
{
UIDatePicker *picker = (UIDatePicker*)txtFieldBranchYear.inputView;
[picker setMaximumDate:[NSDate date]];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
NSDate *eventDate = picker.date;
[dateFormat setDateFormat:#"dd/MM/yyyy"];
NSString *dateString = [dateFormat stringFromDate:eventDate];
txtFieldBranchYear.text = [NSString stringWithFormat:#"%#",dateString];
}
txtFieldBranchYear is an outlet of UITextField
There's a really useful class I found - the blog post is here: http://www.pietrorea.com/2012/07/how-to-hide-the-cursor-in-a-uitextfield/ but it basically uses the inputView/inputAccessory view as well. The kicker is that the UILabel, at least for what I was doing, was exactly what I needed.
open date picker on click on textField swift 3.0
add UITextFieldDelegate and
set delegate on ViewDidload()
tfDate.delegate = self
//MARK:- TextField Delegate
//MARK:-
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
//MARK:- DatePicker
//MARK:-
func textFieldDidBeginEditing(_ textField: UITextField) {
self.callDatePicker(textField: tfDate)
}
func callDatePicker(textField:UITextField){
let datePickerView : UIDatePicker = UIDatePicker()
datePickerView.datePickerMode = UIDatePickerMode.date
textField.inputView = datePickerView
datePickerView.addTarget(self, action: #selector(MyViewController.handleDatePicker), for: .valueChanged)
}
var str:String = ""
var str1:String = ""
var strStartDate:Date!
var strEndDate:Date!
func handleDatePicker(sender: UIDatePicker) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy"
print("Date :: \(dateFormatter.string(from: sender.date))")
tfDate.text = dateFormatter.string(from: sender.date)
}

Resources