簡體   English   中英

自 IOS 13 起,UISearchController 在狀態欄中意外繪制 UITableView

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

我在一個非常基本的 UINavigationBar 中有一個非常基本的 UITableController ,它使用一個非常基本的 UISearchController (但hidesNavigationBarDuringPresentation = YES )。 我遇到的問題是,如果搜索處於活動狀態,則 UITableView 滾動在狀態欄中可見。 請注意,這種行為是自 IOS13 以來的新行為,之前由於搜索欄不透明,這種行為沒有發生。 對我來說,它看起來更像是一個 IOS 錯誤而不是預期的行為。 任何建議如何解決這個問題? 理想情況下,我希望擁有與 IOS12 及之前相同的外觀。

IOS 13,滾動在狀態欄中可見IOS 13,滾動在狀態欄中可見

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

這種(錯誤)行為的原因是在 IOS13 上UISearchBarBackground視圖不再覆蓋狀態欄。 它在之前的 IOS 版本中確實涵蓋了它。

IOS12 UISearchBarBackground覆蓋整個上層區域覆蓋整個上部區域

IOS13 UISearchBarBackground不覆蓋狀態欄僅覆蓋狀態欄本身

我在代碼中沒有觸及任何其他 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);
    }
  }
}

這真的不是我正在尋找的解決方案,但只要沒有更好的解決方案,我就需要保持它(並在此處發布以防其他人偶然發現)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM