はどのようにして、ユーザがUIView
をタップかどうかを確認またはUIView
上のタッチを強制するために、3Dタッチを実現することができますか?3Dタッチ/フォースタッチ実装
UIGestureRecognize
のみUITouch
とでこれを行う方法はありますか?
はどのようにして、ユーザがUIView
をタップかどうかを確認またはUIView
上のタッチを強制するために、3Dタッチを実現することができますか?3Dタッチ/フォースタッチ実装
UIGestureRecognize
のみUITouch
とでこれを行う方法はありますか?
よりも古いバージョンをサポートしている場合は、上で実行されているどのようなiOSのバージョンに基づいて、この認識機能を追加します。 touchesEndedメソッドとtouchesBeganメソッドを調整する必要はありませんが、単にtouchesMovedを使用して正しい値を取得するだけです。 uitouchの力を開始/終了から奇妙な値を返します。その後、
UITouch *touch = [touches anyObject];
CGFloat maximumPossibleForce = touch.maximumPossibleForce;
CGFloat force = touch.force;
CGFloat normalizedForce = force/maximumPossibleForce;
、(0.75が私のために罰金だ)力のしきい値を設定し、このしきい値にnormalizedForceを比較します。
3Dタッチのプロパティare available on UITouch
objects。
UIView
のtouchesBegan:
とtouchesMoved:
のメソッドをオーバーライドすることで、これらの接触を得ることができます。 touchesEnded:
に表示される内容はまだわかりません。
新しいジェスチャーレコグナイザを作成したい場合は、UIGestureRecognizerSubclass
に公開されているUITouch
に完全にアクセスできます。
私はあなたが伝統的なUIGestureRecognizer
での3Dタッチのプロパティを使用することができますかどうかはわかりません。おそらくUIGestureRecognizerDelegate
プロトコルのgestureRecognizer:shouldReceiveTouch:
メソッドを介して。
私はUIViewの –
上のUIViewまたは力touchのユーザータップは 'UITapGestureRecognizer'が3D Touch用更新されていないので、あなたがあなた自身の' UIGestureRecognizer'サブクラスを作るか、またはビューをサブクラス化しなければならないかどうかを確認したいです'touchesBegan'と' touchesMoved'を処理します。 –
タッチが動かずに強制変更された場合、 'touchesMoved:'が呼び出されますか? – Warpling
私がこれをやっているのは、UITapGestureRecognizer(Apple提供)とDFContinuousForceTouchGestureRecognizer(私が提供)の組み合わせを使用することです。
DFContinuousForceTouchGestureRecognizer
は、気圧変化について継続的な更新を提供するので、ユーザーが圧力に変化するにつれてビューを増やすことができます(単一のイベントではなく)。単一のイベントだけが必要な場合は、の- (void) forceTouchRecognized
コールバックを除いて、eveythingを無視することができます。
https://github.com/foggzilla/DFContinuousForceTouchGestureRecognizer
あなたはこれをダウンロードし、それを感じているかを確認するために力押しをサポートするデバイス上でサンプルアプリを実行することができます。
- (void)viewDidLoad {
[super viewDidLoad];
_forceTouchRecognizer = [[DFContinuousForceTouchGestureRecognizer alloc] init];
_forceTouchRecognizer.forceTouchDelegate = self;
//here to demonstrate how this works alonside a tap gesture recognizer
_tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
[self.imageView addGestureRecognizer:_tapGestureRecognizer];
[self.imageView addGestureRecognizer:_forceTouchRecognizer];
}
力touch用のデリゲートプロトコルの実装タップジェスチャーのため
#pragma UITapGestureRecognizer selector
- (void)tapped:(id)sender {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[[UIAlertView alloc] initWithTitle:@"Tap" message:@"YEAH!!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
});
}
をセレクタを実装します:これはのみすること
#pragma DFContinuousForceTouchDelegate
- (void)forceTouchRecognized:(DFContinuousForceTouchGestureRecognizer *)recognizer {
self.imageView.transform = CGAffineTransformIdentity;
[self.imageView setNeedsDisplay];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[[UIAlertView alloc] initWithTitle:@"Force Touch" message:@"YEAH!!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
});
}
- (void)forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer *)recognizer didStartWithForce:(CGFloat)force maxForce:(CGFloat)maxForce {
CGFloat transformDelta = 1.0f + ((force/maxForce)/3.0f);
self.imageView.transform = CGAffineTransformMakeScale(transformDelta, transformDelta);
[self.imageView setNeedsDisplay];
}
- (void) forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer *)recognizer didMoveWithForce:(CGFloat)force maxForce:(CGFloat)maxForce {
CGFloat transformDelta = 1.0f + ((force/maxForce)/3.0f);
self.imageView.transform = CGAffineTransformMakeScale(transformDelta, transformDelta);
[self.imageView setNeedsDisplay];
}
- (void)forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer *)recognizer didCancelWithForce:(CGFloat)force maxForce:(CGFloat)maxForce {
self.imageView.transform = CGAffineTransformIdentity;
[self.imageView setNeedsDisplay];
}
- (void)forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer *)recognizer didEndWithForce:(CGFloat)force maxForce:(CGFloat)maxForce {
self.imageView.transform = CGAffineTransformIdentity;
[self.imageView setNeedsDisplay];
}
- (void)forceTouchDidTimeout:(DFContinuousForceTouchGestureRecognizer *)recognizer {
self.imageView.transform = CGAffineTransformIdentity;
[self.imageView setNeedsDisplay];
}
注意をごUIViewController
次の実装で
フォースタッチをサポートするデバイスで役立つことがあります。あなたはiOSの8それにこれを追加した場合、それはiOSの9
でのみ利用可能UITouch
に新しいforce
プロパティを使用していますので、あなたはiOSの8上または下で実行されている場合
はまた、あなたは、ビューにDFContinuousForceTouchGestureRecognizer
を追加しないでくださいクラッシュし、その条件付きであなたはあなたが指定したジェスチャー認識せずにそれを行うことができますiOSの9
うわー、ありがとう! Swift 2.0へのあなたの答えを変換できますか?私のアプリはiOS 8 - 9をサポートしているので、DFContinuousForceTouchGestureRecognizerを表示するには、 –
Apple Mailアプリの動作をエミュレートするUIGestureRecognizerを作成しました。 3次元タッチでは、最初の短いパルスで振動し、その後、最初のプレスの直後にハードプレスで呼び出される任意の2次アクション(ハードターゲット)とパルスが始まります。
変更から適応
デフォルトレベル
注:文書化されていないシステムサウンドk_PeakSoundIDを追加しましたが、文書化された範囲を超えて定数を使用するのが不快なら、それを無効にしてください。私は何年もの間、非公開の定数でシステムサウンドを使用してきましたが、vibrateOnDeepPressプロパティを使用して振動パルスをオフにすることを歓迎しています。
import AudioToolbox
import UIKit.UIGestureRecognizerSubclass
class DeepPressGestureRecognizer: UIGestureRecognizer
{
var vibrateOnDeepPress = true
var threshold:CGFloat = 0.75
var hardTriggerMinTime:NSTimeInterval = 0.5
private var deepPressed: Bool = false
private var deepPressedAt: NSTimeInterval = 0
private var k_PeakSoundID:UInt32 = 1519
private var hardAction:Selector?
private var target: AnyObject?
required init(target: AnyObject?, action: Selector, hardAction:Selector?=nil, threshold: CGFloat = 0.75)
{
self.target = target
self.hardAction = hardAction
self.threshold = threshold
super.init(target: target, action: action)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent)
{
if let touch = touches.first
{
handleTouch(touch)
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent)
{
if let touch = touches.first
{
handleTouch(touch)
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent)
{
super.touchesEnded(touches, withEvent: event)
state = deepPressed ? UIGestureRecognizerState.Ended : UIGestureRecognizerState.Failed
deepPressed = false
}
private func handleTouch(touch: UITouch)
{
guard let _ = view where touch.force != 0 && touch.maximumPossibleForce != 0 else
{
return
}
let forcePercentage = (touch.force/touch.maximumPossibleForce)
let currentTime = NSDate.timeIntervalSinceReferenceDate()
if !deepPressed && forcePercentage >= threshold
{
state = UIGestureRecognizerState.Began
if vibrateOnDeepPress
{
AudioServicesPlaySystemSound(k_PeakSoundID)
}
deepPressedAt = NSDate.timeIntervalSinceReferenceDate()
deepPressed = true
}
else if deepPressed && forcePercentage <= 0
{
endGesture()
}
else if deepPressed && currentTime - deepPressedAt > hardTriggerMinTime && forcePercentage == 1.0
{
endGesture()
if vibrateOnDeepPress
{
AudioServicesPlaySystemSound(k_PeakSoundID)
}
//fire hard press
if let hardAction = self.hardAction, let target = self.target {
target.performSelector(hardAction, withObject: self)
}
}
}
func endGesture() {
state = UIGestureRecognizerState.Ended
deepPressed = false
}
}
// MARK: DeepPressable protocol extension
protocol DeepPressable
{
var gestureRecognizers: [UIGestureRecognizer]? {get set}
func addGestureRecognizer(gestureRecognizer: UIGestureRecognizer)
func removeGestureRecognizer(gestureRecognizer: UIGestureRecognizer)
func setDeepPressAction(target: AnyObject, action: Selector)
func removeDeepPressAction()
}
extension DeepPressable
{
func setDeepPressAction(target: AnyObject, action: Selector)
{
let deepPressGestureRecognizer = DeepPressGestureRecognizer(target: target, action: action, threshold: 0.75)
self.addGestureRecognizer(deepPressGestureRecognizer)
}
func removeDeepPressAction()
{
guard let gestureRecognizers = gestureRecognizers else
{
return
}
for recogniser in gestureRecognizers where recogniser is DeepPressGestureRecognizer
{
removeGestureRecognizer(recogniser)
}
}
}
を追加する必要はありません。 – Esqarrouth