使用UICollectionViews创建动态和多个功能

时间:2017-06-02 15:12:26

标签: ios uitableview uicollectionview

我有兴趣创建一个包含多个功能的视图,用户可以向下滚动并查看图片,说明,评论,轮播等。我知道UICollectionView能够提供此类型布局。我最初认为UITableViews是最好的方法。

我已经查看了几个教程和GitHub repos,但大多数只是在标准网格布局中使用UICollectionView。我还查看了 Instagram 使用的IGListKit以及与之相关的一些教程。

我的目标是获得类似 KitchenStories 应用的内容:

enter image description here

我想知道是否有人可以就最佳方向和方法向我提出建议。

1 个答案:

答案 0 :(得分:1)

不要试图对任何单一视图做太多,即使是UICollectionView

您展示的屏幕有一个UITabBarController来管理其顶级排列。当前选中的标签(“主页”)有UINavigationController管理其内容。

导航堆栈的顶部可能是集合视图或表视图。这两者都可以使用,因为元素在视觉上布局为堆栈中的屏幕宽度行。表格视图更简单,因为您不必担心设置布局。

表视图有几个可见的行,每个行都不同:

  • 标题/图像行(“Easy seafood paella”)
  • 评级行
  • 导出行(hearts / save / share)
  • 评论行
  • 创作者行(我假设,因为它看起来可能是爆头和名字)

可能还有更多独特的行。

在故事板中,您可以将每个行设计为表视图控制器场景中的原型行。或者,您可以使用静态内容行设计表视图,如果您不需要在运行时更改行的顺序或复制任何行,这将更容易。

“但Rob,”你说,“我无法将所有这些行放入我的故事板中的表格视图中!”Make the storyboard scene taller. UIKit会在运行时调整它以适应设备屏幕。

在每一行中,拖入并排列该行数据所需的子视图。例如,标题/图片行需要UIImageViewUILabel。评级行需要一个标签,可能是显示和编辑星星的自定义视图,也可能是布局的堆栈视图。

对于每一行,您需要一个单独的UITableViewCell子类,其中包含该行视图的出口。要将数据传递到每个单元格以进行显示,请使每个单元格符合协议:

protocol RecipeUsing {
    var recipe: Recipe? { get set }
}

然后,在表视图控制器中,如果您使用静态内容,则将其设置为:

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = super.tableView(tableView, cellForRowAt: indexPath)
        if let user = cell as? RecipeUsing {
            user.recipe = recipe
        }
        return cell
    }

您需要RecipeTitleImageCell一个UIImageViewUILabel的出口。像这样:

class RecipeTitleImageCell: UITableViewCell, RecipeUsing {

    @IBOutlet var label: UILabel!

    // UITableViewCell has an imageView property that's not an outlet 
    @IBOutlet var myImageView: UIImageView!

    var recipe: Recipe? {
        didSet {
            guard let recipe = recipe else { return }
            label.text = recipe.title
            myImageView.image = recipe.image
        }
    }
}

对于评级行,你会想要这样的东西:

class RecipeRatingsCell: UITableViewCell, RecipeUsing {
    @IBOutlet var ratingControl: RatingControl!
    @IBOutlet var label: UILabel!

    var recipe: Recipe? {
        didSet {
            guard let recipe = recipe else { return }
            ratingControl.rating = recipe.ratings.reduce(0, +) / recipe.Double(ratings.count)

            if ratings.count < 5 { label.text = "Too few ratings" }
            else { label.text = "\(ratings.count) ratings" }
        }
    }
}