A drop-in universal solution for moving text fields out of the way of the keyboard A drop-in universal solution for moving text fields out of the way of the keyboard
  • Home
  • Posts
  • Home
  • Posts

Code

A drop-in universal solution for moving text fields out of the way of the keyboard

There are a hundred and one proposed solutions out there for how to move UITextField and UITextView out of the way of the keyboard during editing — usually, it comes down to observing UIKeyboardWillShowNotification and UIKeyboardWillHideNotification, or implementing UITextFieldDelegate delegate methods, and adjusting the frame of the superview, or using UITableView‘s scrollToRowAtIndexPath:atScrollPosition:animated:, but all the proposed solutions I’ve found tend to be quite DIY, and have to be implemented for each view controller that needs it.

I thought I’d put together a relatively universal, drop-in solution: UIScrollView and UITableView subclasses that handle everything.

When the keyboard is about to appear, the subclass will find the subview that’s about to be edited, and adjust its frame and content offset to make sure that view is visible, with an animation to match the keyboard pop-up. When the keyboard disappears, it restores its prior size.

It should work with basically any setup, either a UITableView-based interface, or one consisting of views placed manually.

Read More

Easy AAC compressed audio conversion on iOS

From the iPhone 3Gs up, it’s possible to encode compressed AAC audio from PCM audio data. That means great things for apps that deal with audio sharing and transmission, as the audio can be sent in compressed form, rather than sending huge PCM audio files over the network.

Apple’s produced some sample code (iPhoneExtAudioFileConvertTest), which demonstrates how it’s done, but their implementation isn’t particularly easy to use in existing projects, as it requires some wrapping to make it play nice.

For my upcoming looper app Loopy, I’ve put together a simple Objective-C class that performs the conversion of any audio file to an AAC-encoded m4a, asynchronously with a delegate, or converts any audio provided by a data source class (which provides for recording straight to AAC) and I thought I’d share it.

Read More

A simple, fast circular buffer implementation for audio processing

Circular buffers are pretty much what they sound like – arrays that wrap around. They’re fantastically useful as scratch space for audio processing, and generally passing audio around efficiently.

They’re designed for FIFO (first-in-first-out) use, like storing audio coming in the microphone for later playback or processing.

Consider a naive alternative: You copy the incoming audio into an NSData you allocate, and then pass that NSData off. This means you’re allocating memory each time, and deallocating the memory later once you’re done processing. That allocation incurs a penalty, which can be a show-stopper when part of an audio pipeline – The Core Audio documentation advises against any allocations when within a render callback, for example.

Alternatively, you can allocate space in advance, and write to that, but that has problems too: Either you have a synchronisation nightmare, or you spend lots of time moving bytes around so that the unprocessed audio is always at the beginning of the array.

A better solution is to use a circular buffer, where data goes in at the head, and is read from the tail. When you produce data at the head, the head moves up the array, and wraps around at the end. When you consume at the tail, the tail moves up too, so the tail chases the head around the circle.

Here’s a simple C implementation I recently put together for my app Loopy: TPCircularBuffer

Read More

Easy Delayed Messaging using NSProxy and NSInvocation

Sometimes it’s necessary to perform an action some time in the future, whether it’s disabling a button for a certain time interval after it’s pressed, performing an animation after a short wait, or triggering a reload of some data.

NSTimer is great for that purpose, as well as repeatedly performing actions, but it’s most convenient utility method, scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: only takes one ‘id‘ argument. Using the NSInvocation equivalent, scheduledTimerWithTimeInterval:invocation:repeats: requires creating and setting up the NSInvocation itself, which is always verbose and a pain.

NSProxy is a wonderful little construct that lets us interact with it like we were talking to the original object. I first learned how it works from a post by Shaun Wexler which shows an easier way to send a message on the main thread, by using the NSInvocation given via the NSProxy’s forwardInvocation: method. The same technique can be used to easily create a configured NSTimer.

So, instead of some awful thing like this:

NSInvocation *i = [NSInvocation invocationWithMethodSignature:[mapView methodSignatureForSelector:@selector(selectAnnotation:animated:)]];
[i setTarget:mapView];
MKAnnotation *annotation = view.annotation;
[i setArgument:&annotation atIndex:3];
BOOL flag=YES;
[i setArgument:&flag atIndex:4];
[NSTimer scheduledTimerWithTimeInterval:0.5 invocation:i repeats:NO];

NSInvocation *i = [NSInvocation invocationWithMethodSignature:[mapView methodSignatureForSelector:@selector(selectAnnotation:animated:)]]; [i setTarget:mapView]; MKAnnotation *annotation = view.annotation; [i setArgument:&annotation atIndex:3]; BOOL flag=YES; [i setArgument:&flag atIndex:4]; [NSTimer scheduledTimerWithTimeInterval:0.5 invocation:i repeats:NO];

We can do this:

[(MKMapView*)[TPTimerProxy scheduledTimerProxyWithTarget:mapView timeInterval:0.5 repeats:NO] selectAnnotation:view.annotation animated:YES];

[(MKMapView*)[TPTimerProxy scheduledTimerProxyWithTarget:mapView timeInterval:0.5 repeats:NO] selectAnnotation:view.annotation animated:YES];

Here’s the juice:

Read More

A trick for capturing all touch input for the duration of a touch

If you’ve ever tried to implement an interactive control that makes use of gestures within a UITableView, or tried to implement a view that you can drag around, like pins on a MKMapView, you’ll know that you’re either generally thwarted by the scroll view (and the table view will just scroll, instead of your control getting the vertical drag gesture), or as soon as the touch moves outside the bounds of your view, you’ll get no more touchesMoved events, making for a very frustrating dragging interaction.

Some platforms give you a way to capture all pointer input for a time, but this doesn’t appear to be available out of the box on the iPhone — at least, I haven’t found it.

Here’s a way to make it work:

  • Subclass UIWindow and replace sendEvent: with your own method
  • Provide a way for objects to be registered with your UIWindow subclass to gain ‘touch priority’ – either add a property that taken a UIView/UIResponder, or add a mutable array to be able to register multiple views.
  • When you receive a touch began event, check to see if the touch was within the bounds of any ‘priority’ views – if they are, the view subsequently gets all events until the touch ended event.
Read More

iPhone/Mac animation for custom classes: Property animation for more than just CALayer

I recently wrote a custom view — a 3D vintage-looking pull lever — that provided a continuous property to control the state. I wanted to animated this smoothly, a-la CABasicAnimation, but couldn’t find a built-in way to do so.

So, I wrote a class that provides similar functionality to CABasicAnimation, but works on any object. I thought I’d share it.

Features:

  • From/to value settings (currently only supports NSNumber and scalar numeric types, but easily extendable)
  • Duration, delay settings
  • Timing functions: Linear, ease out, ease in, and ease in/ease out
  • Animation chaining (specify another configured animation for chainedAnimation, and it’ll be fired once the first animation completes)
  • Delegate notification of animation completion
  • Uses a single timer for smooth lock-step animation
  • Uses CADisplayLink if available, to update in sync with screen updates

Use it like this:

- (void)startMyAnimation {
  TPPropertyAnimation *animation = [TPPropertyAnimation propertyAnimationWithKeyPath:@"state"];
  animation.toValue = [NSNumber numberWithFloat:1.0]; // fromValue is taken from current value if not specified
  animation.duration = 1.0;
  animation.timing = TPPropertyAnimationTimingEaseIn;
  [animation beginWithTarget:self];
}

- (void)startMyAnimation { TPPropertyAnimation *animation = [TPPropertyAnimation propertyAnimationWithKeyPath:@"state"]; animation.toValue = [NSNumber numberWithFloat:1.0]; // fromValue is taken from current value if not specified animation.duration = 1.0; animation.timing = TPPropertyAnimationTimingEaseIn; [animation beginWithTarget:self]; }

Make sure you also include the QuartzCore framework, used to access CADisplayLink, if it’s available.

It’s BSD-licensed.

Grab it here:
TPPropertyAnimation.zip

Read More

Hi! I'm Michael Tyson, and I run A Tasty Pixel from our home in the hills of Melbourne, Australia. I occasionally write on a variety of technology and software development topics. I've also spent 3.5-years travelling around Europe in a motorhome.

I make Loopy, the live-looper for iOS, Audiobus, the app-to-app audio platform, and Samplebot, a sampler and sequencer app for iOS.

Follow me on Twitter.

Posts pagination

« 1 2
© 2021 A Tasty Pixel.