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

Posted

技术标签:

【中文标题】自 IOS 13 以来,UISearchController 在状态栏中意外绘制 UITableView【英文标题】:UISearchController unexpected paint of UITableView in status bar since IOS 13 【发布时间】:2019-10-13 15:20:35 【问题描述】:

我在一个非常基本的 UINavigationBar 中有一个非常基本的 UITableController,它使用一个非常基本的 UISearchController(但 hidesNavigationBarDuringPresentation = YES)。 我遇到的问题是,如果搜索处于活动状态,则 UITableView 滚动在状态栏中可见。请注意,此行为是自 ios13 以来的新行为,之前由于搜索栏不透明,这没有发生。对我来说,它看起来更像是一个 IOS 错误,而不是预期的行为。 任何建议如何解决这个问题?理想情况下,我希望拥有与 IOS12 及之前相同的外观。

IOS 13,滚动可见状态栏

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]));
  

【问题讨论】:

我遇到了同样的问题,找不到合适的解决方案。 【参考方案1】:

这种(错误)行为的原因是在 IOS13 上,UISearchBarBackground 视图不再覆盖状态栏。它在之前的 IOS 版本中确实涵盖了它。

IOS12UISearchBarBackground覆盖整个上部区域

IOS13 UISearchBarBackground不覆盖状态栏

我在代码中不涉及任何其他 ViewController 层次结构的情况下提出的解决方案是一个非常讨厌的 hack,扩展了 UISearchBarBackground 的框架以匹配 IOS13 之前的版本中的状态。

-(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);
    
  

这确实不是我正在寻找的解决方案,但只要没有更好的解决方案,我就需要保持它(并在此处发布以防其他人偶然发现)

【讨论】:

以上是关于自 IOS 13 以来,UISearchController 在状态栏中意外绘制 UITableView的主要内容,如果未能解决你的问题,请参考以下文章

自 xCode 13 和 iOS 15 以来,Appium(和桌面)无法启动 wda 会话

自 iOS6 以来的按钮背景和渐变变化

故事板和“自 iOS 11.0 以来不推荐使用底部布局指南”警告

自 IOS 8 以来使用自动布局和滚动视图的额外顶部空白

自 iOS 12.2 更新以来没有崩溃报告的应用程序崩溃 [关闭]

Xamarin.Forms NavigationBar 颜色自 iOS 4.6 以来被覆盖