web-dev-qa-db-ja.com

iPhone:デフォルトでUITableView検索バーを非表示

Interface Builderを使用してテーブルビューを作成し、それにライブラリの検索バーと検索表示コントローラーを追加して、検索機能を追加しました。ただし、IBは、ビューが最初に表示されたときにバーが画面の上部に表示されるように設定しました。

デフォルトで検索バーを非表示にする方法を知りたいのですが、テーブルビューでスクロール可能です(例については、Appleのメールアプリケーションを参照してください)。 viewDidLoadscrollRectToVisible:animated:を呼び出して、テーブルビューを下にスクロールしようとしましたが、効果がありませんでした。デフォルトで検索バーを非表示にする好ましい方法は何ですか?

85
Tim

まず、UISearchBarをUITableViewのtableHeaderViewに追加して、テーブルのコンテンツでスクロールされ、ビューの上部に固定されないようにします。

検索バーは、TableViewの行としてカウントされないため、TableViewの上部を最初の行までスクロールすると、検索バーが「非表示」になります。

[yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];

またはSwiftで:

yourTableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: false)

データが含まれる前にtableviewをスクロールしないようにしてください(指定されたindexPathが有効な行をポイントしていない場合(つまり、tableviewが空の場合)scrollToRowAtIndexPathは例外を発生させます)。

115
Zargony

UITableBarをUITableViewのサブビューとして追加しないでください。これは必要ありません。

UITableViewには、これに最適なtableHeaderViewプロパティがあります。

- (void) viewDidLoad {
    [super viewDidLoad]; 
    self.searchBar = [[[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)] autorelease];
    self.searchBar.showsCancelButton = YES;    
    self.searchBar.delegate = self;
    self.tableView.tableHeaderView = self.searchBar;     
}

デフォルトで表示したくない場合:

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.tableView setContentOffset:CGPointMake(0, 44)];
}

また、キャンセルボタンを表示して、非表示にします。(キーボードを削除します)

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
    [self.tableView setContentOffset:CGPointMake(0, 44) animated:YES];
    [self.searchBar resignFirstResponder];
}
45
bandejapaisa

ContentOffsetは、TimとJoe D'Andreaのコメントに記載されていますが、これは検索バーを非表示にするアニメーションを追加することで少し拡張されています。検索バーが消えるのは少し予想外であることに気付きました。

iOS 4.0以降をターゲットにしたい人のための小さなアップデート、これを試してください:

[UIView animateWithDuration:0.4 animations:^{
    self.tableView.contentOffset = CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height);
 } completion:nil];

前の答え:

[UIView beginAnimations:@"hidesearchbar" context:nil];
[UIView setAnimationDuration:0.4];
[UIView setAnimationBeginsFromCurrentState:YES];

self.tableView.contentOffset = CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height);

[UIView commitAnimations];
25
Andrei

この解決策には多くの答えがありますが、私にとって非常にうまく機能するものはありませんでした。

これは完全に機能します。アニメーションなし、-viewDidLoadに行われます

 - (void)viewDidLoad {
     [super viewDidLoad];
     self.tableView.contentOffset = CGPointMake(0,  self.searchBar.frame.size.height - self.tableView.contentOffset.y);
 }

注:

コードは、検索バーにリンクされているsearchBar@propertyがあることを前提としています。そうでない場合は、代わりにself.searchDisplayController.searchBarを使用できます

7
code ninja

Swift 3+

これは私がしました:

これを宣言しますvar

_    var searchController = UISearchController()
_

そしてviewDidLoad()メソッドで

_    searchController = UISearchController(searchResultsController: nil)
    searchController.searchResultsUpdater = self
    searchController.hidesNavigationBarDuringPresentation = false
    searchController.dimsBackgroundDuringPresentation = true
    searchController.searchBar.placeholder = NSLocalizedString("Search", comment: "")
    definesPresentationContext = true
    tableView.tableHeaderView = searchController.searchBar

    tableView.contentOffset = CGPoint(x: 0, y: searchController.searchBar.frame.size.height)
_
6
Dasoga

私の目標は、View Controllerが読み込まれたときにストーリーボード内のプレーンTableViewスタイルのtableHeaderViewに追加された検索バーを非表示にし、ユーザーがUITableViewの上部を下にスクロールしたときにバーを表示することでした。したがって、私はSwiftを使用しており、拡張機能を追加しています。

extension UITableView {
    func hideSearchBar() {
        if let bar = self.tableHeaderView as? UISearchBar {
            let height = CGRectGetHeight(bar.frame)
            let offset = self.contentOffset.y
            if offset < height {
                self.contentOffset = CGPointMake(0, height)
            }
        }
    }
}

in viewDidLoad()単に呼び出す:

self.tableView.hideSearchBar()
5
HotJard

コンテンツオフセットを使用する方法がありますが、100%の時間は機能しません。

estimatedRowHeightを固定数に設定している場合は機能しません。回避策はまだわかりません。私は project を作成して問題を表示し、Appleで radar を作成しました。

Swiftすべての設定方法の例が必要な場合は、プロジェクトをチェックしてください。

4
RyanJM

IOSはこの状況でインセットを自動的に調整するため、tableViewを満たすのに十分な行がない場合、iOS 8では既存のすべてのソリューションが機能しません。 (ただし、十分な行がある場合は既存の回答が適しています)

この問題で6時間も無駄にした後、ようやくこの解決策を得ました。

要するに、十分なセルがない場合は、tableViewに空のセルを挿入する必要があります。そのため、tableViewのコンテンツサイズはiOSがインセットを調整できないほど大きいです。

これが私がSwiftでどのようにしたかです:

1.)変数minimumCellNumをクラスプロパティとして宣言する

_var minimumCellNum: Int?
_

2.)minimumCellNumを計算し、viewWillAppearに_tableView.contentOffset_を設定します

_let screenHeight = Int(UIScreen.mainScreen().bounds.height)

// 101 = Height of Status Bar(20) + Height of Navigation Bar(44) + Height of Tab Bar(49)
// you may need to subtract the height of other custom views from the screenHeight. For example, the height of your section headers.
self.minimumCellNum = (screenHeight - 103 - heightOfOtherCustomView) / heightOfYourCell
self.tableView.contentOffset = CGPointMake(0, 44)
_

3.)tableView(tableView: UITableView, numberOfRowsInSection section: Int))

_let numOfYourRows = YOUR LOGIC
if numOfYourRows > minimumCellNum {
    return numOfYourRows
} else {
    return minimumCellNum!
}
_

4.)selection属性がNoneである空のセルをストーリーボードとtableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)に登録します

_if indexPath.row < numOfYourRows {
    return YOUR CUSTOM CELL
} else {
    let cell = tableView.dequeueReusableCellWithIdentifier("EmptyCell", forIndexPath: indexPath) as! UITableViewCell
    return cell
}
_

5.)tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)

_if tableView == self.tableView {
    if numOfYourRows < (indexPath.row + 1) {
        return
    }
    YOUR LOGIC OF SELECTING A CELL
}
_

これは完璧な解決策ではありませんが、iOS 8で実際に機能する唯一の回避策です。きちんとした解決策があるかどうか知りたいです。

4
Brian

上記のどれも私には役に立たなかったので、誰かが同じ問題を抱える場合に備えて。

IOS7のグループ化されたテーブルでsearchBarとしてtableHeaderViewとして設定しています。 viewDidLoadには、searchBarを最初に「非表示」に保つtableView.contentOffset = CGPointMake(0, 44);があります。ユーザーが下にスクロールすると、searchBarが表示されます

目標:キャンセルボタンタップでsearchBarを非表示にする

searchBarCancelButtonClicked(searchBar: UISearchBar!)

これは機能しませんでした: _[yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];_ tableViewのスクロールが大きすぎたため、ToolBarの後ろに行0が表示されました。

これは機能しませんでした:tableView.ContentOffset = CGPointMake(0, 44)-何も起こりません

これは機能しませんでした:tableView.ContentOffset = CGPointMake(0, searchBar.frame.size.height)-何も起こりません

これは機能しませんでした:tableView.setContentOffset(CGPointMake(0, 44), animated: true);再びtableViewが上にスクロールしすぎたため、行0がtoolBarの後ろになりました。

これは部分的に機能しました:tableView.setContentOffset(CGPointMake(0, 0)titleForHeaderInSectionはtoolBarの背後にありました

これは機能しました:tableView.setContentOffset(CGPointMake(0, -20)

論理的ではないようですが、-20だけが正しい位置に移動しました

4
grep

テーブルビューにデータがない場合、受け入れられた回答はクラッシュすることに注意してください。また、特定の状況ではviewDidLoadに追加できない場合があります。

[yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; // crashes if no rows/data

したがって、代わりに次のコード行を追加します。

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    [yourTableView setContentOffset:CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height)];
}
3
user3246173

正直なところ、どの答えも実際に問題を解決しませんでした(私にとって)。テーブルビューに行がない場合OR行の高さが異なる場合、これらの答えでは不十分です。

動作する唯一のもの:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    self.tableView.contentOffset = (CGPoint){.y =  self.tableView.contentOffset.y + self.searchController.searchBar.frame.size.height};
}
2
p0lAris

この質問に対する他の回答は、私にはまったく機能しませんでした、tableViewに0行があると奇妙な動作をした、または親とネストされたラインアイテムの間を行き来するときにスクロール位置を台無しにしました。これは私にとってはうまくいきました(目標はロード時にUISearchBarを非表示にすることです):

public override func viewWillAppear(animated: Bool) {        
    if self.tableView.contentOffset.y == 0 {
        self.tableView.contentOffset = CGPoint(x: 0.0, y: self.searchBar.frame.size.height) 
    }
}

説明
tableViewが表示されるたびに、このコードはUISearchBarが表示されるかどうかを確認します(つまり、スクロール位置であるycontentOffset位置は0)。もしそうなら、単にsearchBarの高さをスクロールダウンします。 searchBarが表示されていない場合(tableViewの項目のより大きなリストを考えてください)、tableViewをスクロールしようとはしません。ネストされた広告申込情報。

サイドノート
単一の責任を確保し、コード内でいつでも呼び出すための再利用性を確保するために、このコードを別のメソッドに配置することをお勧めします。

1
kbpontius

以下のコードは私のために働いています

self.tableView.contentOffset = CGPointMake(0.0, 44.0);
1
Ashu

テーブルに常に少なくとも1つの行がある場合は、テーブルの最初の行までスクロールするだけで、検索バーは自動的に非表示になります。

let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0)

self.tableView.selectRowAtIndexPath(firstIndexPath、animated:false、scrollPosition:.Top)

上記のコードをviewDidLoadに配置すると、tableViewがまだロードされていないためエラーがスローされます。したがって、この時点でviewDidAppear tableViewはすでにロードされています。

viewDidAppearに配置すると、tableViewを開くたびに上部にスクロールします。

たぶん、tableViewがUITabBar View Controllerであるときや、セグエを実行してから戻ってきたときなど、tableViewが開いたままの場合、この動作は望ましくありません。最初のロードで一番上までスクロールするだけの場合は、変数を作成して、それが最初のロードであるかどうかを確認して、一度だけ一番上までスクロールできるようにします。

最初に、View ControllerクラスでisInitialLoadという変数を定義し、「true」に設定します。

var isInitialLoad = true

次に、viewDidAppearでisInitialLoadがtrueであるかどうかを確認し、trueである場合は、一番上までスクロールしてisInitialLoad変数をfalseに設定します。

if isInitialLoad {
            let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0)
            self.tableView.selectRowAtIndexPath(firstIndexPath, animated: false, scrollPosition: .Top)

            isInitialLoad = false
        }
1
drdrdrdr

テーブルに行がない場合、scrollToRowAtIndexPathメソッドはクラッシュを引き起こします。

UITableViewは単なるスクロールビューなので、コンテンツオフセットを簡単に変更できます。

これは、tableHeaderViewとして検索バーがあることを確認し、スクロールして非表示にすることを想定しています

    if let searchHeight = tableView.tableHeaderView?.frame.height {
        tableView.setContentOffset(CGPoint.init(x: 0, y:searchHeight ), animated: false)
    }
1
Confused Vorlon

TableViewが空白の場合、「Notes」アプリはアイテムを検索できません。ですから、最初は空のテーブルを追加するために-(void)addSubview:(UIView *)viewを使用しているだけだと思います。データソース配列にアイテムを追加すると、別のコードが実行されてtableViewが読み込まれます。

だから私の解決策は:

if([self.arrayList count] > 0)
{
     [self.tableView reloadData];     //use jdandrea's code to scroll view when cell==nil in cellForRowAtIndexPath
     self.tableView.scrollEnabled = YES;
}
else
{
     tableBlank = [[UITableView alloc]initWithFrame:CGRectMake(0,0,320,416) style:UITableViewStylePlain] autorelease];
     tableBlank.delegate = self;
     tableBlank.dataSource = self;
     [self.view addSubview:tableBlank];
}

お役に立てれば :-)

1
Chilly Zhong

コンテンツオフセットとscrollToIndexpathを設定しようとしましたが、何もうまくいきませんでした。 tableHeaderViewの設定をsearchDidLoadからsearchBarとして削除し、以下のようにscrollviewデリゲートに設定しました

override func scrollViewWillBeginDragging(scrollView: UIScrollView) {
    if scrollView.contentOffset.y < 0 && tableView.tableHeaderView == nil {
        tableView.tableHeaderView = searchController.searchBar
        tableView.setContentOffset(CGPointMake(0, scrollView.contentOffset.y + searchController.searchBar.frame.size.height), animated: false)
    }
}

これは魅力的なものでした。コンテンツのオフセット設定は、スムーズなスクロールを目的としています。

1
Abdur Rahman

TableViewの境界を変更します。これはviewDidLoad内で行うことができ、さらに(例外を回避するために)テーブルが空かどうかを心配する必要はありません。

CGRect newBounds = self.tableView.bounds;
newBounds.Origin.y = newBounds.Origin.y + self.searchBar.bounds.size.height;
self.tableView.bounds = newBounds;

ユーザーが表を下にスクロールすると、検索バーが表示され、正常に動作します

1
LightMan

同様の問題がありました。そして、この問題を解決するために私が見つけた唯一の方法は、UITableView contentOffsetプロパティでキー値オブザーバーを使用することでした。

デバッグ後、テーブルビューのコンテンツサイズがテーブルビューよりも小さい場合に問題が発生することに気付きました。 viewWillAppearでKVOを起動します。ビューが表示されてから0.3秒後にKVOがディスパッチを停止します。 contentOffsetが0.0になるたびに、KVOは反応し、検索バーの高さにcontentOffsetを設定します。ビューが表示された後でもビューレイアウトがcontentOffsetをリセットするため、0.3秒後にKVO非同期を停止します。

- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated];
  [self.tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}

-(void)viewDidAppear:(BOOL)animated{
   __weak typeof (self) weakSelf = self;
   dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [weakSelf.tableView removeObserver:self forKeyPath:@"contentOffset"];});
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if ([keyPath isEqualToString:@"contentOffset"] && self.tableView.contentOffset.y == 0.0) {
       self.tableView.contentOffset = CGPointMake(0, CGRectGetHeight(self.tableView.tableHeaderView.frame));
    }
}

-(void)dealloc {
    [self.tableView removeObserver:self forKeyPath:@"contentOffset"];
}
0
slobodans

Swiftの場合:

TableviewのコンテンツをYオフセットするだけで、検索バーの高さのようになります。

self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height)
0
stakahop

スイフト3

空のテーブルでも動作します!

私の環境では、xibファイルによってカスタムセルをロードし、rowHeightは自動的に設定されます。

    override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        self.tableView.contentOffset = CGPoint(x: 0, y: self.tableView.contentOffset.y + self.searchController.searchBar.bounds.height)
}
0
John

ステータスバーおよびナビゲーションバーを考慮することを忘れないでください。私のTable View ControllerはNavigation ControllerのviewDidAppearに組み込まれています:

tableView.contentOffset = CGPointMake(0, -20) // -20 = 44 (search bar height) - 20 (status bar height) - 44 (navigation bar height)

私のために働いた。

0
fujianjin6471