Ответ 1
Я думаю, что лучшее решение для этого с iOS 6: Используйте
- (void)setRouteButtonImage:(UIImage *)image forState:(UIControlState)state;
в MPVolumeView.
Я использую стандартное наложение градиента (сделано в Photoshop), чтобы кнопки выглядели лучше в моем приложении. Я добавил кнопку Airplay, но эстетика не подходит.
Я действительно хочу наложить на него слой градиента, чтобы он соответствовал, но все, что я могу найти, показывает только, как это сделать с помощью png, а не с существующим UIView. Если не градиентный слой, мне просто нужно каким-то образом изменить внешний вид кнопки Apple в эфире, сохранив при этом ее функциональность.
Код настройки прост:
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:frame];
[volumeView setShowsVolumeSlider:NO];
[bottomPanel addSubview:volumeView];
Как я могу получить внешний вид этого элемента для соответствия моим элементам управления?
Я думаю, что лучшее решение для этого с iOS 6: Используйте
- (void)setRouteButtonImage:(UIImage *)image forState:(UIControlState)state;
в MPVolumeView.
После принятия ответа @Erik B и награждения его щедростью, я обнаружил, что для его работы требуется больше настроек. Я размещаю здесь в интересах будущих поисковиков SO.
Проблема, которую я наблюдал, заключалась в том, что внутренние механизмы кнопок будут назначать изображение, основанное на текущем состоянии воспроизведения. Таким образом, любые настройки, которые я делал во время init, не будут придерживаться, если приемник Airplay исчезнет, или состояние каким-то образом изменилось. Чтобы решить эту проблему, я настраиваю наблюдение KVO на кнопке alpha
. Я заметил, что кнопка всегда исчезает в/из, которая является анимацией на alpha
.
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectZero];
[volumeView setShowsVolumeSlider:NO];
for (UIButton *button in volumeView.subviews) {
if ([button isKindOfClass:[UIButton class]]) {
self.airplayButton = button; // @property retain
[self.airplayButton setImage:[UIImage imageNamed:@"airplay.png"] forState:UIControlStateNormal];
[self.airplayButton setBounds:CGRectMake(0, 0, kDefaultIconSize, kDefaultIconSize)];
[self.airplayButton addObserver:self forKeyPath:@"alpha" options:NSKeyValueObservingOptionNew context:nil];
}
}
[volumeView sizeToFit];
Затем я наблюдаю измененное значение кнопок alpha
.
- (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.png"] forState:UIControlStateNormal];
[(UIButton *)object setBounds:CGRectMake(0, 0, kDefaultIconSize, kDefaultIconSize)];
}
}
Не забудьте удалить наблюдателя, если вы уничтожите кнопку
- (void)dealloc {
[self.airplayButton removeObserver:self forKeyPath:@"alpha"];
…
}
На основе наблюдения кода кнопка будет разбита, если Apple изменит иерархию внутреннего представления MPVolumeView
, чтобы добавить/удалить/изменить виды, чтобы появилась другая кнопка. Это делает его хрупким, поэтому используйте на свой страх и риск, или придумайте план b, если это произойдет. Я использую его более года в производстве без каких-либо проблем. Если вы хотите увидеть его в действии, проверьте основной экран игрока в Ambiance
Наконец-то я нашел Bluetooth-гарнитуру, чтобы проверить тестовую кнопку. Изменение его внешнего вида было очень простым. Здесь код:
for (UIButton *button in volumeView.subviews) {
if ([button isKindOfClass:[UIButton class]]) {
[button setImage:[UIImage imageNamed:@"custom-route-button.png"] forState:UIControlStateNormal];
[button sizeToFit];
}
}
Что там все.
Приведенный выше код не работает для меня (поскольку кнопка AirPlay добавляется позже). В качестве обходного пути вы можете использовать стандартный UIButton в своем пользовательском интерфейсе и запускать AirPlay в (скрытой) кнопке MPVolumeView
с помощью
for (UIButton *button in volumeView.subviews)
{
if ([button isKindOfClass:[UIButton class]])
{
[button sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
Побочным эффектом является то, что кнопка не скроется автоматически, когда доступен только один маршрут, что может или не может быть желательным.
Я создал собственный метод, который отлично работает...
-(void)airplayIcon:(CGRect)rect {
UIView *aiplayView = [[UIView alloc] initWithFrame:self.bounds];
aiplayView.clipsToBounds = true;
aiplayView.backgroundColor = [UIColor clearColor];
[self addSubview:aiplayView];
MPVolumeView *airplayVolume = [[MPVolumeView alloc] initWithFrame:aiplayView.bounds];
airplayVolume.showsVolumeSlider = false;
[aiplayView addSubview:airplayVolume];
for (UIButton *button in airplayVolume.subviews) {
[button setFrame:self.bounds];
if ([button isKindOfClass:[UIButton class]]) {
[button setImage:[UIImage imageNamed:@"normal.png"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:@"selected.png"] forState:UIControlStateSelected];
[button sizeToFit];
}
}
}