CPBPressureTouchGestureRecognizer 仅支持对 UIAccelerometer 的委托模型执行自身的单个实例。这是支持多个实例的更好版本。
// CPBPressureTouchGestureRecognizer.h
// PressureSensitiveButton
#import <UIKit/UIKit.h>
#define CPBPressureNone 0.0f
#define CPBPressureLight 0.3f
#define CPBPressureMedium 0.4f
#define CPBPressureHard 0.6f
#define CPBPressureInfinite 2.0f
@interface CPBPressureTouchGestureRecognizer : UIGestureRecognizer {
@public
float pressure;
float minimumPressureRequired;
float maximumPressureRequired;
@private
float pressureValues[50];
uint currentPressureValueIndex;
uint setNextPressureValue;
}
@property (readonly, assign) float pressure;
@property (readwrite, assign) float minimumPressureRequired;
@property (readwrite, assign) float maximumPressureRequired;
@end
// CPBPressureTouchGestureRecognizer.m
#import <UIKit/UIGestureRecognizerSubclass.h>
#import "CPBPressureTouchGestureRecognizer.h"
#import "CPBAcceleromterDelegate.h"
#define kUpdateFrequency 60.0f
#define KNumberOfPressureSamples 3
@interface CPBPressureTouchGestureRecognizer (private)
- (void)setup;
@end
@implementation CPBPressureTouchGestureRecognizer
@synthesize pressure, minimumPressureRequired, maximumPressureRequired;
- (id)initWithTarget:(id)target action:(SEL)action {
self = [super initWithTarget:target action:action];
if (self != nil) {
[self setup];
}
return self;
}
- (id)init {
self = [super init];
if (self != nil) {
[self setup];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (void)setup {
minimumPressureRequired = CPBPressureNone;
maximumPressureRequired = CPBPressureInfinite;
pressure = CPBPressureNone;
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:0.001f / kUpdateFrequency];
[[UIAccelerometer sharedAccelerometer] setDelegate:[CPBAcceleromterDelegate sharedCPBAcceleromterDelegate]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(accelerateNotification:) name:CPB_ACCELERATION_EVENT object:nil];
}
#pragma -
#pragma UIAccelerometerDelegate methods
- (void)accelerateNotification:(NSNotification *)notification {
UIAcceleration *acceleration = [[CPBAcceleromterDelegate sharedCPBAcceleromterDelegate] acceleration];
int sz = (sizeof pressureValues) / (sizeof pressureValues[0]);
// set current pressure value
pressureValues[currentPressureValueIndex%sz] = acceleration.z;
if (setNextPressureValue > 0) {
// calculate average pressure
float total = 0.0f;
for (int loop=0; loop<sz; loop++) total += pressureValues[loop];
float average = total / sz;
// start with most recent past pressure sample
if (setNextPressureValue == KNumberOfPressureSamples) {
float mostRecent = pressureValues[(currentPressureValueIndex-1)%sz];
pressure = fabsf(average - mostRecent);
}
// caluculate pressure as difference between average and current acceleration
float diff = fabsf(average - acceleration.z);
if (pressure < diff) pressure = diff;
setNextPressureValue--;
if (setNextPressureValue == 0) {
if (pressure >= minimumPressureRequired && pressure <= maximumPressureRequired)
self.state = UIGestureRecognizerStateRecognized;
else
self.state = UIGestureRecognizerStateFailed;
}
}
currentPressureValueIndex++;
}
#pragma -
#pragma UIGestureRecognizer subclass methods
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
setNextPressureValue = KNumberOfPressureSamples;
self.state = UIGestureRecognizerStatePossible;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
self.state = UIGestureRecognizerStateFailed;
}
- (void)reset {
pressure = CPBPressureNone;
setNextPressureValue = 0;
currentPressureValueIndex = 0;
}
@end
//
// CPBAcceleromterDelegate.h
// iPan
//
// Created by Anthony Picciano on 1/25/12.
// Copyright (c) 2012 Crispin Porter + Bogusky. All rights reserved.
//
#import <Foundation/Foundation.h>
#define CPB_ACCELERATION_EVENT @"accellerationEvent"
@interface CPBAcceleromterDelegate : NSObject <UIAccelerometerDelegate>
@property (nonatomic, retain) UIAcceleration *acceleration;
+ (CPBAcceleromterDelegate *)sharedCPBAcceleromterDelegate;
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration;
@end
//
// CPBAcceleromterDelegate.m
// iPan
//
// Created by Anthony Picciano on 1/25/12.
// Copyright (c) 2012 Crispin Porter + Bogusky. All rights reserved.
//
#import "CPBAcceleromterDelegate.h"
#include "SynthesizeSingleton.h"
@implementation CPBAcceleromterDelegate
@synthesize acceleration;
SYNTHESIZE_SINGLETON_FOR_CLASS(CPBAcceleromterDelegate)
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)newAcceleration
{
self.acceleration = newAcceleration;
[[NSNotificationCenter defaultCenter] postNotificationName:CPB_ACCELERATION_EVENT object:self];
}
@end
//
// SynthesizeSingleton.h
// CocoaWithLove
//
// Created by Matt Gallagher on 20/10/08.
// Copyright 2009 Matt Gallagher. All rights reserved.
// http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html
//
// Permission is given to use this source code file without charge in any
// project, commercial or otherwise, entirely at your risk, with the condition
// that any redistribution (in part or whole) of source code must retain
// this copyright and permission notice. Attribution in compiled projects is
// appreciated but not required.
//
#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
\
static classname *shared##classname = nil; \
\
+ (classname *)shared##classname \
{ \
@synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [[self alloc] init]; \
} \
} \
\
return shared##classname; \
} \
\
+ (id)allocWithZone:(NSZone *)zone \
{ \
@synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [super allocWithZone:zone]; \
return shared##classname; \
} \
} \
\
return nil; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return self; \
} \
\
- (id)retain \
{ \
return self; \
} \
\
- (NSUInteger)retainCount \
{ \
return NSUIntegerMax; \
} \
\
- (void)release \
{ \
} \
\
- (id)autorelease \
{ \
return self; \
}