8

所以我有一个我正在使用的 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 像素)

人像模式

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

横向模式

有人有什么想法吗?

4

4 回答 4

5

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

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

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

于 2013-10-19T12:04:22.680 回答
2

在做了很多实验之后,似乎 MPVolumeView 在 iOS 7.0.x 中的 bug 很大。

我遇到了一个问题,即为最小/最大滑块、音量拇指和路由设置自定义图像有时会导致滑块扩展以覆盖路由按钮。

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

这照顾了路线按钮上的重叠轨道。

但是,这导致了一个新问题,其中 maximumSliderImage 开始与 volumeThumbImage 重叠!

最终的解决方案是在 MPVolumeView 的子类中将 thumb 层置于最前面,如下所示:

- (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;
        }
    }];
}
于 2014-01-31T23:54:47.563 回答
2

我测试了另一种效果很好的解决方案。我嵌入了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
    }
}

}
于 2015-04-04T17:19:06.577 回答
-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)

}
于 2015-06-01T23:59:22.053 回答