質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
TableView

TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1921閲覧

構造体を使った特定のセルのスワイプの設定について

退会済みユーザー

退会済みユーザー

総合スコア0

TableView

TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2018/05/19 08:23

swift

1struct Cell { 2 var detail: [String] 3 var lightswipe: Bool//detail 4 var delete: Bool//delete 5 6} 7 8import UIKit 9 10class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate{ 11 12 @IBOutlet weak var mytableView: UITableView! 13 14 //構造体 15 var titles: [String] = [] // title用 16 var products: [Cell] = []//detail 17 18 19 // numberOfRowsInSection省略 20 21 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 22 let cell = UITableViewCell() 23 let index = Int(floor(Double(indexPath.row / 2))) 24 //セルタップ時のハイライトについて 25 cell.selectionStyle = .none 26 // title行 27 if indexPath.row % 2 == 0 { 28 29 guard titles.count > 0 else { 30 return cell 31 } 32 33 34 let title = titles[index] 35 cell.textLabel?.text = title 36 //センター寄せ 37 cell.textLabel!.textAlignment = NSTextAlignment.center 38 cell.backgroundColor = UIColor(red: 0.0, green: 0.8, blue: 1.0, alpha: 0.3) 39 40 // detail行 41 } else { 42 cell.backgroundColor = UIColor.lightGray 43 let item = products[index] 44 45 guard item.detail.count > 0 else { 46 return cell 47 } 48 49 var labels: [UILabel] = [] 50 51 //labelについて 52 for i in item.detail { 53 let label = UILabel() 54 label.backgroundColor = UIColor(red: 0.0, green: 0.8, blue: 0.9, alpha: 0.2) 55 label.text = i 56 57 58 // textLabel という名前の変数に格納された UILabel にフォントサイズの自動調整を設定します。 59 label.adjustsFontSizeToFitWidth = true 60 label.minimumScaleFactor = 10.0 61 //丸みに対して 62 label.layer.cornerRadius = 5 63 label.layer.masksToBounds = true 64 cell.contentView.addSubview(label) 65 labels.append(label) 66 } 67 68 var preLabel: UILabel? = nil 69 for l in labels { 70 71 l.translatesAutoresizingMaskIntoConstraints = false 72 if (preLabel == nil) { 73 l.leftAnchor.constraint(equalTo: cell.contentView.leftAnchor, constant: 12).isActive = true 74 } else { 75 l.leftAnchor.constraint(equalTo: preLabel!.rightAnchor, constant: 20).isActive = true 76 } 77 cell.contentView.heightAnchor.constraint(equalTo: l.heightAnchor, multiplier: 1).isActive = true 78 preLabel = l 79 } 80 81 } 82 83 return cell 84 } 85 86 87 @IBAction func addcellbtr(_ sender: Any) { 88 89 alertnormal() 90 } 91 92 func alertnormal() 93 94 //右スワイプ 95 func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { 96 97 //スワイプ出来るセルを限定する 98/*146行目 */ if products[indexPath.row].lightswipe{ 99 return UISwipeActionsConfiguration(actions: []) 100 } 101 102 let edit = UIContextualAction(style: .normal,title: "追加", handler: { (action: UIContextualAction, view: UIView, success :(Bool) -> Void) in 103 let alert = UIAlertController(title: "タイトル", message: "メッセージ", preferredStyle: .alert) 104 105 // OKボタンの設定 106 let okAction = UIAlertAction(title: "OK", style: .default, handler: { 107 (action:UIAlertAction!) -> Void in 108 109 // OKを押した時入力されていたテキストを表示 110 if let textFields = alert.textFields { 111 112 // アラートに含まれるすべてのテキストフィールドを調べる 113 for textField in textFields { 114 let name = textField.text! 115 let index = Int(floor(Double(indexPath.row / 2))) 116 117 self.products[index].detail.append(name) 118 self.mytableView.reloadData() 119 } 120 } 121 }) 122 alert.addAction(okAction) 123 124 // キャンセルボタンの設定 125 let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) 126 alert.addAction(cancelAction) 127 128 // テキストフィールドを追加 129 alert.addTextField(configurationHandler: {(textField: UITextField!) -> Void in 130 textField.placeholder = "テキスト" 131 }) 132 133 134 alert.view.setNeedsLayout() // シミュレータの種類によっては、これがないと警告が発生 135 136 // アラートを画面に表示 137 self.present(alert, animated: true, completion: nil) 138 print("edit") 139 140 success(true) 141 }) 142 143 edit.backgroundColor = .blue 144 145 let config = UISwipeActionsConfiguration(actions: [edit]) 146 config.performsFirstActionWithFullSwipe = false 147 return config 148 } 149 150 151 152 // trueを返すことでCellのアクションを許可しています 153 func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { 154 // detail行の場合は許可 155 //return indexPath.row % 2 == 1 156 if products.count > (indexPath.row + 1) { 157 return true 158 }else{ 159 return true 160 } 161 } 162 163 164 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 165 if indexPath.row % 2 == 0 { 166 167 guard titles.count > 0 else { 168 return 25//必要なのか? 169 } 170 return 25 171 } 172 return 40 //自動設定 173 } 174 175 //左から右へスワイプ 176 func tableView(_ tableView: UITableView, 177 leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { 178 179 //スワイプ出来るセルを限定する 180/*227行目*/ if !titles[indexPath.row]{//エラー: Cannot convert value of type 'String' to expected argument type 'Bool' 181 return UISwipeActionsConfiguration(actions: []) 182 } 183 184 let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { action, view, completionHandler in 185 self.delete(indexPath) 186 completionHandler(true) 187 188 } 189 190 let edit = UIContextualAction(style: .normal,title: "edit", handler: { (action: UIContextualAction, view: UIView, success :(Bool) -> Void) in 191 192 let alert = UIAlertController(title: "タイトル", message: "メッセージ", preferredStyle: .alert) 193 194 // OKボタンの設定 195 let okAction = UIAlertAction(title: "OK", style: .default, handler: { 196 (action:UIAlertAction!) -> Void in 197 198 // OKを押した時入力されていたテキストを表示 199 if let textFields = alert.textFields { 200 201 // アラートに含まれるすべてのテキストフィールドを調べる 202 for textField in textFields { 203 let name = textField.text! 204 self.titles.insert(name, at: 0) 205 } 206 self.products.append(Cell(detail: [], lightswipe: false, delete: false)) 207 self.mytableView.reloadData() 208 209 } 210 }) 211 alert.addAction(okAction) 212 213 // キャンセルボタンの設定 214 let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) 215 alert.addAction(cancelAction) 216 217 // テキストフィールドを追加 218 alert.addTextField(configurationHandler: {(textField: UITextField!) -> Void in 219 textField.placeholder = "テキスト" 220 }) 221 222 223 alert.view.setNeedsLayout() // シミュレータの種類によっては、これがないと警告が発生 224 225 // アラートを画面に表示 226 self.present(alert, animated: true, completion: nil) 227 print("edit") 228 229 success(true) 230 }) 231 232 //deleteAction.backgroundColor = .orange 233 edit.backgroundColor = .blue 234 235 //return UISwipeActionsConfiguration(actions: [edit]) 236 //return UISwipeActionsConfiguration(actions: [deleteAction,edit]) 237 let config = UISwipeActionsConfiguration(actions: [deleteAction,edit]) 238 config.performsFirstActionWithFullSwipe = false 239 return config 240 241 } 242 243 func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { 244 return indexPath 245 } 246 247 //cellの削除について 248 func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle { 249 return products[indexPath.row].delete ? .delete : .none 250 } 251 //cellの削除について 252 func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { 253 if editingStyle == .delete { 254 self.delete(indexPath) 255 } 256 } 257 258 func delete(at indexPath: IndexPath) { 259 var category = products[indexPath.row].detail 260 category.remove(at: indexPath.row) 261 titles.remove(at: indexPath.row) 262 mytableView.deleteRows(at: [indexPath], with: .fade) 263 } 264 265 266 override func viewDidLoad() { 267 super.viewDidLoad() 268 mytableView.delegate = self 269 mytableView.dataSource = self 270 mytableView.backgroundColor = UIColor(red: 0.0, green: 0.8, blue: 1.0, alpha: 0.1) 271 mytableView.separatorColor = UIColor.clear 272 273 mytableView.reloadData() 274 } 275 276 277 278 override func didReceiveMemoryWarning() { 279 super.didReceiveMemoryWarning() 280 // Dispose of any resources that can be recreated. 281 } 282 283 284} 285

やりたい事

titlesとなるセルは左スワイプ、detailとなるセルは右スワイプとセルの種類によって左右のスワイプを限定できる仕様にしたい。
titlesとなるセルをスワイプによってデリートする時にdetailのセルも同時にデリート出来るようにしたい。

できていること
右のスワイプに関しては構造体を使い、titlesとなるセルは右スワイプできない様になった。
困っていること
detailとなるセルに対してもスワイプできない様になってしまった。しようとすると落ちてしまう。
左に関するスワイプについてはtitlesがBool型じゃ無いとエラーが出ていてstringをBoolに変換する方法が分からないで困っています。

エラーコード
146: Fatal error: Index out of range
227: Cannot convert value of type 'String' to expected argument type 'Bool'

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

146: Fatal error: Index out of range

この仕組みの場合、title行は偶数行、detail行は奇数行に表示されるようになっています。
つまりそれぞれの配列のデータ数はテーブルの行数の半分になります。

一方で

indexPath.row

は単純にtableViewの行数を表現しているため、

products[indexPath.row]

とすると、ある時点でproductsのデータ数を超えるため、Fatal error: Index out of rangeになります。

227: Cannot convert value of type 'String' to expected argument type 'Bool'

titles[indexPath.row]

これが何を表しているのかを理解されていますでしょうか?

titlesはstring型の配列なので、上記はその中のデータの一つのため、string型です。
「stringをBoolに変換する」というがよくわかっていないのですが、stringのisEmptyなどを用いて空文字判定(=Bool判定)などはできると思います。

ただ、

左に関するスワイプについてはtitlesがBool型じゃ無いとエラーが出ていてstringをBoolに変換する方法が分からない

これは何をされようとしていますでしょうか?

ご質問内容のやられたいこととしては、
detail行は左スワイプをできないようにする?
だと思いますので、

indexPath.rowからdetail行を判定して、detail行の場合は処理をしないという条件に変えればよいと思います。(title行は偶数行、detail行は奇数行です。)

投稿2018/05/19 21:32

newmt

総合スコア1277

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/05/20 00:09

>左に関するスワイプについてはtitlesがBool型じゃ無いとエラーが出ていてstringをBoolに変換する方法が分からない に関しては私のエラー文の解釈ミスですので気になさらないで大丈夫です。 スワイプに関しては理解できましたのでやってみます。 デリート処理に関してなのですがtitleかdetailかの一方だけをデリートする処理は本やネットの記事などで分かるのですがtitleとdetailを1つのセットにしてデリートしたい場合のやり方が分からないのでそれだけ教えて頂けませんか?
newmt

2018/05/20 05:39

削除対象する行がわかっていれば、title行の次の行に削除したいdetail行がくるので let detailIndexPath = IndexPath(row: indexPath.row + 1, section: indexPath.section) mytableView.deleteRows(at: [indexPath, detailIndexPath], with: .fade) などでできませんでしょうか? ※ただし、ここで使用しているindexPathのままですとデータ数を超えてしまうため、titlesとproductsの配列から削除するデータの位置は調整する必要があると思いますが。
退会済みユーザー

退会済みユーザー

2018/05/20 05:53

試してみましたがsignal sigbrtで落ちました。 恐らく指摘して頂いたindexPathに問題があると思うので再考してみます。 それと下記の様にスワイプを出来るセルについての処理なんですが@newmtさんに教えて頂いたisEmptyで判定に関する処理を書いているのですがif文の中をどうすればdetailのスワイプを制限できるのでしょうか? 今の状態ですとifの中にreturn UISwipeActionsConfiguration(actions: [])を書くとtitle・detailのセル両方ともスワイプ出来なくなります。またelseに書くと両方とも出来るかでしか判定が出来なくて困っています。 //スワイプ出来るセルを限定する if !titles.isEmpty{ //detailに関する処理を書く }else{ return UISwipeActionsConfiguration(actions: []) }
newmt

2018/05/20 06:01

!titles.isEmptyはあくまでもたとえで提示しただけです。わかりづらくしてしまい、誠に申し訳ございません。 本当に必要な処理は最後に記載した indexPath.rowからdetail行を判定して、detail行の場合は処理をしないという条件に変えればよいと思います。(title行は偶数行、detail行は奇数行です。) の部分です。
退会済みユーザー

退会済みユーザー

2018/05/20 06:13

私の理解力が乏しくて勘違いしてしまいすいません。 下記の様にしたら出来ました。 この形で実行して大丈夫だったのですが@newmtさんが考えていたコードと合っていましたか? //スワイプ出来るセルを限定する if indexPath.row % 2 == 1{ //除算で判定する //detailに関する処理を書く }else{ return UISwipeActionsConfiguration(actions: []) }
退会済みユーザー

退会済みユーザー

2018/05/20 13:59

@newmtさんのデリート処理に関して試してみましたが出来ませんでした。その為、私なり思いつく方法でデリート処理をについて考えて試してみましたがindexPathの取得を上手く出来ずにIndex out of rangeのエラーが起きてしまいどうしても分からないので教えて頂けませんか? https://teratail.com/questions/127105
退会済みユーザー

退会済みユーザー

2018/05/21 18:03

夜遅くにすいません。以下の様にしたらtitleとdetailセルを同時に削除できました。 @newmtさんのアドバイスのお陰で時間は掛かりましたが私自身で解決することが出来ました。 本当にありがとうございました。 self.titles.remove(at: indexPath.row) self.products.remove(at: indexPath.row) mytableView.reloadData()
newmt

2018/05/22 21:43

すいません。仕事で見れていませんでした。解決できて何よりです。
退会済みユーザー

退会済みユーザー

2018/05/23 10:36

@newmt さん 今、cell内のlabelををタップした時の処理などを書いているのですが困っている点がいくつかあります。 ラベルを長押しやダブルクリックした際のGestureの処理を書いているのですが、lablesのインスタンスがcellForRowAt内にある為、Gestureのコードにlabelsを紐づける事が出来ずに困っています。 大変お忙しいと思いますがお時間のある時に教えて頂けると幸いです。 https://teratail.com/questions/127481
退会済みユーザー

退会済みユーザー

2018/06/20 16:18

お久しぶりです。 realmの使い方で躓いてしまって解決の方法がわからなくて困っています。 もしお時間ありましたらご教授頂けないでしょうか? お願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問