0

progressview (이 하위 클래스를 사용하여 Linear Progress View)에 애니메이션을 적용하는 데 조금 어려움이 있습니다.컬렉션 뷰 셀 내에서 뷰 애니메이션 활성화

배경이 약간이므로 아래에 게시 된 코드가 의미가 있습니다. 일부 기본 기능을 사용하여 UICollectionViewCell의 하위 클래스를 만들었습니다. 주로 이것에 대한 이유는 상용구 코드를 줄이는 것이 었습니다. 내 컬렉션보기에서 셀을 내 하위 클래스로 설정하고 모델 객체에 전달합니다. 모든 데이터가 올바르게 표시되지만 진행률보기에는 애니메이션이 적용되지 않습니다. 컬렉션보기에서 viewWillDisplay 같은 것을 시도했지만 아무 소용이 없습니다.

모든 의견을 크게 기뻐할 것입니다. (아래 코드)

CollectionViewCell 클래스 :

import UIKit 
import ChameleonFramework 
import Material 


class MacrocycleCell: Cell { 

var macrocycle:Macrocycle? = nil { 
    didSet{ 
     if let macro = macrocycle, let start = macrocycle?.start, let completion = macrocycle?.completion { 

      title.text = macro.title 
      let percentage = Date().calculatePercentageComplete(startDate: start, completionDate: completion) 
      progress.setProgress(percentage, animated: true) 



      let difference = Date.calculateDifferenceInMonthsAndDaysBetween(start: start, end: completion) 
      if let monthDiff = difference.month, let dayDiff = difference.day { 
       if monthDiff > 0 { 
        detail.text = monthDiff > 1 ? "\(monthDiff) months left" : "\(monthDiff) month left" 
       }else{ 
        detail.text = dayDiff > 1 ? "\(dayDiff) days left" : "\(dayDiff) day left" 
       } 
      } 


     } 

    } 
} 







let dropView:View = { 
    let view = View() 
    view.backgroundColor = .white 
    view.translatesAutoresizingMaskIntoConstraints = false 
    view.depthPreset = DepthPreset.depth2 
    return view 
}() 

let title:UILabel = { 
    let label = UILabel() 
    label.translatesAutoresizingMaskIntoConstraints = false 
    label.textAlignment = .center 
    label.font = UIFont.boldSystemFont(ofSize: 18) 
    label.textColor = UIColor.flatBlack() 
    return label 
}() 

let progress:LinearProgressView = { 
    let progress = LinearProgressView() 
    progress.isCornersRounded = true 
    progress.barColor = UIColor.flatWhiteColorDark() 
    progress.trackColor = UIColor.flatGreen() 
    progress.barInset = 0 
    progress.minimumValue = 0 
    progress.maximumValue = 1 
    progress.animationDuration = 1 
    progress.translatesAutoresizingMaskIntoConstraints = false 
    return progress 
}() 


let detail:UILabel = { 
    let label = UILabel() 
    label.translatesAutoresizingMaskIntoConstraints = false 
    label.textAlignment = .center 
    label.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.light) 
    label.textColor = UIColor.flatGray() 
    return label 
}() 


override func drawView() { 
    addSubview(dropView) 
    dropView.addSubview(title) 
    dropView.addSubview(progress) 
    dropView.addSubview(detail) 

    dropView.topAnchor.constraint(equalTo: topAnchor).isActive = true 
    dropView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true 
    dropView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true 
    dropView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -2).isActive = true 

    progress.centerXAnchor.constraint(equalTo: dropView.centerXAnchor).isActive = true 
    progress.centerYAnchor.constraint(equalTo: dropView.centerYAnchor).isActive = true 
    progress.heightAnchor.constraint(equalToConstant: 10).isActive = true 
    progress.widthAnchor.constraint(equalTo: dropView.widthAnchor, multiplier: 0.8).isActive = true 

    title.topAnchor.constraint(equalTo: dropView.topAnchor).isActive = true 
    title.leftAnchor.constraint(equalTo: dropView.safeAreaLayoutGuide.leftAnchor).isActive = true 
    title.rightAnchor.constraint(equalTo: dropView.safeAreaLayoutGuide.rightAnchor).isActive = true 
    title.bottomAnchor.constraint(equalTo: progress.topAnchor, constant: 6).isActive = true 

    detail.topAnchor.constraint(equalTo: progress.bottomAnchor, constant: 14).isActive = true 
    detail.leftAnchor.constraint(equalTo: dropView.leftAnchor).isActive = true 
    detail.rightAnchor.constraint(equalTo: dropView.rightAnchor).isActive = true 
    detail.heightAnchor.constraint(equalToConstant: 14).isActive = true 
} 
} 

CollectionViewController 등급 :

import UIKit 

private let reuseIdentifier = "Cell" 

class MacrocycleController: UICollectionViewController, UICollectionViewDelegateFlowLayout { 

var athlete:Athlete? = nil { 
    didSet{ 
     self.title = athlete?.name 

    } 
} 

override func viewDidLoad() { 
    super.viewDidLoad() 
    collectionView?.backgroundColor = .flatWhiteColorDark() 

    self.collectionView!.register(MacrocycleCell.self, forCellWithReuseIdentifier: reuseIdentifier) 


} 


override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 




// MARK: UICollectionViewDataSource 



func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 
    return CGSize(width: collectionView.frame.width, height: 90) 
} 

override func numberOfSections(in collectionView: UICollectionView) -> Int { 
    // #warning Incomplete implementation, return the number of sections 
    return 1 
} 


override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
    // #warning Incomplete implementation, return the number of items 
    return athlete?.macrocycles?.count ?? 0 
} 

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! MacrocycleCell 
    cell.macrocycle = athlete?.macrocycles?[indexPath.item] 



    return cell 
} 


} 

나는 그것이 내가 구현하는 잊어 버린 것을, 뭔가 간단 확신합니다.

감사합니다. 아름다운 사람들!

+0

그래서'macrocycle'은'viewDidLoad'와'cellForItem'에 설정되어 있습니다. – MQLN

+0

[매크로 사이클]은 이전 vc에서 설정되고 didSet 호출을 사용하여 푸시됩니다. 셀 인스턴스는 같지만 collectionViewCell 매크로 싸이클 집합 내에서 동일합니다. 말이 돼? – Paulo

+0

실제 애니메이션이 어디에서 호출되는지 파악하려고합니다. 셀의 애니메이션을 호출 할 곳을 알아내는 질문의 의도는 무엇입니까? – MQLN

답변

1

눈에 보이는 변화가 없으므로 애니메이션이 표시되지 않습니다. 특히 셀이 표시되기 전에 setProgress에서 didSet을 호출하고 다시 호출하지 않습니다.

애니메이션을 보려면 일부 초기 값 (0 %)으로보기를 허용 한 다음 setProgress를 다시 호출하여 변경 사항을 실제 값에 애니메이션으로 적용해야합니다.

당신이하려는 것은 UI 관점에서 볼 때 좋은 생각이 아닙니다. 원칙적으로 진행 막대는 실제 의미있는 진행 상황 (사용자 조치, 다운로드 등)이 발생할 때만 이동해야합니다. 따라서 귀하의 질문에 대한 내 대답은이 경우 애니메이션없이 진행률 표시 줄을 사용하는 것입니다.

즉, 셀을 다시로드 할 필요없이 셀의 진행률 막대를 업데이트하려는 정당한 경우가 있습니다. 예를 들어 주기적으로 각 셀과 관련된 진행 상황을보고하는 백그라운드 작업이 실행되고있는 경우. 이러한 종류의 업데이트를 수행하는 다양한 방법을 보여주는 풍부한 답변이 있습니다.

또한 셀을 표시 한 직후에 업데이트를 트리거하기 위해 제안 된 다양한 해킹이 있습니다. 존재하지 않는 "DidDisplayCell"대리자 메서드에 대한 질문을 검색하여 이러한 아이디어 중 일부를보고 싶습니다. 셀 디스플레이 후에 애니메이션을 만들 수는 있지만 인위적인 목적으로 애니메이션을 사용하려는 유혹으로부터 벗어나고 싶습니다. (내가있는 tableview와이 테스트) 여기

는 WillDisplay에서이 사용 asyncAfter을 할 수있는 방법을 설명하기 위해 몇 가지 코드 조각입니다 : 분명히

// This would be in your cell class 
var progress: Float = 0.0 
@IBOutlet var progressBar: LinearProgressView! 

func animateIfNeeded() { 

    if progressBar.progress != self.progress { 
     progressBar.setProgress(progress, animated: true) 
    } 
} 

// This would be in your delegate (I tested with tableview) 
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { 

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { 
     let animateCell = cell as! Cell 
     animateCell.animateIfNeeded() 
    } 
} 

그리고, didSet에 그냥 인스턴스로 계산 된 값을 절약 할 수 변수 (progress : Float)를 호출하고 progressBar.setProgress (0, animated : false)를 호출합니다.

+0

Init에서 값을 0으로 설정 한 다음 애니메이션을 적용 하시겠습니까? – Paulo

+0

didSet에서 진행률 표시 줄을 0으로 설정하고 계산 된 값을 저장합니다. 그것은 쉬운 부분입니다. 더 어려운 부분은 셀이 표시된 후 setProgress를 두 번째로 호출 할시기/방법을 파악하는 것입니다. 대리자 메서드 "DidDisplayCell"이 없으므로, 자신 만의 기술을 고안해야합니다. 힌트 (세 가지 옵션) : cell.layoutSubviews, cell.didMoveToWindow 또는 dispatch asyncAfter는 WillDisplayCell에서 호출됩니다. – ozzieozumo

+0

좋아, 이것 좀 봐. :) 나는 올바른 것으로 표시 할 것입니다. 제안이 나오면 – Paulo

0

다음은 셀 클래스의 모든 논리를 유지하고 수집 컨트롤러의 WillDisplayCell 대리자 메서드를 사용하지 않는 또 다른 대답입니다.

var progress: Float = 0.0 
@IBOutlet var progressBar: LinearProgressView! 
var drawnAtLeastOnce = false 

func animateIfNeeded() { 
    if progressBar.progress != self.progress { 
     progressBar.setProgress(progress, animated: true) 
    } 
} 
override func layoutSubviews() { 
    super.layoutSubviews() 
    if drawnAtLeastOnce { 
     animateIfNeeded() 
    } 
} 

override func draw(_ rect: CGRect) { 
    super.draw(rect) 
    if !drawnAtLeastOnce { 
     drawnAtLeastOnce = true 
     setNeedsLayout() 
    } 
} 

이 응답의 핵심은 제

도면 패스의 종료를 검출하고, 그 때까지 애니메이션을 억제한다.

이것은 셀의 첫 번째 화면에 꽤 잘 작동합니다. 뷰로 스크롤하는 셀은 미리 그린 수 있으므로 해당 셀에서 애니메이션을 볼 수 없습니다. (적어도 그것은 내가 tableview로 테스트 할 때 관찰 한 것입니다).

+0

이것은 더 나은 접근 방법입니다. 내 컴퓨터로 돌아 가면이 컴퓨터가 작동하는지 확인할 수 있습니다. 감사 – Paulo