2

原則として、非常にうまく機能するカスタム Split View Controller を実装しました。

ただし、バージョン 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 ではすべて正常に動作することがわかっています。

iOS バージョン 4.2 以降をサポートする必要がありますが…</p>

私が欠けているものに関するヘルプ/ヒントは大歓迎です。

4

2 に答える 2

1

私が見る限り、あなたのアプローチは iOS SDK > 5 でのみ機能します。実際、iOS SDK 5 では、UIToolbarバックグラウンドを明示的な方法で操作する可能性が導入されました (setBackgroundImage:forToolbarPosition:barMetricsおよび相対ゲッター メソッドを参照)。

iOS SDK 4 では、UIToolbarオブジェクトにサブビューがないため、実装_UIToolbarBackground内でオブジェクトを移動できません。layoutSubviewsこれを確認するには、次のようなトレースを追加します。

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

コードを iOS 4 と 5 の両方で実行すると、私の言いたいことがわかるでしょう。

全体として、問題の解決策は、iOS 4 と iOS 5 で 2 つの異なる方法でバックグラウンドを処理することにあります。具体的には、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、ビュー階層に追加を挿入しました。しかし、これをデフォルトのツールバー スタイルで動作させたかったので、いくつかの手順を踏む必要がありました。

  1. が変更されるたびに、画像を動的に生成する必要がありtintColorました。
  2. iOS 5.0.x では、ツールバーの背景は追加のビューです。

これを解決するために、私は…</p>

  1. +load何かをする必要があるかどうかに静的 BOOL を設定する実装。-[UIDevice systemVersion]( 5.1 より前のバージョンの解析)。
  2. 画像ビューの (遅延ロードされた) プロパティを追加しますstretchableBackgroundnil私の静的フラグが の場合、ビューは になりますNO。それ以外の場合、ビューは の 2 倍の幅で作成され、[UIScreen mainScreen]その幅の半分だけ左にオフセットされ、高さと右マージンがサイズ変更可能になり、ツールバーのインデックス 0 に挿入されます。
  3. オーバーライドしsetTintColor:ます。これが発生するたびに、 と を呼び出しsuperます__updateBackground
  4. __updateBackground次のメソッドを 実装しました。
    • ツールバーが応答しbackgroundImageForToolbarPosition:barMetrics:て、私たちのものではない最初のサブビューを取得したときstretchableBackgroundcontentsそのビューのレイヤのプロパティを使用して、stretchableBackgroundのプロパティを設定しimageて返します。
    • ツールバーがそのセレクターに反応しない場合、
      1. 幅が 1 ピクセルで、高さがツールバーに画面のスケールを掛けたものでCGBitmapContextCreate()ある 32 ビット RGBA を取得するために使用します。CGContextRef(kCGImageAlphaPremultipliedLast を使用して、デバイスの RGB 色空間を操作します…)
      2. CTM をその高さで変換し、scale/-scale でスケーリングして UIKit から CG-Coordinates に移行し、ビューのレイヤーをそのコンテキストに描画します。(これを怠ると、画像は常に透明な空白になります...)
      3. そのコンテキストから UIImage を作成し、それをstretchableBackgroundの画像として設定します。

iOS 5.0.x のこの修正は、縦向きと横向きに異なる背景画像を使用する場合、または拡大 縮小されない画像を使用する場合、期待どおりに機能しないことに注意してください。

于 2012-05-21T15:38:31.083 に答える