ios - 在 collectionviewcell 中动画化 View

标签 ios swift uicollectionviewcell uiviewanimation uiprogressview

我有点卡住了 progressView 的动画(使用这个子类:Linear Progress View)。

只是一些背景知识,所以下面发布的代码很有意义。我创建了一个具有一些基本功能的 UICollectionViewCell 的子类。这样做的主要原因是减少样板代码。在我的 Collection View 中,我将单元格设置为我的子类并将模型对象传递给它。所有数据都正确显示,但进度 View 没有动画。我在 Collection View 上尝试过 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
}


}

我确信这很简单,但我忘了实现。

谢谢你们这些美丽的人!

最佳答案

您看不到任何动画,因为没有要设置动画的可见变化。具体来说,您在显示单元格之前从 didSet 调用 setProgress,然后您再也不会调用它。

要查看动画,您必须允许 View 以某个初始值 (0%) 显示,然后再次调用 setProgress,将更改动画化为真值。

从 UI 的角度来看,您尝试做的事情不是一个好主意——原则上,进度条应该仅在发生某些实际有意义的进展(用户操作、下载等)时才移动。因此,我对你的问题的回答是在这种情况下使用没有动画的进度条。

话虽这么说,但在某些合理的情况下,您可能希望更新单元格中的进度条而不必重新加载单元格。 例如,如果您有一些正在运行的后台任务定期报告与每个单元格相关的进度。有大量的答案展示了进行这种更新的不同方法。

此外,还有一些建议用于在显示单元格后立即触发更新。如果您想查看其中一些想法,请搜索不存在的“DidDisplayCell”委托(delegate)方法的问题。您绝对可以在单元格显示之后制作动画,但我想让您远离将动画用于人为目的的诱惑。

下面是一些代码片段,用于说明如何使用 WillDisplay 中的 asyncAfter 执行此操作(我使用 tableview 对此进行了测试):

// 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)。

关于ios - 在 collectionviewcell 中动画化 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47242942/

相关文章:

json - Three20 和 Facebook Graph API 问题

ios - 接受函数的回调作为参数

ios - 滚动后 CollectionView 未填充

ios - UI Collection View 单元格和自动布局

ios - 为 collectionView 中的每个其他项目设置特定布局

ios - SIGSEGV 和 SIGBUS 使用 Xamarin.iOS 统一 API 崩溃

iphone - 如何使用 iOS 的 api 1.1 获取 Twitter 个人资料图片?

ios - 使用搜索栏取消按钮关闭模态视图 Controller

ios - 在 iOS 上使用 swift 绘制 View 后以编程方式绘制新图层以进行查看

ios - swift 3 : How to center horizontally the last row of cells in a UICollectionView with only one section?