Risposte:
Da " Tutorial per iPhone: un modo migliore per verificare le funzionalità dei dispositivi iOS ":
Esistono due funzioni apparentemente simili che accettano un parametro kSystemSoundID_Vibrate
:
1) AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
2) AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
Entrambe le funzioni vibrano l'iPhone. Ma quando si utilizza la prima funzione su dispositivi che non supportano le vibrazioni, viene emesso un segnale acustico. La seconda funzione, d'altra parte, non fa nulla sui dispositivi non supportati. Quindi, se hai intenzione di far vibrare il dispositivo continuamente, come avviso, dice il buon senso, usa la funzione 2.
Innanzitutto, aggiungi il framework AudioToolbox AudioToolbox.framework
al tuo target in Build Phases.
Quindi, importa questo file di intestazione:
#import <AudioToolbox/AudioServices.h>
AudioServicesPlayAlertSound(UInt32(kSystemSoundID_Vibrate))
(almeno dalla beta 2)
AudioToolbox presenta ora il kSystemSoundID_Vibrate
come un SystemSoundID
tipo, in modo che il codice è:
import AudioToolbox.AudioServices
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate)
Invece di dover passare attraverso il passaggio del cast extra
(Prop a @Dov)
Ed ecco come lo fai su Swift (nel caso in cui ti sia imbattuto nello stesso problema che ho fatto io)
Collega contro AudioToolbox.framework
(Vai al tuo progetto, seleziona il tuo obiettivo, costruisci fasi, Collega binario con librerie, aggiungi lì la libreria)
Una volta completato:
import AudioToolbox.AudioServices
// Use either of these
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
La cosa di cattivo gusto è che SystemSoundID
è fondamentalmente un typealias
(fantasia veloce typedef
) per a UInt32
, ed kSystemSoundID_Vibrate
è un normale Int
. Il compilatore ti dà un errore nel tentativo di eseguire il cast da Int
aUInt32
, ma l'errore è "Impossibile convertire in SystemSoundID", il che è fonte di confusione. Perché la mela non l'ha fatta diventare un enum Swift è oltre me.
@ Aponomarenko va nei dettagli, la mia risposta è solo per gli Swifters.
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
e compilato bene
Un modo semplice per farlo è con i servizi audio:
#import <AudioToolbox/AudioToolbox.h>
...
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
Ho avuto grossi problemi con questo per i dispositivi che avevano la vibrazione disattivata in qualche modo, ma ne avevamo bisogno per funzionare indipendentemente, perché è fondamentale per il funzionamento della nostra applicazione e poiché è solo un numero intero per una chiamata di metodo documentata, passerà convalida. Quindi ho provato alcuni suoni che erano al di fuori di quelli ben documentati qui: TUNER88 / iOSSystemSoundsLibrary
Mi sono quindi imbattuto nel 1352, che funziona indipendentemente dall'interruttore silenzioso o dalle impostazioni sul dispositivo (Settings->vibrate on ring, vibrate on silent)
.
- (void)vibratePhone;
{
if([[UIDevice currentDevice].model isEqualToString:@"iPhone"])
{
AudioServicesPlaySystemSound (1352); //works ALWAYS as of this post
}
else
{
// Not an iPhone, so doesn't have vibrate
// play the less annoying tick noise or one of your own
AudioServicesPlayAlertSound (1105);
}
}
Nota importante: avviso di futura deprecazione.
A partire da iOS 9.0 , la descrizione delle funzioni API per:
AudioServicesPlaySystemSound(inSystemSoundID: SystemSoundID)
AudioServicesPlayAlertSound(inSystemSoundID: SystemSoundID)
include la seguente nota:
This function will be deprecated in a future release.
Use AudioServicesPlayAlertSoundWithCompletion or
AudioServicesPlaySystemSoundWithCompletion instead.
La strada giusta da percorrere sarà usare uno di questi due:
AudioServicesPlayAlertSoundWithCompletion(kSystemSoundID_Vibrate, nil)
o
AudioServicesPlayAlertSoundWithCompletion(kSystemSoundID_Vibrate) {
//your callback code when the vibration is done (it may not vibrate in iPod, but this callback will be always called)
}
ricordati di
import AVFoundation
Per un iPhone 7/7 Plus o più recente, usa queste tre API di feedback Haptic.
let generator = UINotificationFeedbackGenerator()
generator.notificationOccured(style: .error)
Stili disponibili sono .error
, .success
e .warning
. Ognuno ha il suo aspetto distintivo.
Dai documenti :
Una
UIFeedbackGenerator
sottoclasse concreta che crea tattiche per comunicare successi, fallimenti e avvertimenti.
let generator = UIImpactFeedbackGenerator(style: .medium)
generator.impactOccured()
Stili disponibili sono .heavy
, .medium
e .light
. Queste sono vibrazioni semplici con vari gradi di "durezza".
Dai documenti :
Una
UIFeedbackGenerator
sottoclasse concreta che crea tattili per simulare gli impatti fisici
let generator = UISelectionFeedbackGenerator()
generator.selectionChanged()
Questo è il meno evidente di tutti gli aspetti tattili, e quindi è il più adatto per quando i soggetti tattili non dovrebbero assumere l'esperienza dell'app.
Dai documenti :
Una
UIFeedbackGenerator
sottoclasse concreta che crea tattili per indicare un cambiamento nella selezione.
Ci sono un paio di cose che vale la pena ricordare quando si utilizzano queste API.
In realtà non si crea l'ottico. Si richiede al sistema di generare un aptico. Il sistema deciderà in base a quanto segue:
Pertanto, il sistema ignorerà silenziosamente la tua richiesta di aptico se non è possibile. Se ciò è dovuto a un dispositivo non supportato, puoi provare questo:
func haptic() {
// Get whether the device can generate haptics or not
// If feedbackSupportLevel is nil, will assign 0
let feedbackSupportLevel = UIDevice.current.value(forKey: "_feedbackSupportLevel") as? Int ?? 0
switch feedbackSupportLevel {
case 2:
// 2 means the device has a Taptic Engine
// Put Taptic Engine code here, using the APIs explained above
case 1:
// 1 means no Taptic Engine, but will support AudioToolbox
// AudioToolbox code from the myriad of other answers!
default: // 0
// No haptic support
// Do something else, like a beeping noise or LED flash instead of haptics
}
Sostituisci i commenti nel switch
-case
dichiarazioni e questo codice di generazione aptico sarà portatile per altri dispositivi iOS. Genererà il più alto livello possibile di aptico.
prepare()
metodo per metterlo in stato di prontezza. Usando il tuo Game Over esempio: potresti sapere che il gioco sta per finire, se l'utente ha HP molto bassi o un mostro pericoloso è vicino a lui.
In questo caso, la preparazione del Taptic Engine creerebbe un'esperienza di qualità superiore e più reattiva.
Ad esempio, supponiamo che la tua app utilizzi un riconoscimento dei gesti di panoramica per cambiare la parte del mondo visibile. Volete generare un aptico quando l'utente "guarda" a 360 gradi. Ecco come è possibile utilizzare prepare()
:
@IBAction func userChangedViewablePortionOfWorld(_ gesture: UIPanGestureRecogniser!) {
haptic = UIImpactFeedbackGenerator(style: .heavy)
switch gesture.state {
case .began:
// The user started dragging the screen.
haptic.prepare()
case .changed:
// The user trying to 'look' in another direction
// Code to change viewable portion of the virtual world
if virtualWorldViewpointDegreeMiddle = 360.0 {
haptic.impactOccured()
}
default:
break
}
import UIKit
!
haptic
all'interno di questo metodo. Non stai chiamando impactOccured
la stessa istanza che chiami prepare
.
Nei miei viaggi ho scoperto che se provi una delle seguenti operazioni mentre stai registrando l'audio, il dispositivo non vibrerà anche se è abilitato.
1) AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
2) AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
Il mio metodo è stato chiamato in un momento specifico nella misurazione dei movimenti dei dispositivi. Ho dovuto interrompere la registrazione e quindi riavviarlo dopo che si era verificata la vibrazione.
Sembrava così.
-(void)vibrate {
[recorder stop];
AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
[recorder start];
}
recorder
è un'istanza di AVRecorder.
Spero che questo aiuti gli altri che hanno avuto lo stesso problema prima.
In iOS 10 e su iPhone più recenti, puoi anche utilizzare l'API aptica. Questo feedback tattile è più morbido dell'API AudioToolbox.
Per il tuo scenario GAME OVER, dovrebbe essere adatto un forte feedback sull'impatto dell'interfaccia utente.
UIImpactFeedbackGenerator(style: .heavy).impactOccurred()
È possibile utilizzare gli altri stili di feedback tattili .
Nel mio caso stavo usando AVCaptureSession. AudioToolbox era in fase di costruzione del progetto ed è stato importato ma non ha ancora funzionato. Per farlo funzionare ho interrotto la sessione prima delle vibrazioni e ho continuato dopo.
#import <AudioToolbox/AudioToolbox.h>
...
@property (nonatomic) AVCaptureSession *session;
...
- (void)vibratePhone;
{
[self.session stopRunning];
NSLog(@"vibratePhone %@",@"here");
if([[UIDevice currentDevice].model isEqualToString:@"iPhone"])
{
AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
}
else
{
AudioServicesPlayAlertSound (kSystemSoundID_Vibrate);
}
[self.session startRunning];
}
Puoi usare
1) AudioServicesPlayAlertSound (kSystemSoundID_Vibrate);
per iPhone e alcuni iPod più recenti.
2) AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
per iPad.