编辑:
虽然下面的代码适用于 iOS 5 和 6,但从 iOS 6.0 开始,有一种官方方法可以做到这一点,这要容易得多。只需查看 的文档MPVolumeView,特别是– setRouteButtonImage:forState:.
==== 旧答案:====
这很难实现,但我找到了适用于 iOS 5.0+ 的方法。首先,将以下行添加到您的 ViewController:
#import <AudioToolbox/AudioToolbox.h>
在您的 viewDidLoad 中,您已经做对了大部分事情,这是我的代码:
for (id current in self.volumeView.subviews){
if([current isKindOfClass:[UIButton class]]) {
UIButton *airPlayButton = (UIButton*)current;
self.airPlayButton = airPlayButton;
[self setAirPlayButtonSelected:[self isAirPlayActive]];
[airPlayButton addObserver:self forKeyPath:@"alpha" options:NSKeyValueObservingOptionNew context:nil];
}
}
这是辅助setAirPlayButtonSelected方法,它只是设置图像:
- (void)setAirPlayButtonSelected:(BOOL)selected {
UIImage* image;
if (selected) {
image = [UIImage imageNamed:@"button-airplay-selected"];
}else {
image = [UIImage imageNamed:@"button-airplay"];
}
[self.airPlayButton setImage:image forState:UIControlStateNormal];
[self.airPlayButton setImage:image forState:UIControlStateHighlighted];
[self.airPlayButton setImage:image forState:UIControlStateSelected];
}
为了完整起见,observeValueForKeyPath:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (object == self.airPlayButton && [[change valueForKey:NSKeyValueChangeNewKey] intValue] == 1) {
[self setAirPlayButtonSelected:[self isAirPlayActive]];
}
}
现在是有趣的部分。这是isAirPlayActive辅助方法。它使用 AudioSession 框架来确定当前正在播放的音频源。
- (BOOL)isAirPlayActive{
CFDictionaryRef currentRouteDescriptionDictionary = nil;
UInt32 dataSize = sizeof(currentRouteDescriptionDictionary);
AudioSessionGetProperty(kAudioSessionProperty_AudioRouteDescription, &dataSize, ¤tRouteDescriptionDictionary);
if (currentRouteDescriptionDictionary) {
CFArrayRef outputs = CFDictionaryGetValue(currentRouteDescriptionDictionary, kAudioSession_AudioRouteKey_Outputs);
if(CFArrayGetCount(outputs) > 0) {
CFDictionaryRef currentOutput = CFArrayGetValueAtIndex(outputs, 0);
CFStringRef outputType = CFDictionaryGetValue(currentOutput, kAudioSession_AudioRouteKey_Type);
return (CFStringCompare(outputType, kAudioSessionOutputRoute_AirPlay, 0) == kCFCompareEqualTo);
}
}
return NO;
}
因此,所有这些代码都会在应用启动时正确更改 AirPlay 按钮。更新呢?我们需要监听 AudioSource 的变化。将以下行添加到您的viewDidLoad:
AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange, audioRouteChangeCallback, (__bridge void*)self);
不要忘记取消注册dealloc:
- (void)dealloc {
[self.airPlayButton removeObserver:self forKeyPath:@"alpha"];
AudioSessionRemovePropertyListenerWithUserData(kAudioSessionProperty_AudioRouteChange, audioRouteChangeCallback, (__bridge void*)self);
}
并在您的 ViewController 上方添加此 C 函数@implementation:
void audioRouteChangeCallback (void *inUserData,
AudioSessionPropertyID inPropertyID,
UInt32 inPropertyValueSize,
const void *inPropertyValue) {
if (inPropertyID != kAudioSessionProperty_AudioRouteChange) {
return;
}
CFDictionaryRef routeChangeDictionary = inPropertyValue;
CFDictionaryRef currentRouteDescriptionDictionary = CFDictionaryGetValue(routeChangeDictionary, kAudioSession_AudioRouteChangeKey_CurrentRouteDescription);
CFArrayRef outputs = CFDictionaryGetValue(currentRouteDescriptionDictionary, kAudioSession_AudioRouteKey_Outputs);
if(CFArrayGetCount(outputs) > 0) {
CFDictionaryRef currentOutput = CFArrayGetValueAtIndex(outputs, 0);
CFStringRef outputType = CFDictionaryGetValue(currentOutput, kAudioSession_AudioRouteKey_Type);
[(__bridge SettingsViewController*)inUserData setAirPlayButtonSelected:CFStringCompare(outputType, kAudioSessionOutputRoute_AirPlay, 0) == kCFCompareEqualTo];
}
}
如您所见,它所做的只是确定 AirPlay 输出源是否处于活动状态并setAirPlayButtonSelected相应地调用该方法。
请参阅 Apple 的音频会话编程指南,特别是本节以获取有关回调如何准确工作等的详细信息。