3つのアプリをiOS 7に更新しましたが、3つすべてで、コードを共有していないにもかかわらず、ユーザーがスワイプして(戻るボタンをタップするのではなく)Navigation Controllerに戻ると問題が発生します、セルは選択状態のままになります。
3つのアプリでは、1つはプログラムで作成されたカスタムセルを使用し、もう1つはストーリーボードで作成されたカスタムセルを使用し、3つ目はストーリーボードでもUITableViewの非常に基本的なサブクラスのデフォルトセルを使用します。 3つすべてのケースで、セルは選択解除されません。ユーザーがゆっくりとスワイプするか、戻るボタンを押すと、通常どおり選択が解除されます。
これは私のiOS 7アプリでのみ発生し、Apple自身のアプリとiOS 7用にアップグレードされたサードパーティアプリはすべて正常に動作しているようです(ただし、セルの選択解除の速さにはわずかな違いはありますが)。
私が間違っていることはあるに違いありませんが、何がわからないのですか?
私は今、同じ問題に取り組んでいます。 ICatalog -sample from Appleは汚い解決策をもたらすようです。
本当に嬉しくはありません。前述のように、[self.tableView deselectRowAtIndexPath:tableSelection animated:NO];
を使用して、現在選択されている行の選択を解除します。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// this UIViewController is about to re-appear, make sure we remove the current selection in our table view
NSIndexPath *tableSelection = [self.tableView indexPathForSelectedRow];
[self.tableView deselectRowAtIndexPath:tableSelection animated:NO];
// some over view controller could have changed our nav bar tint color, so reset it here
self.navigationController.navigationBar.tintColor = [UIColor darkGrayColor];
}
サンプルコードが iOS 7iOS 8iOS 9 iOS 10対応
私を本当に混乱させているのは、 ITableViewController Class Reference :
テーブルビューが初めて読み込まれたときに表示されるとき、Table View Controllerはテーブルビューのデータを再読み込みします。 また、テーブルビューが表示されるたびに、選択をクリアします(リクエストに応じて、アニメーションの有無にかかわらず)。
UITableViewController
クラスこれをスーパークラスメソッドviewWillAppear:
で実装します。clearsSelectionOnViewWillAppear
プロパティの値を変更することにより、この動作を無効にできます。
これはまさに私が期待する動作です...しかし、動作しないようです。あなたにも私にも。 「ダーティ」ソリューションを実際に使用して、自分で実行する必要があります。
これは私にとって最もうまくいきました:
- (void)viewDidLoad {
[super viewDidLoad];
self.clearsSelectionOnViewWillAppear = NO;
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated];
}
ゆっくりと後ろにスワイプしている間、私ははるかに優れた選択解除フェーディングさえも得ました。
Fabioの答えはうまく機能しますが、ユーザーが少しスワイプしてから気が変わった場合、正しい外観を与えません。そのケースを正しく取得するには、選択したインデックスパスを保存し、必要に応じてリセットする必要があります。
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.savedSelectedIndexPath = nil;
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if (self.savedSelectedIndexPath) {
[self.tableView selectRowAtIndexPath:self.savedSelectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.savedSelectedIndexPath = self.tableView.indexPathForSelectedRow;
if (self.savedSelectedIndexPath) {
[self.tableView deselectRowAtIndexPath:self.savedSelectedIndexPath animated:YES];
}
}
UITableViewControllerを使用している場合は、組み込みのクリアを無効にしてください:
self.clearsSelectionOnViewWillAppear = NO;
savedSelectedIndexPathのプロパティを追加します。
@property(strong, nonatomic) NSIndexPath *savedSelectedIndexPath;
いくつかの異なるクラスでこれを行う必要がある場合は、たとえばこの要点でやったように、ヘルパーで分割するのが理にかなっています: https://Gist.github.com/rhult/46ee6c4e8a862a8e66d4
このソリューションは、行の選択解除を遷移コーディネーターとともにアニメーション化し(ユーザー駆動VC dismiss))、ユーザーが遷移をキャンセルした場合に選択を再適用します。 SwiftのCaleb Davenport 。iOS 9でのみテスト済み。ユーザー駆動(スワイプ)トランジションと古いスタイルの「戻る」ボタンタップの両方で動作することがテスト済み。
UITableViewController
サブクラス内:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Workaround. clearsSelectionOnViewWillAppear is unreliable for user-driven (swipe) VC dismiss
NSIndexPath *indexPath = self.tableView.indexPathForSelectedRow;
if (indexPath && self.transitionCoordinator) {
[self.transitionCoordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
[self.tableView deselectRowAtIndexPath:indexPath animated:animated];
} completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
if ([context isCancelled]) {
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}];
}
}
今日自分でこれに遭遇した後、これは明らかにUITableViewでかなりよく知られている問題であることがわかりました。インタラクティブなナビゲーション遷移のサポートはわずかに壊れています。カストロの背後にいる人々は、これに対する優れた分析と解決策を投稿しています: http://blog.supertop.co/post/80781694515/viewmightappear
私はキャンセルされたトランジションも考慮する彼らのソリューションを使用することにしました:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSIndexPath *selectedRowIndexPath = [self.tableView indexPathForSelectedRow];
if (selectedRowIndexPath) {
[self.tableView deselectRowAtIndexPath:selectedRowIndexPath animated:YES];
[[self transitionCoordinator] notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context) {
if ([context isCancelled]) {
[self.tableView selectRowAtIndexPath:selectedRowIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}];
}
}
設定しようとすることができます
self.clearsSelectionOnViewWillAppear = YES;
uITableViewControllerまたは
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:NO];
viewWillAppearで、おそらく[super viewWillAppear:animated]を呼び出す前。 UItableViewがUITableViewController内でnotの場合、セルを手動で選択解除する必要があります。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
シンプルSwift 3/4 Answer:
override func viewWillAppear(_ animated: Bool) {
if tableView.indexPathForSelectedRow != nil {
self.tableView.deselectRow(at: tableView.indexPathForSelectedRow! as IndexPath, animated: true)
}
}
私は使っています
[tableView deselectRowAtIndexPath:indexPath animated:YES];
メソッドの最後に
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
このような:
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//doing something according to selected cell...
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
デフォルトの動作を正常に機能させるだけの、この問題の非常に簡単な解決策を見つけました。結果の視覚効果がわずかに異なるため、deselectRowAtIndexPath
を含むソリューションに満足しませんでした。
この奇妙な動作を防ぐために必要なことは、ビューが表示されたときにテーブルをリロードすることだけです。
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.tableView reloadData];
}
Codestage answer 、in Swift 3. in notifyWhenInteractionEnds
は非推奨です。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
if let indexPath = self.tableView.indexPathForSelectedRow {
self.tableView.deselectRow(at: indexPath, animated: true)
self.transitionCoordinator?.notifyWhenInteractionChanges { (context) in
if context.isCancelled {
self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
}
}
}
}
おそらく、スーパービューのviewWillAppearメソッド([super viewWillAppear:animated];)を呼び出していません。これを行い、UITableViewControllerのパラメーターclearsSelectionOnViewWillAppearがYESの場合、viewWillAppearでセルの選択が解除されます。
使用する
_[tableView deselectRowAtIndexPath:indexPath animated:YES];
_
コードイン
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method
Swiftの場合
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
guard let indexPath = tableView.indexPathForSelectedRow else{
return
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
Rhultのソリューション iOS 9.2で完全に動作します。これは、Swiftの実装です。
IndexPathを保存するには、MasterViewController
で変数を宣言します。
var savedSelectedIndexPath: NSIndexPath?
次に、明確にするためにコードを拡張機能に配置できます。
extension MasterViewController {
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.savedSelectedIndexPath = nil
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if let indexPath = self.savedSelectedIndexPath {
self.tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)
}
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.savedSelectedIndexPath = tableView.indexPathForSelectedRow
if let indexPath = self.savedSelectedIndexPath {
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
}
Rhult のコードに基づいて、いくつかの変更を加えました。
この実装により、ユーザーはスワイプバックをキャンセルしても、今後のスワイプバック選択解除アニメーションのために選択されたままになります。
@property(strong, nonatomic) NSIndexPath *savedSelectedIndexPath;
- (void)viewDidLoad {
[super viewDidLoad];
self.clearsSelectionOnViewWillAppear = NO;
}
-(void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.savedSelectedIndexPath = nil;
}
-(void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.savedSelectedIndexPath && ![self.tableView indexPathForSelectedRow]) {
[self.tableView selectRowAtIndexPath:self.savedSelectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
} else {
self.savedSelectedIndexPath = [self.tableView indexPathForSelectedRow];
}
}
コードステージは、最も見栄えの良い答えを提供してくれました なので、Swift 2。
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
let selectedRowIndexPath = self.tableView.indexPathForSelectedRow
if ((selectedRowIndexPath) != nil) {
self.tableView.deselectRowAtIndexPath(selectedRowIndexPath!, animated: true)
self.transitionCoordinator()?.notifyWhenInteractionEndsUsingBlock({ context in
if (context.isCancelled()) {
self.tableView.selectRowAtIndexPath(selectedRowIndexPath, animated: false, scrollPosition: UITableViewScrollPosition.None)
}
})
}
}