18

我使用标准渐变叠加(在 Photoshop 中完成)使按钮在我的应用程序中看起来更漂亮。我添加了一个 Airplay 按钮,但审美不匹配。

在此处输入图像描述

我真的很想在它上面放一个渐变层以便匹配,但是我能找到的任何东西都只显示了如何使用 png 来做到这一点,而不是现有的 UIView。如果不是渐变层,我只需要以某种方式改变 Apple Airplay 按钮的外观,同时保持其功能不变。

设置代码很简单:

MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:frame];
[volumeView setShowsVolumeSlider:NO];
[bottomPanel addSubview:volumeView];

我怎样才能让这个外观与我的控件相匹配?

4

5 回答 5

16

在接受@Erik B 的回答并将赏金授予他之后,我发现需要进行更多调整才能使其正常工作。我在这里发帖是为了未来的 SO 搜索者。

我看到的问题是按钮的内部机制会根据当前的播放状态分配图像。因此,如果 Airplay 接收器消失或状态以某种方式改变,我在初始化期间所做的任何自定义都不会保留。alpha为了解决这个问题,我在按钮的键上设置了一个 KVO 观察。我注意到按钮总是淡入/淡出,这是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中的主播放器屏幕

于 2011-10-28T12:20:12.237 回答
15

我终于找到了一个蓝牙耳机,以便我可以测试按钮。改变它的外观非常简单。这是代码:

for (UIButton *button in volumeView.subviews) {
    if ([button isKindOfClass:[UIButton class]]) {
        [button setImage:[UIImage imageNamed:@"custom-route-button.png"] forState:UIControlStateNormal];
        [button sizeToFit];
    }
}

这就是它的全部。

于 2011-03-25T17:09:07.410 回答
7

更新:从 iOS 13 开始,此方法已弃用!

我认为自 iOS 6 以来有一个更好的解决方案:使用

- (void)setRouteButtonImage:(UIImage *)image forState:(UIControlState)state;

在 MPVolumeView 上。

请参阅 https://developer.apple.com/Library/ios/documentation/MediaPlayer/Reference/MPVolumeView_Class/index.html#//apple_ref/occ/instm/MPVolumeView/setRouteButtonImage:forState

于 2014-10-10T08:54:25.993 回答
3

上面的代码对我不起作用(因为稍后添加了 AirPlay 按钮)。作为一种解决方法,您可以在 UI 中使用标准 UIButton 并在(隐藏)MPVolumeView按钮中触发 AirPlay

for (UIButton *button in volumeView.subviews)
{
    if ([button isKindOfClass:[UIButton class]]) 
    {
        [button sendActionsForControlEvents:UIControlEventTouchUpInside];
    }
}

副作用是,当只有一条路线可用时,按钮不会自动隐藏,这可能是也可能不是所需的行为。

于 2011-10-18T20:00:23.807 回答
1

我创建了一个完美的自定义方法......

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

        }

    }

}
于 2015-04-27T22:51:29.913 回答