2

我已经实现了一个自定义的拆分视图控制器——原则上——它工作得很好。

然而,有一个方面不起作用那就是在 5.1 版本之前的 iOS 上调整工具栏的大小动画 - 如果存在:

在继承 UIToolbar 以覆盖其layoutSubviews方法后,对我的主要内容区域的宽度进行动画更改会导致工具栏项按预期移动。然而,工具栏的背景并没有按预期设置动画。

相反,它的宽度会立即更改为新值,从而在增加宽度的同时显示背景。

以下是我认为我使用的代码的相关部分——所有非常标准的东西,尽可能少的魔法/黑客:

// From the implementation of my Split Layout View Class:
- (void)setAuxiliaryViewHidden:(BOOL)hide animated:(BOOL)animated completion:(void (^)(BOOL isFinished))completion
{
auxiliaryViewHidden_ = hide;
    if (!animated)
    {
        [self layoutSubviews];
        if (completion)
            completion(YES);

        return;
    }

    // I've tried it with and without UIViewAnimationOptionsLayoutSubviews -- didn't change anything...
    UIViewAnimationOptions easedRelayoutStartingFromCurrentState = UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState;
    [UIView animateWithDuration:M_1_PI delay:0.0 options:easedRelayoutStartingFromCurrentState animations:^{
        [self layoutSubviews];
    } completion:completion];
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    // tedious layout work to calculate the frames for the main- and auxiliary-content views

    self.mainContentView.frame = mainContentFrame; // <= This currently has the toolbar, but...
    self.auxiliaryContentView.frame = auxiliaryContentFrame; // ...this one could contain one, as well.
}

// The complete implementation of my UIToolbar class:
@implementation AnimatableToolbar

static CGFloat sThresholdSelectorMargin = 30.;

- (void)layoutSubviews
{
    [super layoutSubviews];

    // walk the subviews looking for the views that represent toolbar items 
    for (UIView *subview in self.subviews)
    {
        NSString *className = NSStringFromClass([subview class]);
        if (![className hasPrefix:@"UIToolbar"]) // not a toolbar item view
            continue;

        if (![subview isKindOfClass:[UIControl class]]) // some other private class we don't want to f**k around with…
            continue;

        CGRect frame = [subview frame];
        BOOL isLeftmostItem = frame.origin.x <= sThresholdSelectorMargin;
        if (isLeftmostItem)
        {
            subview.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
            continue;
        }

        BOOL isRightmostItem = (CGRectGetMaxX(self.bounds) - CGRectGetMaxX(frame)) <= sThresholdSelectorMargin;
        if (!isRightmostItem)
        {
            subview.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;

            continue;
        }

        subview.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
    }
}

@end

我已经在 InterfaceBuilder 中设置了工具栏的类,我知道一个事实,这个代码被调用了,就像我说的,在 iOS 5.1 上一切正常。

不过,我必须从 4.2 版开始支持 iOS……</p>

非常感谢任何关于我所缺少的帮助/提示。

4

2 回答 2

1

据我所知,您的方法只能在 iOS SDK > 5 上工作。确实,iOS SDK 5 引入了UIToolbar以显式方式操作背景的可能性(参见setBackgroundImage:forToolbarPosition:barMetrics和相关的 getter 方法)。

在 iOS SDK 4 中,UIToolbar对象没有_UIToolbarBackground子视图,因此您无法在layoutSubviews实现中移动它。要验证这一点,请添加如下跟踪:

for (UIView *subview in self.subviews)
{
    NSLog(@"FOUND SUBVIEW: %@", [subview description]);

在 iOS 4 和 5 上运行代码,你就会明白我的意思了。

总而言之,您的问题的解决方案在于在 iOS 4 和 iOS 5 下以两种不同的方式处理背景。具体来说,在 iOS 4 上,您可以尝试以下方法:

  1. 向您的自定义添加一个子视图UIToolbar作为背景视图:

    [toolbar insertSubview:backgroundView atIndex:0];

  2. 放:

    toolbar.backgroundColor = [UIColor clearColor];

    这样 UIToolbar 背景颜色就不会干扰;

  3. 在您的layoutSubviews方法中,与其他子视图一起围绕此背景子视图制作动画,就像您正在做的那样;

当然,没有什么能阻止您在 iOS 5 中使用相同的背景子视图,唯一需要注意的是,在第 1 步中,子视图应插入到索引 1 处(即,在现有背景之上)。

希望这会有所帮助。

于 2012-05-17T08:02:00.610 回答
0

因为我认为这对其他人有用,所以我将我的解决方案放在这里以供参考:

UIImageView根据 sergio 的建议,我在视图层次结构中插入了一个附加项。但由于我希望它与默认的工具栏样式一起使用,我需要跳过几个环节:

  1. tintColor每当更改时,都需要动态生成图像。
  2. 在 iOS 5.0.x 上,工具栏背景是一个附加视图。

为了解决这个问题,我最终......</p>

  1. 实施+load以设置我是否需要做任何事情的静态 BOOL。(解析-[UIDevice systemVersion]5.1 之前的版本)。
  2. 为图像视图添加(延迟加载)属性stretchableBackground。如果nil我的静态标志是NO. 否则,视图将被创建为宽度的两倍[UIScreen mainScreen],向左偏移该宽度的一半,高度和右边距可调整大小,并插入到索引 0 处的工具栏。
  3. 压倒一切setTintColor:。每当发生这种情况时,我都会打电话给superand __updateBackground
  4. 实现了一个方法__updateBackground
    • 当工具栏响应backgroundImageForToolbarPosition:barMetrics:获取不是我们的第一个子视图时stretchableBackground。使用该contents视图层的属性来填充stretchableBackgroundimage属性并返回。
    • 如果工具栏没有响应该选择器,
      1. 用于CGBitmapContextCreate()获得一个 32 位 RGBA CGContextRef,其宽度为 1 个像素,高度为工具栏乘以屏幕比例。(使用 kCGImageAlphaPremultipliedLast 来处理设备 RGB 颜色空间……)
      2. 将 CTM 平移该高度并通过 scale/-scale 对其进行缩放以从 UIKit 过渡到 CG 坐标并将视图的图层绘制到该上下文中。(如果你不这样做,你的图像将永远是透明的空白......)
      3. 从该上下文创建一个 UIImage 并将其设置为stretchableBackground的图像。

请注意,iOS 5.0.x 的此修复在使用不同的背景图像用于纵向和横向或不缩放的图像时 将无法按预期工作- 尽管可以通过配置不同的图像视图来调整...</p>

于 2012-05-21T15:38:31.083 回答