struct GridView<CellView: View>: UIViewRepresentable { let cellView: (Int) -> CellView let proxy: GeometryProxy var numbers: [Int] init(_ numbers: [Int], proxy: GeometryProxy, @ViewBuilder cellView: @escaping (Int) -> CellView) { self.proxy = proxy self.cellView = cellView self.numbers = numbers } func makeUIView(context: Context) -> UICollectionView { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .vertical layout.minimumLineSpacing = 20 layout.minimumInteritemSpacing = 10 layout.itemSize = CGSize(width: 234, height: 240) let collectionView = UICollectionView(frame: proxy.frame(in: .global), collectionViewLayout: layout) collectionView.backgroundColor = bcBodyBackUIColor collectionView.register(GridCellView.self, forCellWithReuseIdentifier: "CELL") collectionView.dragInteractionEnabled = true collectionView.dataSource = context.coordinator collectionView.delegate = context.coordinator collectionView.contentInset = UIEdgeInsets(top: 28, left: 28, bottom: 28, right: 28) return collectionView } func updateUIView(_ uiView: UICollectionView, context: Context) { } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { var parent: GridView var collectionView: UICollectionView? init(_ parent: GridView) { self.parent = parent } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { self.collectionView = collectionView return parent.numbers.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CELL", for: indexPath) as! GridCellView cell.layer.backgroundColor = bcBodyBackUIColor.cgColor cell.backgroundColor = .clear cell.cellView.rootView = AnyView(parent.cellView(parent.numbers[indexPath.row]).fixedSize()) let tap = UILongPressGestureRecognizer(target: self, action: #selector(delectBtn(_:))) tap.minimumPressDuration = 0.1 cell.addGestureRecognizer(tap) return cell } @objc func delectBtn(_ sender: UILongPressGestureRecognizer) { switch sender.state { case .began: let selectedCellIndex = self.collectionView!.indexPathForItem(at: sender.location(in: collectionView)) self.collectionView!.beginInteractiveMovementForItem(at: selectedCellIndex!) case .changed: self.collectionView!.updateInteractiveMovementTargetPosition(sender.location(in: collectionView)) case .ended: self.collectionView!.endInteractiveMovement() default: self.collectionView!.cancelInteractiveMovement() } } func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { let tempMybook = self.parent.numbers[sourceIndexPath.item] self.parent.numbers.remove(at: sourceIndexPath.item) self.parent.numbers.insert(tempMybook, at: destinationIndexPath.item) } } }
class GridCellView: UICollectionViewCell { public var cellView = UIHostingController(rootView: AnyView(EmptyView())) 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(cellView.view) cellView.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ cellView.view.leftAnchor.constraint(equalTo: contentView.leftAnchor), cellView.view.rightAnchor.constraint(equalTo: contentView.rightAnchor), cellView.view.topAnchor.constraint(equalTo: contentView.topAnchor), cellView.view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) ]) cellView.view.layer.masksToBounds = true cellView.view.layer.backgroundColor = bcBodyBackUIColor.cgColor } }
struct MyView: View { var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9] var body: some View { GeometryReader { proxy in GridView(self.numbers, proxy: proxy) { number in Text(String(number)) } }.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height - 150) } }