简体   繁体   English

自 IOS 13 起,UISearchController 在状态栏中意外绘制 UITableView

[英]UISearchController unexpected paint of UITableView in status bar since IOS 13

I have a very basic UITableController within a very basic UINavigationBar using a very basic UISearchController ( but hidesNavigationBarDuringPresentation = YES ).我在一个非常基本的 UINavigationBar 中有一个非常基本的 UITableController ,它使用一个非常基本的 UISearchController (但hidesNavigationBarDuringPresentation = YES )。 The issue I have is that if the search is active the UITableView scroll is visible in the statusbar.我遇到的问题是,如果搜索处于活动状态,则 UITableView 滚动在状态栏中可见。 Note that this behavior is new since IOS13, before due to the opaque search bar this didn't happen.请注意,这种行为是自 IOS13 以来的新行为,之前由于搜索栏不透明,这种行为没有发生。 It looks more like an IOS bug to me than the expected behavior.对我来说,它看起来更像是一个 IOS 错误而不是预期的行为。 Any suggestions how to fix this?任何建议如何解决这个问题? Ideally I'd like to have the same appearance like in IOS12 and before.理想情况下,我希望拥有与 IOS12 及之前相同的外观。

IOS 13, scrolling visible in statusbar IOS 13,滚动在状态栏中可见IOS 13,滚动在状态栏中可见

IOS 12, search bar half way opaque: no problem IOS 12、搜索栏中途不透明:没问题IOS 12,搜索栏不透明:没问题

#import <UIKit/UIKit.h>
@interface MyAppDelegate : UIResponder <UIApplicationDelegate,UITableViewDelegate,UITableViewDataSource,UISearchResultsUpdating>
{
  UIWindow* _win;
  UINavigationController* _nav;
  UITableViewController* _tc;
  NSMutableArray* _model;
  NSArray* _filteredModel;
  UISearchController* _search;
  UILabel* _label;
}
@end
@implementation MyAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  _win=[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  UIViewController* c=[[UIViewController alloc] init];
  UIView* v=c.view;
  v.backgroundColor=UIColor.whiteColor;
  _label=[[UILabel alloc] initWithFrame:CGRectMake(10, 100, 200, 20)];
  _model=[NSMutableArray array];
  _label.text=@"Tap on 'Show Table'";
  [v addSubview:_label];
  for (int i=0;i<200;i++) {
    _model[i]=[NSString stringWithFormat:@"Item %d",i];
  }
  _nav=[[UINavigationController alloc] initWithRootViewController:c];
  c.navigationItem.title=@"A title";
  UIBarButtonItem* b=[[UIBarButtonItem alloc] initWithTitle:@"Show Table" style:UIBarButtonItemStylePlain target:self action:@selector(showTable:)];
  c.navigationItem.rightBarButtonItem=b;
  _tc=[[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
  _tc.definesPresentationContext=YES; //have to do it for other reasons
  _search=[[UISearchController alloc] initWithSearchResultsController:nil];
  _search.obscuresBackgroundDuringPresentation=NO; //needed to be able to tap in results
  _search.hidesNavigationBarDuringPresentation=YES; //have to do it for other reasons
  _search.searchResultsUpdater=self;
  UITableView* tv=_tc.tableView;
  tv.delegate=self;
  tv.dataSource=self;
  tv.tableHeaderView=_search.searchBar;
  _win.rootViewController=_nav;
  [_win makeKeyAndVisible];
  return YES;
}
-(void)showTable:(UIBarButtonItem*)b {
  [_nav pushViewController:_tc animated:YES];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  _label.text=[NSString stringWithFormat:@"You selected row:%ld",(long)indexPath.row];
  [_nav popViewControllerAnimated:TRUE];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  return _search.active?_filteredModel.count:_model.count;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  static NSString* reuse=@"whatever";
  UITableViewCell* cell=[tableView dequeueReusableCellWithIdentifier:reuse];
  if (cell==nil) {
    cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuse];
  }
  NSInteger row=indexPath.row;
  cell.textLabel.text=_search.active?_filteredModel[row]:_model[row];
  return cell;
}
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController {
  NSString* searchText=searchController.searchBar.text;
  if (searchText.length==0) {
    _filteredModel=_model;
  } else {
    NSPredicate *predicate = [NSPredicate predicateWithFormat:
                                              @"SELF contains[c] %@",searchText];
    _filteredModel=[_model filteredArrayUsingPredicate:predicate];
  }
  [_tc.tableView reloadData];
}
@end
int main(int argc, char * argv[]) {
  @autoreleasepool {
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([MyAppDelegate class]));
  }
}

The reason for this (mis)behavior is that on IOS13 the UISearchBarBackground view does not cover the status bar anymore.这种(错误)行为的原因是在 IOS13 上UISearchBarBackground视图不再覆盖状态栏。 It did cover it in previous IOS versions.它在之前的 IOS 版本中确实涵盖了它。

IOS12 UISearchBarBackground covering the whole upper area IOS12 UISearchBarBackground覆盖整个上层区域覆盖整个上部区域

IOS13 UISearchBarBackground not covering the statusbar IOS13 UISearchBarBackground不覆盖状态栏仅覆盖状态栏本身

The solution I came up with without touching any other ViewController hierarchies in my code was a pretty nasty hack, extending the frame of the UISearchBarBackground to match with the state in pre IOS13 versions.我在代码中没有触及任何其他 ViewController 层次结构的情况下提出的解决方案是一个非常讨厌的 hack,扩展UISearchBarBackground的框架以匹配 IOS13 之前版本中的 state。

-(void)updateSearchResultsForSearchController:(UISearchController *)searchController {
  NSString* searchText=searchController.searchBar.text;
  if (@available(iOS 13.0, *)) {
    if (searchController.active) {
      //The intrinsic UISearchBar code seems to adjust the
      //background view of UISearchBar later on thats why we
      //need to delay
      [self performSelector:@selector(adjustBg) withObject:nil afterDelay:0.1];
    }
  }
  if (searchText.length==0) {
    _filteredModel=_model;
  } else {
    NSPredicate *predicate = [NSPredicate predicateWithFormat:
                                              @"SELF contains[c] %@",searchText];
    _filteredModel=[_model filteredArrayUsingPredicate:predicate];
  }
  [_tc.tableView reloadData];
}
CGPoint pointInScreen(UIView* v,CGPoint pt)
{
  CGPoint ptWin=[v.superview convertPoint:pt toView:nil];
  CGPoint ptScreen=[v.window convertPoint:ptWin toWindow:nil];
  return ptScreen;
}
-(void)adjustBg
{
  //ugly: we try to adjust the background view of the UISearchBar
  //to the top of the screen (like it was in pre IOS13 times)
  if (!_search.active) {
    return;
  }
  UISearchBar* bar=_search.searchBar;
  if (bar.subviews.count==0) { return; }
  UIView* first=bar.subviews[0];
  if (first.class!=UIView.class || first.subviews.count==0) { return;}
  UIView* bg=first.subviews[0];
  if ([bg isKindOfClass:NSClassFromString(@"UISearchBarBackground")]) {
    CGSize size=bg.frame.size;
    CGPoint orig=bg.frame.origin;
    CGPoint p=pointInScreen(bg,orig);
    CGPoint p2=pointInScreen(bg, CGPointMake(0, orig.y+size.height));
    if (p.y>0) { //not top of screen
      bg.frame=CGRectMake(orig.x,-p.y,size.width,p2.y);
    }
  }
}

It's really not the solution I was looking for, but as long there is no better one, I need to maintain that (and post it here in case someone else stumbles across that)这真的不是我正在寻找的解决方案,但只要没有更好的解决方案,我就需要保持它(并在此处发布以防其他人偶然发现)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM