我已经实现了一个自定义拆分视图控制器 - 原则上 - 运行良好。
然而,有一个方面是不工作是预期的,这是版本5.1之前iOS上工具栏的调整大小动画 - 如果存在:
在对UIToolbar进行子类化以覆盖其layoutSubviews
方法后,动画更改主内容区域的宽度会导致工具栏项按预期移动。然而,工具栏的背景 - 不按预期进行动画处理。
相反,它的宽度会立即变为新值,导致在增加宽度时显示背景。
以下是我认为我使用的代码的相关部分 - 所有非常标准的东西,尽可能少的魔法/ hackery:
// 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上一切正常。
我必须支持iOS启动版本4.2,但是......
非常感谢任何关于我所缺少的帮助/提示。
答案 0 :(得分:1)
据我所知,您的方法只适用于iOS SDK&gt; 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上,您可以尝试以下方法:
将子视图添加到充当背景视图的自定义UIToolbar
:
[toolbar insertSubview:backgroundView atIndex:0];
组:
toolbar.backgroundColor = [UIColor clearColor];
以便UIToolbar背景颜色不会干扰;
在您的layoutSubviews
方法中与其他子视图一起围绕此背景子视图进行动画处理,就像您正在做的那样;
当然,对于iOS 5来说,没有什么可以阻止你使用相同的背景子视图,只有你应该注意的是,在第1步,子视图应该插入索引1(即,在现有背景的顶部)。
希望这会有所帮助。
答案 1 :(得分:0)
由于我认为这对其他人有用,我会把我的解决方案放在这里以供参考:
根据塞尔吉奥的建议,我在视图层次结构中插入了一个额外的UIImageView
。但是因为我希望这可以使用默认的工具栏样式,所以我需要跳过几个环节:
tintColor
发生变化,就需要动态生成图像。为了解决这个问题,我结束了......
+load
以设置是否需要执行任何操作的静态BOOL。 (对于5.1之前的版本,解析-[UIDevice systemVersion]
。)。stretchableBackground
添加(延迟加载)属性。如果我的静态标记为nil
,则视图为NO
。否则创建的视图宽度为[UIScreen mainScreen]
的两倍,向左偏移该宽度的一半,并可调整高度和右边距,并插入到索引0处的工具栏中。setTintColor:
。每当发生这种情况时,我都会致电super
和__updateBackground
。__updateBackground
:
backgroundImageForToolbarPosition:barMetrics:
时,获取的第一个子视图不是我们的stretchableBackground
。使用该视图图层的contents
属性填充stretchableBackground
的{{1}}属性并返回。image
获取32位RGBA CGBitmapContextCreate()
,它是一个像素宽,并且与工具栏一样高,乘以屏幕的比例。 (使用kCGImageAlphaPremultipliedLast处理设备RGB颜色空间...)CGContextRef
的图像。请注意,当使用不同的背景图像作为纵向和横向或不缩放的图像时,iOS 5.0.x 的此修复程序将无法正常工作 - 尽管可以通过配置图像视图进行调整不同...