UISearchController неожиданно рисует UITableView в строке состояния начиная с IOS 13 - PullRequest
0 голосов
/ 13 октября 2019

У меня есть очень простой UITableController в очень простой UINavigationBar, использующий очень простой UISearchController (но hidesNavigationBarDuringPresentation = YES). У меня проблема в том, что, если поиск активен, прокрутка UITableView видна в строке состояния. Обратите внимание, что это поведение является новым с IOS13, ранее из-за непрозрачной панели поиска этого не происходило. Для меня это больше похоже на ошибку IOS, чем на ожидаемое поведение. Любые предложения, как это исправить? В идеале я хотел бы иметь такой же внешний вид, как в IOS12 и ранее.

IOS 13, прокрутка видна в строке состояния IOS 13, scrolling visible in statusbar

IOS 12, строка поиска наполовину непрозрачна: нет проблем IOS 12, search bar opaque: no problem

#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 Ответ

0 голосов
/ 16 октября 2019

Причина этого (неправильного) поведения заключается в том, что на IOS13 представление UISearchBarBackground больше не покрывает строку состояния. В предыдущих версиях IOS он действительно освещался.

IOS12 UISearchBarBackground, охватывающий всю верхнюю область covers the whole upper area

IOS13 UISearchBarBackground, не покрывающий строку состояния covers only the status bar itself

Решение, которое я придумал, не затрагивая другие иерархии ViewController в моем коде, было довольно неприятным хаком: расширение фрейма 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);
    }
  }
}

Это действительноне то решение, которое я искал, но пока нет лучшего, мне нужно сохранить его (и опубликовать здесь, если кто-то другой наткнется на это)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...