2012-09-07 8 views
7

Próbowałem rozwiązać ten problem przez 2 dni i poddaję się. Próbuję zaimplementować dostosowany przycisk airplay (muszę mieć świadomość, że tło jest białe, a przycisk musi być czarny). Ive dodał widok w interfacebuilder i wybrał dla niego mpVolumeView. Potem zrobiłem połączenia i napisałem poniższy kod;Jak dostosować przycisk Airplay, gdy gra jest włączona?

viewDidLoad.. { 
    ..... 

    [_volumeView setShowsVolumeSlider:NO]; 
    for (UIButton *button in _volumeView.subviews) { 
     if ([button isKindOfClass:[UIButton class]]) { 
      [button setImage:[UIImage imageNamed:@"airplay_icon.png"] forState:UIControlStateNormal]; 
      [button addObserver:self forKeyPath:@"alpha" options:NSKeyValueObservingOptionNew context:nil]; 
      [button addTarget:self action:@selector(switchAirplayButton) forControlEvents:UIControlEventTouchUpInside]; 
      [button sizeToFit]; 
     } 
    } 
    [_volumeView sizeToFit]; 

} 

-(void)switchAirplayButton { 

    for (UIButton *button in _volumeView.subviews) { 
     if ([button isKindOfClass:[UIButton class]]) { 

      NSLog(@"%d", _controlBar.player.airPlayVideoActive); 

      if(_controlBar.player.airPlayVideoActive) { 
       [button setImage:[UIImage imageNamed:@"airplay_icon_pressed.png"] forState:UIControlStateNormal]; 
      } else [button setImage:[UIImage imageNamed:@"airplay_icon.png"] forState:UIControlStateNormal]; 

      [button sizeToFit]; 
     } 
    } 


} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 
    if ([object isKindOfClass:[UIButton class]] && [[change valueForKey:NSKeyValueChangeNewKey] intValue] == 1) { 
     [(UIButton *)object setImage:[UIImage imageNamed:@"airplay_icon.png"] forState:UIControlStateNormal]; 
     [(UIButton *)object sizeToFit]; 
    } 
} 

"Gracz" to singel na podstawie AVPLayer. Jednak zawsze zwraca wartość false podczas sprawdzania, czy funkcja airPlay jest aktywna. Może to tylko dlatego, że używam dźwięku, a nie wideo.

Moje pytanie brzmi: jak mogę zmienić przycisk, aby ... powiedzmy pomarańczowy (tylko po to, aby dopasować resztę interfejsu), gdy strumień jest w strumieniu (tak jak jabłko robi to na niebiesko). Próbowałem wszystkiego i po prostu nie działa. Proszę pomóż mi.

+0

Chikuba, jak radzisz sobie z tym problemem, mam do czynienia z tym samym problemem w mojej aplikacji VoIP iOS, możesz udzielić sugestii? Dzięki! –

Odpowiedz

18

Edit:

Choć poniżej kod działa zarówno iOS 5 i 6, wychodząc z iOS 6.0 nie jest oficjalnym sposobem na to, co jest o wiele łatwiejsze. Wystarczy spojrzeć na dokumentację MPVolumeView, konkretnie – setRouteButtonImage:forState:.

==== Old odpowiedź: ====

Jest to dość trudne do osiągnięcia, ale znalazłem sposób na iOS 5.0+. Przede wszystkim, należy dodać następujący wiersz do ViewController:

#import <AudioToolbox/AudioToolbox.h> 

W swojej viewDidLoad, jesteś już robi większość rzeczy rację, to jest mój kod:

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]; 
    } 
} 

Oto pomocnik setAirPlayButtonSelected metoda, to po prostu ustawia obraz:

- (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]; 
} 

Przez wzgląd na Ukończenie, tym 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]]; 
    } 
} 

A teraz nadchodzi interesująca część. Oto metoda pomocnika isAirPlayActive. Wykorzystuje framework AudioSession do określenia aktualnie odtwarzanego źródła audio.

- (BOOL)isAirPlayActive{ 
    CFDictionaryRef currentRouteDescriptionDictionary = nil; 
    UInt32 dataSize = sizeof(currentRouteDescriptionDictionary); 
    AudioSessionGetProperty(kAudioSessionProperty_AudioRouteDescription, &dataSize, &currentRouteDescriptionDictionary); 
    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; 
} 

A więc cały ten kod poprawnie zmienia przycisk AirPlay przy uruchomieniu aplikacji. A co z aktualizacjami? Musimy słuchać zmian w AudioSource. Dodaj następujący wiersz do viewDidLoad:

AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange, audioRouteChangeCallback, (__bridge void*)self); 

Nie zapomnij wyrejestrowania w dealloc:

- (void)dealloc { 
    [self.airPlayButton removeObserver:self forKeyPath:@"alpha"]; 

    AudioSessionRemovePropertyListenerWithUserData(kAudioSessionProperty_AudioRouteChange, audioRouteChangeCallback, (__bridge void*)self); 

} 

I dodać tę funkcję C powyżej twój ViewController na @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]; 
    } 

} 

jak ty widać, wszystko, co robi, to określa, czy źródło sygnału AirPlay jest aktywne, i wywołuje metodę zgodną z metodą setAirPlayButtonSelected co najwyżej.

Zobacz Apple's Audio Session Programming Guide, w szczególności this section, aby uzyskać szczegółowe informacje o tym, jak działają callbacki itp.

+0

Po prostu zarabiasz na prawdziwe rep-boost :) wczoraj doszłam prawie do tego samego rozwiązania, ale wskazałeś kilka naprawdę fajnych rzeczy, które muszę zachować inmind (na przykład usuń słuchacza). dziękuję bardzo! – chikuba

+0

Obserwator alfa jest tym, czego potrzebowałem do mojego rozwiązania. Świetna sprawa! : D –

+0

w iOS 8 musisz zmienić: if (CFArrayGetCount (output)> 0) to: if (outputs && CFArrayGetCount (output)> 0) –

0

Sprawdź tę podobną link here.

Nie jestem pewien, czy to będzie działać, ale spróbuj czarny przycisk z symbolem AirPlay następnie umieścić go na górze przycisk airplay że trudno zobaczyć. Powinieneś ustawić interakcję użytkownika na wyłączona. Spróbuj, może to być łatwiejsze rozwiązanie.

* nie zapomnij wyłączyć interakcji użytkownika w inspektorze atrybutów i inspektorze tożsamości.

Powiązane problemy