web-dev-qa-db-ja.com

タイトルを中心としたUINavigationItem

両側に左と右の両方のバーボタンがあるナビゲーションバーがあります。 customTitlelabelのtitleViewとして設定したUINavigationItemがあります。

[self.navigationItem setTitleView:customTitleLabel];

今はすべて元気です。問題は、rightbarButtonのサイズが、テキストフィールドの1つで取得した入力に基づいて動的になることです。

したがって、タイトルはボタン間の使用可能なスペースに基づいて自動的に中央に配置されます。

タイトルを固定位置に設定するにはどうすればよいですか?

20
Neelesh

あなたが直接やりたいことを行うことはできません-タイトルビューの位置はあなたのコントロールの外にあります(UINavigationBarによって管理されている場合)。

ただし、必要な効果を得るには、少なくとも2つの方法があります。

1)タイトルビューを、ナビゲーションバーの「適切な」タイトルビューとしてではなく、UINavigationBarのサブビューとして追加します。 (注:これは「公式」に認可されたわけではありませんが、私はそれが完了し、機能することを確認しました。明らかに、タイトルラベルがボタンのビットを上書きすることに注意し、さまざまな方向のさまざまなサイズのナビゲーションバーなどを処理する必要があります。 -少し手間がかかります。)

2)完全に画面の中央に配置されたサブビューを効果的に表示するように計算された位置に特定のサブビュー(UILabelとなる)を表示するインテリジェントなUIViewサブクラスを作成します。これを行うために、インテリジェントUIViewサブクラスは、ラベルサブビューの位置(frame)を変更することにより、レイアウトイベント(またはframeプロパティの変更など)に応答します。

個人的に、私はアプローチ2)のアイデアが好きです。

15
occulus

ナビゲーションバーのtitleViewプロパティの設定は問題なく機能します。カスタムビューのフレーム以外のフレームをサブクラス化したり変更したりする必要はありません。

UINavigationBarの幅全体に対して中央に配置するコツは、次のとおりです。

  1. テキストのサイズに応じてビューの幅を設定します
  2. 配置を中央揃えに設定し、
  3. 自動サイズ変更マスクを設定して、使用可能なスペースにサイズ変更する

以下は、向き、左または右のバーボタンの幅に関係なく、UINavigationBarの中央に配置されたままのラベルを持つカスタムtitleViewを作成するコードの例です。

self.title = @"My Centered Nav Title";

// Init views with rects with height and y pos
CGFloat titleHeight = self.navigationController.navigationBar.frame.size.height;
UIView *titleView = [[UIView alloc] initWithFrame:CGRectZero];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];

// Set font for sizing width
titleLabel.font = [UIFont boldSystemFontOfSize:20.f];

// Set the width of the views according to the text size
CGFloat desiredWidth = [self.title sizeWithFont:titleLabel.font
                            constrainedToSize:CGSizeMake([[UIScreen mainScreen] applicationFrame].size.width, titleLabel.frame.size.height)
                                lineBreakMode:UILineBreakModeCharacterWrap].width;

CGRect frame;

frame = titleLabel.frame;
frame.size.height = titleHeight;
frame.size.width = desiredWidth;
titleLabel.frame = frame;

frame = titleView.frame;
frame.size.height = titleHeight;
frame.size.width = desiredWidth;
titleView.frame = frame;

// Ensure text is on one line, centered and truncates if the bounds are restricted
titleLabel.numberOfLines = 1;
titleLabel.lineBreakMode = UILineBreakModeTailTruncation;
titleLabel.textAlignment = NSTextAlignmentCenter;

// Use autoresizing to restrict the bounds to the area that the titleview allows
titleView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
titleView.autoresizesSubviews = YES;
titleLabel.autoresizingMask = titleView.autoresizingMask;

// Set the text
titleLabel.text = self.title;

// Add as the nav bar's titleview
[titleView addSubview:titleLabel];
self.navigationItem.titleView = titleView;
28
followben
override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.navigationBar.topItem?.title = ""
}

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    navigationItem.title = "Make peace soon"
}
12
neoneye

正しい答えは、sizeThatFits:をカスタムtitleViewのコンテンツサイズとして返します。ナビゲーションバーは、そのためのスペースがなくなるまでカスタムタイトルビューを中央に配置します。

たとえば、内部にUIViewを含むUILabelコンテナがある場合:

@interface CustomTitleView : UIView

@property UILabel* textLabel;

@end

@implementation CustomTitleView

- (CGSize)sizeThatFits:(CGSize)size {
    CGSize textSize = [self.textLabel sizeThatFits:size];
    CGSize contentSize = size;
    contentSize.width = MIN( size.width, textSize.width );

    return contentSize;
}

@end
3
highmaintenance

私はaopsfanの答えを試しましたが、うまくいきませんでした。ブレークポイントにより、バーの中心が "(480.0、22.0)"(X座標はオフ)であることがわかりました。

だから私はそれをこれに変えました:

- (void)layoutSubviews 
{
    [super layoutSubviews];

    // Center Title View

    UINavigationItem* item = [self topItem]; // (Current navigation item)

    [item.titleView setCenter:CGPointMake(160.0, 22.0)]; 
    // (...Hard-coded; Assuming portrait iPhone/iPod touch)

}

...そしてそれは魅力のように機能します。ビューコントローラーを押したときのスライド/フェード効果はそのままです。 (iOS 5.0)

2
Nicolas Miari

同様の問題がありました。 enter image description here 私の解決策は、元の戻るボタンを非表示にし、独自の実装を追加することです。システムは左のアイテムのためにスペースを予約するので。

UIImage* cancelIcon = [UIImage imageNamed:@"ic_clear"];
UIBarButtonItem* cancelButton = [[UIBarButtonItem alloc] initWithImage:cancelIcon style:UIBarButtonItemStylePlain target:self action:@selector(back:)];

セレクターはシンプルです

- (void)back:(UIButton *) sender
{
    [self.navigationController popViewControllerAnimated:YES];
}

これは次のようになります: enter image description here

ああ...そして、ラベルのような動的な長さのコンテンツがある場合は、カスタムタイトルビューで自動レイアウトを使用することを忘れないでください。カスタムビューに追加のレイアウトを追加して、Androidの中央に配置し、先頭と末尾のスペースを "> =" 0に設定することで、「wrap_content」のようにします。

enter image description here

1
Nevin Chen

titleViewをUINavigationBarの中央に配置する必要がある同様の状況がありました。 UIViewをサブクラス化し、setFrame:をオーバーライドするというocculusのアプローチが好きです。次に、フレームをUINavigationBarの寸法の中央に配置します。

UIViewサブクラスで:

-(void)setFrame:(CGRect)frame{
  super.frame = CGRectMake(320 / 2 - 50, 44 / 2 - 15, 100, 30);
}

その後、UIViewサブクラスは、通常、各navigationItemのtitleViewに割り当てることができます。開発者は、プログラムで特別なサブビューをUINavigationBarに追加および削除する必要はありません。

0
Richard H Fung