- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我已经有一个 UICollectionView
,它垂直滚动并显示一组具有固定大小的自定义 UICollectionViewCell
。
现在我被要求在所有其他单元格顶部显示另一个 UICollectionView
,它应该 水平滚动 并且其 单元格大小是动态 (我只会在异步网络调用完成后知道大小)。此外,这个内部集合 View 可能并不总是需要显示 (这取决于从网络调用接收到的数据),但如果是,它应该只显示一次(在所有内容之上)。
我的问题是:处理第二个内部集合 View 的最佳方法应该是什么?我应该将它添加到外部 View Controller 作为它的不同类型的单元格,还是作为节标题?
也许另一种布局方法会更好?
编辑: 更多注意事项:
最佳答案
"how the best way to deal with this second and inner collection view should be?"
"Should I add it to the outer view controller as a different kind of cell of it, or maybe as a section header?"
"I'd need to animate the inner collection view when I'm going to show it"
"The whole thing should be vertically scrollable, this inner collection view should not stick to the top of the screen."
cellForItemAt indexPath
中)
UICollectionView
是独立的 View 。
UICollectionViewController
本质上是包含
UIViewController
的
UICollectionViewDelegate
、
UICollectionViewDataSource
和
UICollectionView
。就像任何 UIView 一样,您可以将
UICollectionView
子类化并将其添加到另一个 View 的 subview 中,例如
UICollectionViewCell
。通过这种方式,您可以将集合 View 添加到单元格并将单元格添加到该嵌套集合 View 。您还可以允许嵌套集合 View 处理来自
UICollectionViewDelegate
和
UICollectionViewDataSource
的所有委托(delegate)方法,从而使其模块化和可重用。您可以在
UICollectionView
方法中传递要显示在嵌套
convenience init
的每个单元格中的数据,并允许该类处理动画和设置。这是迄今为止最好的方法,不仅是为了重用,也是为了性能,尤其是当您以编程方式创建 View 时。
UICollectionViewController
,它将成为所有其他 View 的 View Controller 。
ParentCollectionView
和
HorizontalCollectionView
。 ParentCollectionView 是 UICollectionView 的一个空实现。我可以使用
collectionView
的
UICollectionViewController
但因为我希望它完全模块化,所以我稍后会将我的 ParentCollectionView 分配给 ViewController 的 collectionView。 ParentCollectionView 将处理 View 中的所有单元格静态单元格,包括包含我们的 HorizontalCollectionView 的单元格。 HorizontalCollectionView 将是所有“单元格对象”(您的数据模型)在其便利初始化程序中传递给它的委托(delegate)和数据源。也就是说 HorizontalCollectionView 将管理它自己的单元格,这样我们的
UICollectionViewController
就不会变胖。
UICollectionViewCell
类,一个是静态大小,另一个是动态(随机生成的 CGSize)。为了便于使用,我还有一个将类名作为标识符返回的扩展,我不喜欢将硬编码字符串用于可重用的单元格。这些单元格类别并不是完全不同,可以使用相同的单元格并在
sizeForItemAt indexPath
或
cellForItemAt indexPath
中更改单元格大小,但为了演示起见,我将说它们是完全不同的单元格,需要完全不同的数据模型。
UICollectionViewCell
作为标识符。
import UIKit
class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
// Programmically add our empty / custom ParentCollectionView
let parentCollectionView: ParentCollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = ParentCollectionView(frame: .zero, collectionViewLayout: layout)
cv.translatesAutoresizingMaskIntoConstraints = false
return cv
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
setup()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setup() {
// Assign this viewcontroller's collection view to our own custom one.
self.collectionView = parentCollectionView
// Set delegate and register Static and empty cells for later use.
parentCollectionView.delegate = self
parentCollectionView.register(StaticCollectionViewCell.self, forCellWithReuseIdentifier: StaticCollectionViewCell.identifier)
parentCollectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: UICollectionViewCell.identifier)
// Add simple Contraints
let guide = self.view.safeAreaLayoutGuide
parentCollectionView.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
parentCollectionView.leftAnchor.constraint(equalTo: guide.leftAnchor).isActive = true
parentCollectionView.rightAnchor.constraint(equalTo: guide.rightAnchor).isActive = true
parentCollectionView.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true
}
// MARK: - CollectionView
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// Erroneous Data from your network call, data should be a class property.
let data = Array.init(repeating: "0", count: 12)
// Skip if we dont have any data to show for the first row.
if (indexPath.row == 0 && data.count > 0) {
// Create a new empty cell for reuse, this cell will only be used for the frist cell.
let cell = parentCollectionView.dequeueReusableCell(withReuseIdentifier: UICollectionViewCell.identifier, for: IndexPath(row: 0, section: 0))
// Programmically Create a Horizontal Collection View add to the Cell
let horizontalView:HorizontalCollectionView = {
// Only Flow Layout has scroll direction
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
// Init with Data.
let hr = HorizontalCollectionView(frame: cell.frame, collectionViewLayout: layout, data: data)
return hr
}()
// Adjust cell's frame and add it as a subview.
cell.addSubview(horizontalView)
return cell
}
// In all other cases, just create a regular cell.
let cell = parentCollectionView.dequeueReusableCell(withReuseIdentifier: StaticCollectionViewCell.identifier, for: indexPath)
// Update Cell.
return cell
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// 30 sounds like enough.
return 30
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
//If you need your first row to be bigger return a larger size.
if (indexPath.row == 0) {
return StaticCollectionViewCell.size()
}
return StaticCollectionViewCell.size()
}
}
import UIKit
class ParentCollectionView: UICollectionView {
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
import Foundation
import UIKit
class HorizontalCollectionView: UICollectionView, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
// Your Data Model Objects
var data:[Any]?
// Required
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
}
convenience init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout, data:[Any]) {
self.init(frame: frame, collectionViewLayout: layout)
// Set These
self.delegate = self
self.dataSource = self
self.data = data
// Setup Subviews.
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// return zero if we have no data to show.
guard let count = self.data?.count else {
return 0
}
return count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = self.dequeueReusableCell(withReuseIdentifier: DynamicCollectionViewCell.identifier, for: indexPath)
// Do Some fancy Animation when scrolling.
let endingFrame = cell.frame
let transitionalTranslation = self.panGestureRecognizer.translation(in: self.superview)
if (transitionalTranslation.x > 0) {
cell.frame = CGRect(x: endingFrame.origin.x - 200, y: endingFrame.origin.y - 100, width: 0, height: 0)
} else {
cell.frame = CGRect(x: endingFrame.origin.x + 200, y: endingFrame.origin.y - 100, width: 0, height: 0)
}
UIView.animate(withDuration: 1.2) {
cell.frame = endingFrame
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// See DynamicCollectionViewCell size method, generate a random size.
return DynamicCollectionViewCell.size()
}
func setup(){
self.backgroundColor = UIColor.white
self.register(DynamicCollectionViewCell.self, forCellWithReuseIdentifier: DynamicCollectionViewCell.identifier)
// Must call reload, Data is not loaded unless explicitly told to.
// Must run on Main thread this class is still initalizing.
DispatchQueue.main.async {
self.reloadData()
}
}
}
import Foundation
import UIKit
class DynamicCollectionViewCell: UICollectionViewCell {
/// Get the Size of the Cell
/// Will generate a random width element no less than 100 and no greater than 350
/// - Returns: CGFloat
class func size() -> CGSize {
let width = 100 + Double(arc4random_uniform(250))
return CGSize(width: width, height: 100.0)
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup() {
self.backgroundColor = UIColor.green
}
}
import Foundation
import UIKit
class StaticCollectionViewCell: UICollectionViewCell {
/// Get the Size of the Cell
/// - Returns: CGFloat
class func size() -> CGSize {
return CGSize(width: UIScreen.main.bounds.width, height: 150.0)
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup() {
self.backgroundColor = UIColor.red
}
}
import UIKit
extension UICollectionViewCell {
/// Get the string identifier for this class.
///
/// - Returns: String
class var identifier: String {
return NSStringFromClass(self).components(separatedBy: ".").last!
}
}
关于ios - 另一个 Collection View 中的 Collection View : section header or cell?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51906411/
我在让“@header”或任何其他@规则在ANTLR中工作时遇到麻烦。具有非常基本的语法,如下所示: grammar test; options { language = CSharp2;
我对来源和寄宿有疑问 我有一个ajax页面“Page A”,它将称为ajax提要“Page B” 我看到来自ajax调用的“页面B”的请求 header 具有源“http://mydomain.com
我在 pandas 中使用了数据透视表并获得了所需的数据框格式,但现在我有两行标题。数据透视表后的结果数据框如下: scenario Actual Plan
我在 pandas 中使用了数据透视表并获得了所需的数据框格式,但现在我有两行标题。数据透视表后的结果数据框如下: scenario Actual Plan
我想在主机将它们发送到网络之前修改数据包头(IP 头、TCP 头)。 例如,如果我使用 firefox 进行浏览,那么我想拦截所有来自 firefox 的数据包并修改 IP/TCP header ,然
我的 header 内容被包装到#header 中,但是当我设置边框显示结构时,它显示我的#header 的内容出现在#header 本身之后。可能是什么问题?这是我的代码: #header { bo
我是一名 Web 开发人员,使用过 PHP 和 .NET。有一年多的 Web 工作经验,我一直无法彻底了解浏览器缓存功能,希望这里的 Web Gurus 可以帮助我。我心中的问题是: 浏览器实际上是如
伙计们,我有一个问题,我不知道如何在一个 header 中连接多个 header ,我们称它为“主 header ”并使用该 header 中的函数,例如 // A.h #include class
我有一个包含 SOAP 消息的 XMLHTTPRequest。 我想添加用于标识消息并将由 C# Web 服务使用的 guid。 GUID 的目标是识别特定用户,并应护送所有用户请求以在服务器上进行身
我一直在阅读粘性标题,这是我目前所发现的。第一个粘性 header 效果很好,但是当它遇到第一个 header 时,我如何向上滚动第一个 header 并使第二个 header 卡住? http://
我想将当前基于 TableView 的数据网格转换为新的 UICollectionView 类。 这就是我当前的网格的样子: 我的网格有两个标题: 年份(2006a、2007a 等)和 类型(“收入”
我目前正在使用 Apollo 服务器。我正在尝试在响应 header 中设置一个属性。并且此属性是从客户端 graphQL 请求 header 中检索的。 我在网上查了一下。并看到了诸如使用插件或扩展
我的 Controller 的方法需要设置一个标题,例如X-Authorization .创建新对象( store Action )后,我执行转发以显示新创建的对象( show Action ): $
我正在研究一些关于 VLAN 的事情,发现了 VLAN 标签 和 header 。 如果我们有标准 802.3 以太网帧 的 MTU(1518 字节), header 802.3 中包含什么? 另外,
我是放心和 Java 的新手,我正在尝试做一个非常基本的测试来检查 API 的响应是否为 200 ok。 谁能告诉我我需要在下面的脚本中更改什么才能传递多个 header Id、Key 和 ConId
在我的项目中,我需要知道 zlib header 是什么样的。我听说它相当简单,但我找不到 zlib header 的任何描述。 例如,它是否包含魔数(Magic Number)? 最佳答案 zlib
我正在使用 JMeter 测试 HTTP 服务器,该服务器接受并验证 APIKey 并在成功时返回一个有时限的 token 。如果我有 token ,我想发送一个 token ;如果没有,我想发送一个
以太网 header 是什么样的? 是吗: 1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|
我们的应用程序支持 CORS 配置 header 。我在两个不同的主机上分别配置了 testApp。两种设置都相互独立工作。host1 上的应用程序配置有 CORS header Access-Con
tlhelp32.h 不包含 windows.h 本身是有原因的吗?我一直在与大量的编译器错误作斗争,因为我在包含 tlhelp32.h 之后包含了 windows.h。这是设计决定还是出于什么原因?
我是一名优秀的程序员,十分优秀!