프로젝트의 기능 중에 셀 안에 체크버튼을 누르면 Lottie 체크 애니메이션이 재생이 되고, 체크표시가 되어야 하는데 의도와는 다르게 작동해서 이에 대해 정리해보고자 합니다.

 

Lottie-Animaion


https://github.com/airbnb/lottie-ios

 

GitHub - airbnb/lottie-ios: An iOS library to natively render After Effects vector animations

An iOS library to natively render After Effects vector animations - airbnb/lottie-ios

github.com

 

Lottie는 JSON형식의 애니메이션 코드를 실시간으로 렌더링하여 출력하는 라이브러리입니다.

장점으로는 벡터기반 애니메이션 형식으로 확대해도 이미지가 깨지지 않는점입니다.

또한 JSON형식으로 저장되기 때문에 파일 크기가 작아 로딩시간이 짧습니다.

이 라이브러리를 사용해서 애니메이션을 출력하고자 했습니다.

 

 

기획


  • 테이블 뷰 셀안에 LottieAnimationView와 버튼이 있습니다.
  • LottieAnimationView는 체크 애니메이션을 재생합니다.
  • 버튼을 누르면 해당 셀의 가운데위치에서 체크애니메이션을 재생합니다.
  • 애니메이션이 종료되면 체크표시가 남아있도록 합니다.
  • 여러 개의 셀이 존재할 수 있고, 각자 독립적인 셀입니다.

처음 기획했던 의도는 위와 같습니다.

쉽게 말하면 To-do와 같이 해야 할 일을 불러와 완료되면 애니메이션 출력 후 완료표시를 남겨두는 것입니다.

 

하지만 기획했던 의도와 다르게 작동하는 버그가 발생하였습니다.

 

 

버그발생


애니메이션이 재생되지않음 / 다른셀에 있는 애니메이션 뷰가 반응함

위와 같이 버그가 발생했습니다. 버그내용은 다음과 같습니다.

  • 체크버튼을 눌러도 애니메이션이 재생을 건너뛰고 완료표시만 생김
  • 체크버튼을 누르면 다른 셀이 반응함

왜 이런 버그가 발생했는지 원인을 찾아보기로 했습니다.

 

 

원인분석


전체적으로 테이블뷰가 존재하고, 커스텀 셀을 구현하여 데이터모델에 맞춰 재사용되고 있습니다.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // TableViewCell을 만들어서 해당 셀을 사용 (커스텀 셀)
    guard let cell = tableView.dequeueReusableCell(
        withIdentifier: TodayTableViewCell.identifier,
        for: indexPath
    ) as? TodayTableViewCell else {
        return UITableViewCell()
    }
    // 데이터모델의 데이터를 셀의 UI Property에 주입
    let study = viewModel.todo[indexPath.row]
    cell.configure(with: study)
    cell.setUIColor()
    
    // 버튼 이벤트를 위해 델리게이트 위임
    cell.delegate = self

    return cell
}
// 체크버튼 클릭 시 이벤트
@objc func checkButtonTapped() {
	// 애니메이션 재생
    checkView.play()
    // 해당 셀의 데이터 done을 true로 변경하는 메서드
    delegate?.checkButtonTapped(name: name)
}

// TableViewCell.Swift
// Cell 데이터 바인딩 메서드
func configure(with model: FirebaseDataModel) {
    self.name = model.name
    label.text = model.name
    guard let done = model.done else { return }
    // done값이 True면 체크표시로 남긴다.
	if done {
    	checkView.currentProgress = 20
    }
}

 

테이블 뷰의 셀을 최신화하기 위해 늘 사용해 왔던 메서드 tableView.reloadData()가 있습니다.

reloadData() 메서드가 실행되면 테이블뷰는 데이터를 가장 최신값을 기준으로 다시 불러오는 과정을 실행하게 됩니다.

이때 tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) 메서드 역시 재실행하는데요

만들어둔 커스텀셀의 데이터 바인딩을 위해 구현한 configure메서드도 실행됩니다.

configure메서드가 실행되므로 셀의 데이터가 변경되어 사용자가 시점에서는 변경된 데이터로 즉시 볼 수 있게 됩니다.

 

configure메서드 내부를 살펴보면 done값이 true면 체크표시가 남도록 설계했었습니다.

이 결과 체크버튼을 누르면 즉시 데이터가 변경되어 reloadData() 메서드가 실행되어 애니메이션 재생을 건너뛰고 바로 체크표시로 남게 되었습니다.

 

두 번째로 발생한 버그는 셀의 재사용 특성에서 볼 수 있었습니다.

커스텀셀을 dequeueReuseableCell로 지정하여 셀이 생성되거나 스크롤 시 재사용큐에 저장된 셀을 사용하도록 구현되었습니다.

데이터를 추가하여 새로운 셀이 추가되니 다음과 같은 현상을 볼 수 있었습니다.

currentProgress 0: 재생전 / currentProgress 1: 재생후 체크표시

2가 적힌 셀을 재생시키고 체크표시를 해두었지만 새로운 데이터를 추가하여 셀을 추가하니

이미 재생된 셀이 나오거나 재생되지 않은 셀이 나오는 현상을 발견하였습니다.

 

재사용하는 셀의 초기 UI상태를 직접 설정하는 prepareForReuse() 메서드를 사용하지 않으니 UI가 뒤죽박죽 되었습니다.

 

 

 

해결한 방안


버그 1) 체크버튼을 눌러도 애니메이션이 재생을 건너뛰고 완료표시만 생김

-> 데이터바인딩이 되어 있어서 데이터값이 변경되면 tableView.reloadData() 메서드가 즉시 실행되는 구조였습니다.

-> 이를 데이터값이 변경은 되어도 tableView.reloadData()메서드가 실행되지 않도록 수정하여 애니메이션이 정상적으로 실행되도록 수정하였습니다.

커스텀 셀과 같은 UI는 데이터바인딩이 되어있지만 데이터 변경에 따른 애니메이션 출력은 진행 과정을 엄밀히 살펴보았어야 했습니다.

체크버튼 클릭 -> 애니메이션 재생 -> 애니메이션 종료 -> 데이터 값 변경 -> 이를 UI에 적용

 

 

 

버그 2) 체크버튼을 누르면 다른 셀이 반응함

-> 커스텀셀을 구현했고, dequeueReusableCell을 사용했습니다. 이에 따라 테이블뷰가 스크롤되거나 새로운 셀이 추가되면 재사용큐에 저장된 셀을 사용하거나 이전에 만들어진 셀을 바탕으로 셀이 생성됩니다.

-> 그 결과 UI가 뒤죽박죽 된 상태로 되었고 이를 방지하기 위해 셀이 추가되거나 재사용될 때 초기 UI 상태를 지정하는 prepareForReuse()를

 

 

 

결과


정상적으로 작동하게 되었습니다.

 

 

 

당연하게 테이블 뷰를 구성할 때 커스텀 셀을 만들었고 dequeueReusableCell을 이용하여 셀을 구성하였었습니다.

이번 버그를 고치기 위해 셀을 재사용한다는 점과 데이터와 UI가 바인딩된 상태에서 애니메이션구현까지 된다면 기획했던 과정이 잘 진행이 되는지 검토해야 한다는 점을 느꼈습니다. 그리고 tableView.reloadData()는 즉시 테이블 뷰를 새로고침해서 애니메이션이 부자연스럽게 작동한다는 것을 알았습니다.

 

+ Recent posts