10

私は そのとして持っUITableViewControllerています。また、それをそのとして、それをそのとして初期化しました。これまでのところ、すべてがほぼ機能しています。UISearchBartableHeaderViewtableViewUISearchDisplayControllerUISearchBarsearchBarUITableViewControllercontentsController

問題は、に設定されUITableViewているセルがあることです。何が起こるかです:accessoryTypeUITableViewCellAccessoryDetailDisclosureButton

  1. まず、すべてが適切に表示されます。
    ここに画像の説明を入力してください
  2. ユーザーは内をタップしUISearchBarます。
  3. はメインテーブルのUISearchDisplayController上に暗いオーバーレイを作成し、メインテーブルのインデックス(のようにsectionIndexTitlesForTableView)を非表示にします。
  4. この時点でユーザーがキーボードを非表示にするとします(標準キーボードのiPadの「キーボードを非表示」ボタンを押します)。
  5. ユーザーはまだ何も入力していないので、UISearchBarによって追加された暗いオーバーレイの下にありますが、メインテーブルは引き続き表示されますUISearchDisplayController
  6. キーボードを非表示にすると、メインテーブルがより多く表示され、メインテーブルがより多くのセルをロードするようになります。
  7. ここで問題があります。メインテーブルのインデックスが非表示になっているときにこれらのセルが読み込まれるため、開示ボタンが右に表示されすぎます(少なくとも他のセルと比較して)。
    ここに画像の説明を入力してください
  8. さらに、ユーザーが検索をキャンセルすると、それらのセルが再ロードされず、インデックスの下に開示ボタンが表示される場合があります(これが再び表示されます)。
    ここに画像の説明を入力してください

私はこれを回避する方法に迷っています。私が考えることができる唯一のオプションは、開示ボタンに対応するUIViewを見つけて手動で移動することですが、UIViewを見つけるだけでも厄介なハックが必要なため、それは信じられないほどハッキーに思えます。これをより良い方法で修正する方法についての提案は大歓迎です!

実行可能な最小限の例

以下は最小限の例です。新しいXCodeプロジェクトを開始し、ARC、iPadのみを有効にして、AppDelegateのコンテンツを以下に置き換えます。最小限の例のために、メインテーブルにセルを強制的にリロードすることに注意してくださいsearchDisplayController:willShowSearchResultsTableView。そうしないと、メインテーブルがセルをキャッシュし、問題が表示されません(実際のアプリケーションでは、メインテーブルは他の理由でセルをリロードしています、理由は完全にはわかりませんが、もちろん、メインテーブルがいつでもセルをリロードしても問題ないはずです。)

問題が発生していることを確認するには、コードを実行し、検索ボックスに何かを入力して(「検索結果0 .. 5」と表示されます)、検索をキャンセルします。メインテーブルの開示ボタンは、インデックスの横ではなく、下に表示されるようになりました。

以下は単なるコードです:

@interface AppDelegate ()

@property (nonatomic, strong) UITableViewController* mainTableController;
@property (nonatomic, strong) UISearchDisplayController* searchDisplay;

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // Override point for customization after application launch.

    UITableViewController* tableViewController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];

    UITableView* tableView = [tableViewController tableView];
    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
    [tableView setDataSource:self];
    [self setMainTableController:tableViewController];

    UISearchBar* searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 0, 44)]; // Width set automatically
    [tableView setTableHeaderView:searchBar];

    UISearchDisplayController* searchDisplay = [[UISearchDisplayController alloc] initWithSearchBar:searchBar
                                                                                 contentsController:tableViewController];
    [searchDisplay setSearchResultsDataSource:self];
    [searchDisplay setDelegate:self];
    [self setSearchDisplay:searchDisplay];

    [[self window] setRootViewController:tableViewController];

    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

#pragma mark Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    if (tableView != [[self searchDisplay] searchResultsTableView]) {
        return 26;
    } else {
        return 1;
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (tableView != [[self searchDisplay] searchResultsTableView]) {
        return 10;
    } else {
        return 5;
    }
}

- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView {
    // The problem arises only if the main table view needs to reload its data
    // In this minimal example, we force this to happen
    [[[self mainTableController] tableView] reloadData];

    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"SearchCell"];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (tableView != [[self searchDisplay] searchResultsTableView]) {
        UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

        [[cell textLabel] setText:[NSString stringWithFormat:@"%c%d", 'A' + [indexPath section], [indexPath row]]];
        [cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];

        return cell;
    } else {
        UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"SearchCell" forIndexPath:indexPath];

        [[cell textLabel] setText:[NSString stringWithFormat:@"Search result %d", [indexPath row]]];
        [cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];

        return cell;
    }
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    if (tableView != [[self searchDisplay] searchResultsTableView]) {
        return [NSArray arrayWithObjects:@"A", @"B", @"C", @"D", @"E", @"F", @"G", @"H", @"I", @"J", @"K", @"L", @"M", @"N", @"O", @"P", @"Q", @"R", @"S", @"T", @"U", @"V", @"W", @"X", @"Y", @"Z", nil];
    } else {
        return nil;
    }
}
4

3 に答える 3

1

このような状況でApple自身のアプリがどのように動作するかを模倣しようとしている場合、正しい行動方針は、検索を開始するときに詳細開示ボタンがすべて右に移動し、次にすべてがもう一度戻る原因になります。検索が完了しました。

私はあなたの例で、コードに追加しreloadDataた2つのメソッドでメインテーブルビューを呼び出すことにより、これを自分で達成しました。UISearchDisplayDelegate

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
    [[[self mainTableController] tableView] reloadData];
}

- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
    [[[self mainTableController] tableView] reloadData];
}

これにより、テーブルビューインデックスの可視性を考慮して詳細開示ビューを再配置し、検索モードであるかどうかに関係なく、すべての開示インジケーターの位置を相互に一致させます。

アップデート

私は次のような他のUISearchDisplayDelegate方法でテーブルビューをリロードすることをいじくり回しました:

- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView
- (void)searchDisplayController:(UISearchDisplayController *)controller willUnloadSearchResultsTableView:(UITableView *)tableView

しかし、これらは詳細開示ボタンの位置が突然飛び回るというかなり不快な効果を生み出すので、前述の方法willBeginSearchと方法をお勧めします。willEndSearch

于 2013-02-02T10:36:15.440 に答える
0

私が考えることができる最も簡単で、おそらく最もクリーンな方法は、キーボードイベントをリッスンするようにビューコントローラ(またはビュー)に指示することです。次に、キーボードが最小化されたら、検索バーの最初のレスポンダーを辞任し、テーブルビューをリロードします(まだ正しくリロードされていない場合)。

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        //Your code here



        // register for keyboard notifications
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillShow:)
                                                     name:UIKeyboardWillShowNotification
                                                   object:self.window];
        // register for keyboard notifications
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillHide:)
                                                     name:UIKeyboardWillHideNotification
                                                   object:self.window];
    }
    return self;
}

-(void)dealloc
{


    [[NSNotificationCenter defaultCenter] removeObserver:self name: UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name: UIKeyboardWillHideNotification object:nil];
}

次に、これら2つの関数を追加して、必要なことを実行します。

- (void)keyboardWillHide:(NSNotification *)aNotification
{
    //searchbar resignFirstResponder

    //Tableview reload (if needed)
}

- (void)keyboardWillShow:(NSNotification *)aNotification
{
    //Don't really need this one for your needs
}

キーボードが動き始める前にkeyboardwillhide関数でファーストレスポンダーを辞任しているので、テーブルビューセルは、再度リロードしなくても適切にリロードする必要があります。

于 2013-02-01T20:32:28.257 に答える
0

問題は、セクションインデックスタイトルのあるテーブルに限定されません。セクションヘッダーのタイトルについても同様の問題がありました。追加する場合

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if (tableView != [[self searchDisplay] searchResultsTableView]) {
        return [NSString stringWithFormat:@"Section %c", 'A' + section];
    } else {
        return nil;
    }
}

「最小限の実行可能な例」プログラムでは、メインテーブルビューが再ロードされるとすぐに、セクションヘッダーのタイトルが検索テーブルビューにも表示されることがわかります。(同じ問題がここで報告されました:検索モードでUITableViewからヘッダータイトルを削除します。)

私が知っている唯一の解決策は、検索表示コントローラーがアクティブである限り([self.searchDisplay isActive] == YES)メインテーブルビューへのすべての更新を回避し、検索テーブルがアンロードされたときにのみメインテーブルビューをリロードすることです。

- (void)searchDisplayController:(UISearchDisplayController *)controller  willUnloadSearchResultsTableView:(UITableView *)tableView {
        [[[self mainTableController] tableView] reloadData];
}
于 2013-02-02T09:46:48.660 に答える