MPVolumeView在iOS 7中无法正确重绘

时间:2013-10-07 06:28:01

标签: ios uiview ios7 mpvolumeview

所以我有一个iOS7应用,我正在使用MPVolumeView,因此用户可以控制音量。我在此特定MPVolumeView上隐藏了路线按钮,并使用另一个MPVolumeView并禁用滑块作为我的AirPlay图标。

我的应用程序同时支持纵向和横向,并且在这两种不同模式下,音量滑块的宽度不同。

如果视图首先在横向模式下初始化,那么MPVolumeView将正确调整其大小。

然而,当视图在纵向模式下初始化然后我旋转到横向模式时,应用程序中的所有其他内容都会被调整大小/移动,除了MPVolumeView仅被移动,并且它不会像它一样变短应该。

我在MPVolumeView上使用自定义图片,如果我删除了该曲目的自定义图片,则此问题就会消失。

以下是用于初始化MPVolumeView

的代码
    self.volumeView = [[MPVolumeView alloc] initWithFrame:CGRectZero];
    self.volumeView.showsRouteButton = NO;
    self.volumeView.layer.borderColor = [[UIColor redColor] CGColor];
    self.volumeView.layer.borderWidth = 1.0f;
    if (AT_LEAST_IOS7) {
        // TODO: BUGBUG iOS7 doesn't redraw this MPVolumeView correctly when it's frame changes (i.e. we rotate to the portrait view).
        // These images simply make the bar a little thicker than the standard thickness (to match the iOS7 music app) but it's not redrawing
        // correctly so we are going to have to live with a slightly thinner bar.
        [self.volumeView setMaximumVolumeSliderImage:[UIImage imageNamed:@"volume_bar_max"] forState:UIControlStateNormal];
        [self.volumeView setMinimumVolumeSliderImage:[UIImage imageNamed:@"volume_bar_min"] forState:UIControlStateNormal];
        [self.volumeView setVolumeThumbImage:[UIImage imageNamed:@"volume_scrubber"] forState:UIControlStateNormal];
    }
    [self addSubview:self.volumeView];

在layoutSubviews中,我正在重新定位/缩放它的框架:

self.volumeView.frame = CGRectIntegral(CGRectMake(controlsLeft + kEdgeToSliderSideWidth,
                                                  volumeTop,
                                                  controlsWidth - (2 * kEdgeToSliderSideWidth),
                                                  volumeSize.height));

以下是在纵向模式下开始视图时的样子:(总宽度为640像素)

Portrait Mode

当它旋转到横向时,它最终看起来像这样:(总宽度为568像素)

Landscape Mode

有人有什么想法吗?

4 个答案:

答案 0 :(得分:4)

我遇到了同样的问题。我目前的解决方法是在屏幕旋转后销毁并重新添加滑块:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    //remove the old view
    for (UIView *subview in self.volumeViewContainer.subviews)
        [subview removeFromSuperview];

    //recreate it
    UIImage *slider = [[UIImage imageNamed:@"slider"] resizableImageWithCapInsets:UIEdgeInsetsMake(0.0, 15.0, 0.0, 15.0)];
    UIImage *knobImage = [UIImage imageNamed:@"slider_knob"];
    MPVolumeView *volumeView = [[[MPVolumeView alloc] initWithFrame:self.volumeViewContainer.bounds] autorelease];
    [volumeView setMinimumVolumeSliderImage:slider forState:UIControlStateNormal];
    [volumeView setMaximumVolumeSliderImage:slider forState:UIControlStateNormal];
    [volumeView setVolumeThumbImage:knobImage forState:UIControlStateNormal];
    [self.volumeViewContainer addSubview:volumeView];
}

这样做仍然存在滑块在旋转期间仍然显示毛刺的问题。这就是我将滑块渲染到图像并在旋转发生之前将滑块与所述图像交换的原因:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    //render to UIImage
    UIGraphicsBeginImageContextWithOptions(self.volumeViewContainer.frame.size, NO, 0.0);
    [self.volumeViewContainer.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    //remove old slider
    for (UIView *subview in self.volumeViewContainer.subviews)
        [subview removeFromSuperview];

    //add UIImageView which resizes nicely with the container view
    UIImageView *imageView = [[[UIImageView alloc] initWithFrame:self.volumeViewContainer.bounds] autorelease];
    imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    imageView.image = img;
    [self.volumeViewContainer addSubview:imageView];
}

我知道这不是一个真正的解决方案,但我认为它总比没有好,我希望它对你有所帮助。

答案 1 :(得分:2)

经过大量实验后,似乎MPVolumeView在iOS 7.0.x中非常错误。

我遇到的问题是,使用最小/最大滑块,体积拇指和路线的自定义图像有时会导致滑块展开以覆盖路线按钮。

当我更改调用它们的顺序时,它修复了问题。诀窍是首先调用setVolumeThumbImage和setRouteButtonImage,然后调用setMinimumVolumeSliderImage和setMaximumVolumeSliderImage。

它处理了路线按钮上的重叠轨道。

但是,这引起了一个新问题,其中maximumSliderImage开始重叠volumeThumbImage!

最终解决方案是将拇指图层放在MPVolumeView的子类中,如下所示:

- (void)_initialize {
    UIImage *scrubber = [UIImage imageNamed:@"volume_scrubber_grip"];
    scrubberSize = scrubber.size;
    [self setVolumeThumbImage:scrubber forState:UIControlStateNormal];
    [self setRouteButtonImage:[UIImage imageNamed:@"airplay_button"] forState:UIControlStateNormal];
    [self setMinimumVolumeSliderImage:[UIImage imageNamed:@"min_slider"] forState:UIControlStateNormal];
    [self setMaximumVolumeSliderImage:[UIImage imageNamed:@"max_slider"] forState:UIControlStateNormal];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    [self.subviews enumerateObjectsUsingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
        if([obj isKindOfClass:[UISlider class]]) {
            UISlider *slider = (UISlider *)obj;
            [slider.subviews enumerateObjectsUsingBlock:^(UIView *obj2, NSUInteger idx, BOOL *stop2) {
                if(CGSizeEqualToSize(obj2.frame.size, scrubberSize)) {
                    [obj bringSubviewToFront:obj2];
                    *stop2 = YES;
                }
            }];
            *stop = YES;
        }
    }];
}

答案 2 :(得分:1)

我测试了另一种工作正常的解决方案。我将MPVolumeView嵌入到一个简单的UIView中(可以在故事板中创建)。然后我对UIView的属性“边界”进行键值观察。当此属性更改时,我将MPVolumeView的帧更新为UIView的新边界。

此解决方案可处理自动旋转和自动布局。

import UIKit
import MediaPlayerclass ViewController: UIViewController {

@IBOutlet weak var volumeViewContainer: UIView!

override func viewDidLoad() {
    super.viewDidLoad()
    volumeViewContainer.backgroundColor = UIColor.grayColor()
    var volumeView = MPVolumeView(frame: volumeViewContainer.bounds)
    volumeViewContainer.addSubview(volumeView)
    volumeViewContainer.addObserver(self, forKeyPath: "bounds", options: nil, context: nil)
}

override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
    if let subview = volumeViewContainer.subviews.first as? UIView {
    subview.frame = volumeViewContainer.bounds
    }
}

}

答案 3 :(得分:-2)

@IBOutlet var volumeViewHolder: UIView!

override func viewDidLoad() {
    super.viewDidLoad()
    volumeViewHolder.backgroundColor = UIColor.clearColor()
    var volumeView : MPVolumeView = MPVolumeView()
    volumeView.frame = volumeViewHolder.frame
    volumeView.center = volumeViewHolder.center
    volumeView.sizeToFit()
    volumeView.showsRouteButton = false
    volumeView.showsVolumeSlider = true
    volumeView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
    volumeViewHolder.addSubview(volumeView)

}