SwiftUI Text
ビューは、カスタムデザインのラベルを非常に簡単に作成できることがわかりました。そのため、通常のUIKit UICollectionViewCellのビューとして使用したいと思いました。
これはこれまでのところ私のコードです(Xcode 11内でコピーして貼り付けることができます)。
import SwiftUI
import UIKit
struct ContentView: View {
var body: some View {
CollectionComponent()
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
struct CollectionComponent : UIViewRepresentable {
func makeCoordinator() -> CollectionComponent.Coordinator {
Coordinator(data: [])
}
class Coordinator: NSObject, UICollectionViewDataSource, UICollectionViewDelegate {
var data: [String] = []
init(data: [String]) {
for index in (0...1000) {
self.data.append("\(index)")
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! GenericCell
cell.customView.rootView = AnyView(
Text(data[indexPath.item]).font(Font.title).border(Color.red)
)
return cell
}
}
func makeUIView(context: Context) -> UICollectionView {
let layout = UICollectionViewFlowLayout()
layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
layout.scrollDirection = .vertical
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.dataSource = context.coordinator
cv.delegate = context.coordinator
cv.register(GenericCell.self, forCellWithReuseIdentifier: "cell")
cv.backgroundColor = .white
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
return cv
}
func updateUIView(_ uiView: UICollectionView, context: Context) {
}
}
open class GenericCell: UICollectionViewCell {
public var customView = UIHostingController(rootView: AnyView(Text("")))
public override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
private func configure() {
contentView.addSubview(customView.view)
customView.view.preservesSuperviewLayoutMargins = false
customView.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
customView.view.leftAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leftAnchor),
customView.view.rightAnchor.constraint(equalTo: contentView.layoutMarginsGuide.rightAnchor),
customView.view.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor),
customView.view.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor),
])
}
}
最初の画面は良いです。
しかし、目に見える画面の最後を超えてスクロールすると、次のようになります
セルの自動サイズ変更で問題が発生していますか?それとも、これはより多くのSwiftUIバグですか?
[編集]SwiftUIの回答を受け入れましたが、この質問で尋ねられたように、UIKitを使用するための修正を提供できる人がいれば、受け入れます。
SwiftUIだけを使用して、必要なテキストビューをリフローするビューをまとめることができます。 コードはGitHubにあります ですが、非常に長いため、ここには投稿しません。何が起こっているかについての私の説明は この答え にあります。ここにデモがあります:
私はいくつかの変更を加えましたが、動作しますが、これはベストプラクティスではないと思います。
import SwiftUI
import UIKit
struct ContentView: View {
var body: some View {
CollectionComponent()
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
struct CollectionComponent : UIViewRepresentable {
func makeCoordinator() -> CollectionComponent.Coordinator {
Coordinator(data: [])
}
class Coordinator: NSObject, UICollectionViewDataSource, UICollectionViewDelegate {
var data: [String] = []
init(data: [String]) {
for index in (0...1000) {
self.data.append("\(index)")
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
data.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width/2.5, height: collectionView.frame.width/2)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! GenericCell
cell.customView?.rootView = Text(data[indexPath.item])
return cell
}
}
func makeUIView(context: Context) -> UICollectionView {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
let cvs = UICollectionView(frame: .zero, collectionViewLayout: layout)
cvs.dataSource = context.coordinator
cvs.delegate = context.coordinator
cvs.register(GenericCell.self, forCellWithReuseIdentifier: "cell")
cvs.backgroundColor = .white
return cvs
}
func updateUIView(_ uiView: UICollectionView, context: Context) {
}
}
public class GenericCell: UICollectionViewCell {
public var textView = Text("")
public var customView: UIHostingController<Text>?
public override init(frame: CGRect) {
super.init(frame: .zero)
customView = UIHostingController(rootView: textView)
customView!.view.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(customView!.view)
customView!.view.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
customView!.view.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true
customView!.view.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true
customView!.view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}