Interface Builderを使用してテーブルビューを作成し、それにライブラリの検索バーと検索表示コントローラーを追加して、検索機能を追加しました。ただし、IBは、ビューが最初に表示されたときにバーが画面の上部に表示されるように設定しました。
デフォルトで検索バーを非表示にする方法を知りたいのですが、テーブルビューでスクロール可能です(例については、Appleのメールアプリケーションを参照してください)。 viewDidLoad
のscrollRectToVisible:animated:
を呼び出して、テーブルビューを下にスクロールしようとしましたが、効果がありませんでした。デフォルトで検索バーを非表示にする好ましい方法は何ですか?
まず、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
は例外を発生させます)。
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];
}
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];
この解決策には多くの答えがありますが、私にとって非常にうまく機能するものはありませんでした。
これは完全に機能します。アニメーションなし、-viewDidLoad
に行われます
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.contentOffset = CGPointMake(0, self.searchBar.frame.size.height - self.tableView.contentOffset.y);
}
注:
コードは、検索バーにリンクされているsearchBar
@property
があることを前提としています。そうでない場合は、代わりにself.searchDisplayController.searchBar
を使用できます
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)
_
私の目標は、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()
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で実際に機能する唯一の回避策です。きちんとした解決策があるかどうか知りたいです。
上記のどれも私には役に立たなかったので、誰かが同じ問題を抱える場合に備えて。
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だけが正しい位置に移動しました
テーブルビューにデータがない場合、受け入れられた回答はクラッシュすることに注意してください。また、特定の状況では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)];
}
正直なところ、どの答えも実際に問題を解決しませんでした(私にとって)。テーブルビューに行がない場合OR行の高さが異なる場合、これらの答えでは不十分です。
動作する唯一のもの:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.tableView.contentOffset = (CGPoint){.y = self.tableView.contentOffset.y + self.searchController.searchBar.frame.size.height};
}
この質問に対する他の回答は、私にはまったく機能しませんでした、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が表示されるかどうかを確認します(つまり、スクロール位置であるy
のcontentOffset
位置は0
)。もしそうなら、単にsearchBarの高さをスクロールダウンします。 searchBarが表示されていない場合(tableView
の項目のより大きなリストを考えてください)、tableView
をスクロールしようとはしません。ネストされた広告申込情報。
サイドノート
単一の責任を確保し、コード内でいつでも呼び出すための再利用性を確保するために、このコードを別のメソッドに配置することをお勧めします。
以下のコードは私のために働いています
self.tableView.contentOffset = CGPointMake(0.0, 44.0);
テーブルに常に少なくとも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
}
テーブルに行がない場合、scrollToRowAtIndexPath
メソッドはクラッシュを引き起こします。
UITableViewは単なるスクロールビューなので、コンテンツオフセットを簡単に変更できます。
これは、tableHeaderViewとして検索バーがあることを確認し、スクロールして非表示にすることを想定しています
if let searchHeight = tableView.tableHeaderView?.frame.height {
tableView.setContentOffset(CGPoint.init(x: 0, y:searchHeight ), animated: false)
}
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];
}
お役に立てれば :-)
コンテンツオフセットと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)
}
}
これは魅力的なものでした。コンテンツのオフセット設定は、スムーズなスクロールを目的としています。
TableViewの境界を変更します。これはviewDidLoad
内で行うことができ、さらに(例外を回避するために)テーブルが空かどうかを心配する必要はありません。
CGRect newBounds = self.tableView.bounds;
newBounds.Origin.y = newBounds.Origin.y + self.searchBar.bounds.size.height;
self.tableView.bounds = newBounds;
ユーザーが表を下にスクロールすると、検索バーが表示され、正常に動作します
同様の問題がありました。そして、この問題を解決するために私が見つけた唯一の方法は、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"];
}
Swiftの場合:
TableviewのコンテンツをYオフセットするだけで、検索バーの高さのようになります。
self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height)
スイフト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)
}
ステータスバーおよびナビゲーションバーを考慮することを忘れないでください。私のTable View ControllerはNavigation ControllerのviewDidAppear
に組み込まれています:
tableView.contentOffset = CGPointMake(0, -20) // -20 = 44 (search bar height) - 20 (status bar height) - 44 (navigation bar height)
私のために働いた。