2016-10-28 1 views
0

배경 : 단일 ViewController에는 4 개의 사용자 정의 프로토 타입 셀이 있습니다. 첫 번째 것은 항상 표시되며 UITextField입니다. 프로토 타입 셀 2, 3 및 4에는 이미지, 레이블 및 레이블이 각각 들어 있습니다. 그러나 프로토 타입 셀 4는 배열을 기반으로하며 첫 번째 셀의 입력에 따라 1 또는 여러 행을 가질 수 있습니다.begin-endUpdates() 및 여러 사용자 정의 셀을 사용하여 UITableViewCells를 확장/축소하는 방법은 무엇입니까?

첫 번째 셀에 특정 문자열을 입력하면 해당 문자열이있는 속성이 속성에 있는지 확인하는 검사가 수행됩니다. 값이 인 경우 일 경우 첫 번째 셀의 높이와 레이아웃이 변경됩니다. 값이 인 경우이면 첫 번째 셀의 높이가 변경되고 가장 중요한 것은 3 개의 다른 프로토 타입 셀이 확장되어 String 입력에 해당하는 객체의 세부 정보를 표시합니다. 그런 다음 사용자가 잘못된 다른 문자열을 입력하면 셀이 축소됩니다.

문제점 : 다른 세 개의 셀을 확장하거나 축소하는 애니메이션입니다. beginOpdates()와 endUpdates() 사이에서 numberOfRowsInSection() 메서드와 코드 블록 (아래 코드 2 단계)을 정의하는 방법을 파악하는 데 문제가 있습니다. 심지어 arraycells 구현없이 insertRows() 후에 reloadRows()를 호출하는 것은 효과가없는 것 같습니다. 내가 뭘하려

:

  • reloadData는() = 데이터를 올바르게 보여 주지만, 필요한 애니메이션을 제공하지 않기 때문에 나는 그것을 사용할 수 없습니다.
  • beginUpdates()와 = 다음과 같은 오류주는 사이에서 아무것도없이 EndUpdates 사이() :이가 마지막 프로토 타입 셀이 배열에 따라 나는 '는 사실과 관련이 생각

    Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (6) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

을 셀의 실제 데이터를 다시로드하지 않고보기 만합니다.

  • 다른 조합은 insertRowsAtIndexPath, reloadRowsAtIndexPath, ... = 행 수와 관련된 유사한 오류를 제공합니다.

도움이 될만한 도움이 될 것입니다.

간체 코드 :

class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, updateUITableView { 

    var people: [Person] = [ 
     Person(name: "name", image: "imagename1", description: "description1", children: ["name1","name2","name3"]), 
     Person(name: "name2", image: "imagename3", description: "description2", children: ["name4", "name5", "name6"]) 
    ] 

    enum Flag { 
     case start 
     case match 
     case noMatch 
    } 
    var flag = Flag.start 

    var globalObject: Person? 

    @IBOutlet var tableView: UITableView! 

    func numberOfSections(in tableView: UITableView) -> Int { 
     return 1 
    } 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     switch (flag) { 
     case .start : 
      return 1 
     case .noMatch: 
      return 1 
     case .match: 
      return 3 + (globalObject?.children.count)! //PROBLEM! 
     } 
    } 

    //START - Input received from tableViewCell 
    func checkName(senderCell: SearchInputTableViewCell, name: String) { 
     // STEP 1: Check if person exists 
     let person = checkPersonNameMatch(nameInput: name) 
     globalObject = person //save globally for cellForRowsAtIndexPath 

     // STEP 2: Show/hide cells 
     toggleCellsVisibility(person: person) 
    } 

    //STEP 1: 
    func checkPersonNameMatch(nameInput: String) -> Person? { 
     guard let index = people.index(where: {$0.name == nameInput}) else { 
      flag = .noMatch 
      return nil 
     } 
     let personFound = people[index] 
     flag = .match 
     globalObject = personFound 
     return personFound 
    } 

    //STEP 2 = PROBLEM! 
     func toggleCellsVisibility(person: Person?) { 
    if person != nil { //Cells appear 
     UIView.animate(withDuration: 0.7, animations: { 

      self.tableView.beginUpdates() 

      let indexPath: IndexPath = IndexPath(row: 1, section: 0) //for Image cell 
      let indexPath2: IndexPath = IndexPath(row: 2, section: 0) //for Description cell 
      //let indexPath3: IndexPath = IndexPath[....] //for array in Children cell 

      self.tableView.insertRows(at: [indexPath], with: .bottom) 
      self.tableView.insertRows(at: [indexPath2], with: .bottom) 

      self.tableView.reloadRows(at: [indexPath], with: .bottom) 
      self.tableView.reloadRows(at: [indexPath2], with: .bottom) 
      //... a for-loop to reload the array cells here? 

      self.tableView.endUpdates() 
     }) 
    } else { //Cells disappear 
     UIView.animate(withDuration: 0.4, animations: { 
      self.tableView.beginUpdates() 
      //... same code as above? 
      self.tableView.endUpdates() 
     }) 
    } 
} 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     switch indexPath.row { 
     case 0: 
      let cellIdentifier = "InputCell" 
      let inputCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! InputTableViewCell 

      inputCell.delegate = self 

      switch (flag) { 
      case .start: 
       self.tableView.rowHeight = 187 
      case .match: 
       self.tableView.rowHeight = 170 
      case .noMatch: 
       self.tableView.rowHeight = 200 
      } 

      return inputCell 

     case 1: 
      let cellIdentifier = "ImageCell" 
      let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! ImageTableViewCell 

      cell.image?.image = UIImage(named: (globalObject?.image)!) 

      switch (flag) { 
      case .start: 
       self.tableView.rowHeight = 0 
      case .match: 
       self.tableView.rowHeight = 170 
      case .noMatch: 
       self.tableView.rowHeight = 0 
      } 

      return cell 

     case 2: 
      let cellIdentifier = "DescriptionCell" 
      let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! DescriptionTableViewCell 

      cell.description?.text = globalObject?.description 

      switch (flag) { 
      case .start: 
       self.tableView.rowHeight = 0 
      case .match: 
       self.tableView.rowHeight = 54 
      case .noMatch: 
       self.tableView.rowHeight = 0 
      } 

      return cell 

     default: 
      let cellIdentifier = "ChildrenCell" 
      let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! ChildrenTableViewCell 

      cell.childName?.text = globalObject?.children[(indexPath as IndexPath).row - 3] 

      switch (flag) { 
      case .start: 
       self.tableView.rowHeight = 0 
      case .match: 
       self.tableView.rowHeight = 44 
      case .noMatch: 
       self.tableView.rowHeight = 0 
      } 

      return cell 
     } 
    } 
} 

답변

0

나의 제안이 될 것이다는 : 어떤 삽입을하거나 이러한 행의 제거하지 않습니다. 높이가 0이고 (clipsToBoundstrue으로 설정) 행을 항상 계속 유지하십시오. 따라서 사용자가 필요하기 전까지는 보이지 않습니다. 필요할 때 높이를 변경하고 beginUpdatesendUpdates으로 전화하십시오.

+0

자세한 내용은 내 대답은 여기를 참조하십시오 : http://stackoverflow.com/a/40198962/341994 – matt

+0

나는 그 접근 방식을 시도했지만 그것은 나에게 '잘못된 행 수의 오류가 위에서 설명한 바와 같이했다. 내 상황과 내가 링크 한 상황의 차이는 내 데이터의 종속성입니다. 표시/확장되는 셀의 데이터 (및 번호)는 첫 번째 셀의 입력을 기반으로합니다. 따라서 처음에 어떻게 정의 할 수 있는지 미리 알지 못합니다. 사전에 얼마나 많은 데이터가있을 것이며 어떤 데이터가 포함될 지 미리 알지 못합니다. – Aovib

+0

"얼마나 많은 데이터가있을 것이며 어떤 데이터가 포함될 것인지 미리 알지 못하면"좋습니다. 그러나'beginUpdates'를 호출하기 전에 항상 _model_를 업데이트해야합니다. 기본적으로 이것은 행을 추가 할 때와 다릅니다. 그리고 귀하의 경우, 내가 말할 수있는 한, _row_ 삽입을 할 필요가 없습니다. – matt

0

열거 형을 사용하여 데이터 레이아웃을 변경하면 데이터가있을 때 계산할 수있는 행 수에 대해 걱정할 필요가 없습니다.예제 코드는 다음과 같이에서

enum CellType { 
    case textField 
    case labelCell 
    case array 
} 

당신의있는 tableView

class TableViewController: UITableViewController { 
    var order = [CellType]() 

    func calculateRowOrder() { 
     // You can also customize which cells you want here, or if they're dynamic 
     order = [.textField, .labelCell] 

     // Add as many .array as child cells 
     for _ in globalObject?.children ?? [] { 
      order.append(.array) 
     } 
    } 
} 

에 관련된 무언가를 포함 그리고 당신은 더 쉽게 데이터 소스에 대한 방법을 수행 할 수 있습니다

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return order.count 
} 

그리고를 셀 사용자 정의 :

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let row = indexPath.row 

    let cellType = order[row] 

    switch cellType { 
    case .textField: 
     <Customize textField> 
    case .label: 
     <Customize label> 
    case .array: 
     // You can figure out which child element you're customizing 
     <Customize array> 
    } 
} 

언제든지 데이터가 변경되었거나 데이터를 다시로드해야 할 경우 주문을 다시 계산하고 데이터를 다시로드해야합니다. 행운을 빕니다.

+0

이 코드를 구현할 때 이상한 결과가 나타납니다 ... 첫 번째 셀에 값을 입력하고 reloadData()를 사용하여 tableView를 다시로드하면 마지막 두 셀만 표시됩니다. 언제 어디서나 화면을 터치하고 스크롤하면 화면이 갑자기 즉시 모든 셀을 올바르게 보여줍니다. 무엇이이 결함을 일으킬 수 있습니까? 어쩌면 깃발과 관련이 있고 calculateRows()를 호출해야하는 순간이 있습니까? 나는 화면을 열 때 첫 번째 셀을 얻으려면 viewDidLoad()에 calculateRows()를 넣고 새 행을 다시 계산하고 가져 오려면 toggleCellsVisibilty()에 넣습니다. – Aovib

+0

또한 코드를 더 읽기 쉽고 깨끗하게 만들지 만 원래의 게시물에있는 beginUpdates()/endUpdates() 충돌은 여전히 ​​수정되지 않습니다. 나는 여전히 "잘못된 행 수"에 관한 동일한 오류 메시지를 받는다. :/ – Aovib

+0

beginUpdates()/endUpdates()를 사용할 필요가 없으며 tableView.reloadData() – Sealos

관련 문제