昨天,在关于iPad 2的新版Garageband的演示中,苹果展示了一个有趣的功能:使用加速度计检测敲击力度。(请参见Garageband页面上的鼓组部分。)
我在想,如果iPad平放在桌子上,那么它该如何运作呢?没有移动,没有可测的加速度,那怎么办?
我在想,如果iPad平放在桌子上,那么它该如何运作呢?没有移动,没有可测的加速度,那怎么办?
有一些不错的答案。这里是一些可工作的代码。我将其实现为UIGestureRecognizer的子类,以便您可以轻松地将其放置并附加到UIView或UIButton上。一旦触发,它将把“压力”设置为介于0.0f和2.0f之间的浮点数。您还可以选择设置必须识别的最小和最大压力。享受。
//
// CPBPressureTouchGestureRecognizer.h
// PressureSensitiveButton
//
// Created by Anthony Picciano on 3/21/11.
// Copyright 2011 Anthony Picciano. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#import <UIKit/UIKit.h>
#define CPBPressureNone 0.0f
#define CPBPressureLight 0.1f
#define CPBPressureMedium 0.3f
#define CPBPressureHard 0.8f
#define CPBPressureInfinite 2.0f
@interface CPBPressureTouchGestureRecognizer : UIGestureRecognizer <UIAccelerometerDelegate> {
@public
float pressure;
float minimumPressureRequired;
float maximumPressureRequired;
@private
float pressureValues[30];
uint currentPressureValueIndex;
uint setNextPressureValue;
}
@property (readonly, assign) float pressure;
@property (readwrite, assign) float minimumPressureRequired;
@property (readwrite, assign) float maximumPressureRequired;
@end
//
// CPBPressureTouchGestureRecognizer.h
// PressureSensitiveButton
//
// Created by Anthony Picciano on 3/21/11.
// Copyright 2011 Anthony Picciano. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#import <UIKit/UIGestureRecognizerSubclass.h>
#import "CPBPressureTouchGestureRecognizer.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)setup {
minimumPressureRequired = CPBPressureNone;
maximumPressureRequired = CPBPressureInfinite;
pressure = CPBPressureNone;
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:1.0f / kUpdateFrequency];
[[UIAccelerometer sharedAccelerometer] setDelegate:self];
}
#pragma -
#pragma UIAccelerometerDelegate methods
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)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
请执行以下实验:
使用XCode打开AccelerometerGraph教程应用程序(该应用程序包含在XCode捆绑包中)。 然后启动该应用程序(使用高通滤波器,最好使用自适应滤波器):您将看到蓝线根据应用程序的强度而改变。当然,这会受到桌子上的颤动的影响,从而给测量结果添加噪声,但是您仍然可以通过检查带有触摸事件的加速度计数据来过滤它。
因此,使用加速度计可以进行此类压力检测。
viggio24说得对。手指区域感应很好用。(我在这里发布了一些获取它的简单代码行)唯一的问题是,如果启用它,不清楚后果会是什么;我们假设在最好的情况下,它只是不能被批准。
触控区域大小检测?(更强的敲击,更大的指纹) 敲击动态?
只是在思考。
尝试使用AccelerometerGraph示例应用程序进行自我测试。设备和桌面具有有限的刚度,因此您可能会在图表中看到一些小的波动。
添加:
如果您自己从源代码编译Apple的AccelerometerGraph图形示例,则可以在垂直轴上调高增益并查看更小加速度的波动。