🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
UI

UIはUser Interfaceの略であり、人間がコンピュータとやりとりをするためのシステムです。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

2540閲覧

Swift 2つのCollectionViewのscroll検知とcellの連動。

Cyobi11

総合スコア7

UI

UIはUser Interfaceの略であり、人間がコンピュータとやりとりをするためのシステムです。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2019/12/20 14:09

前提・実現したいこと

独学で学ぶ初心者です。初投稿をさせていただきます。iPhoneに標準搭載されている写真アプリの写真プレビュー画面と同じUIを実装をしたいと考えています。
イメージ説明
画面上部と下部にCollectionviewを配置し、下部のcollectionViewをスクロールすると、上部のセルが連動するようにしたいです。contentOffSetで下部のcollectionViewをスクロールして、上部もスクロールするのではなく、上部はパラパラと表示が変わるようにしたいです。

発生している問題・エラーメッセージ

下部をスクロールするとおかしな動きをし、固まります。combineで正しくインデックスは取得しているですが、cellの生成か、渡し方がいけないのか、原因がわかりません。

ソースコードをコピペしていただけますと、挙動を確かめれます。

該当のソースコード

Swift5

1import UIKit 2import Combine 3 4class ViewController: UIViewController { 5 fileprivate let screenWidth = UIScreen.main.bounds.size.width 6 fileprivate let screenHeight = UIScreen.main.bounds.size.height 7 let model = Model() 8 fileprivate var mainCollectionView: UICollectionView! 9 fileprivate var thumbCollectionView: UICollectionView! 10 fileprivate var thumCollectionViewActive: Bool = true 11 @Published var collectionViewIndex: Int? = 0 12 private var validateCollectionViewIndex : AnyPublisher<Int?, Never> { 13 return $collectionViewIndex 14 .debounce(for: 0.4, scheduler: RunLoop.main) 15 .removeDuplicates() 16 .flatMap{ (collectionViewIndex) -> AnyPublisher<Int?, Never> in 17 Future<Int?, Never> { (promise) in 18 guard let collectionViewIndex = collectionViewIndex else { 19 promise(.success(nil)) 20 return 21 } 22 if 0 ... self.model.colors.count ~= collectionViewIndex { 23 promise(.success(collectionViewIndex)) 24 } else {promise(.success(nil))} 25 } 26 .eraseToAnyPublisher() 27 } 28 .eraseToAnyPublisher() 29 } 30 override func viewDidLoad() { 31 super.viewDidLoad() 32 setUpMainCollectionView() 33 setUpThumCollectionView() 34 bind() 35 } 36 override func viewDidAppear(_ animated: Bool) { 37 let displayDataIndex = model.colors.count 38 let indexPath = IndexPath(row: displayDataIndex - 1, section: 0) 39 thumbCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredHorizontally) 40 mainCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredHorizontally) 41 } 42 private func bind() { 43 _ = $collectionViewIndex 44 .subscribe(on: RunLoop.main) 45 .sink(receiveCompletion: { (completion) in print("validatedCollectionViewIndex.receiveCompletion: (completion)") }, receiveValue: { [weak self] (value) in 46 guard let value = value else {return} 47 print("validatedCollectionViewIndex.receiveValue: (String(describing: value))") 48 self?.mainCollectionView.selectItem(at: IndexPath(row: value, section: 0), animated: false, scrollPosition: .centeredHorizontally) 49 }) 50 } 51 func setUpMainCollectionView() { 52 let mainLayout = UICollectionViewFlowLayout() 53 mainLayout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) 54 mainLayout.minimumLineSpacing = 0 55 mainLayout.minimumInteritemSpacing = 0 56 mainLayout.itemSize = CGSize(width: screenWidth, height: screenHeight) 57 mainLayout.scrollDirection = .horizontal 58 let width = self.view.frame.size.width 59 let height = self.view.frame.size.height 60 mainCollectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: width, height: height), collectionViewLayout: mainLayout) 61 mainCollectionView.isPagingEnabled = true 62 mainCollectionView.isScrollEnabled = true 63 mainCollectionView.alwaysBounceVertical = false 64 mainCollectionView.showsHorizontalScrollIndicator = false 65 mainCollectionView.showsVerticalScrollIndicator = false 66 mainCollectionView.backgroundColor = UIColor.white 67 mainCollectionView.register(MainCollectionViewCell.self, forCellWithReuseIdentifier: "mainCell") 68 mainCollectionView.delegate = self 69 mainCollectionView.dataSource = self 70 self.view.addSubview(mainCollectionView) 71 } 72 func setUpThumCollectionView() { 73 let thumbLayout = UICollectionViewFlowLayout() 74 thumbLayout.sectionInset = UIEdgeInsets(top: 0, left: screenWidth * 0.5, bottom: 0, right: screenWidth * 0.4) 75 thumbLayout.minimumLineSpacing = 0 76 thumbLayout.minimumInteritemSpacing = 0 77 thumbLayout.itemSize = CGSize(width: screenWidth * 0.1, height: screenHeight * 0.1) 78 let width = self.view.frame.size.width 79 let height = self.view.frame.size.height 80 thumbCollectionView = UICollectionView(frame: CGRect(x: 0, y: (height * 0.9) - 25, width: width, height: height * 0.1 ), collectionViewLayout: thumbLayout) 81 thumbLayout.scrollDirection = .horizontal 82 thumbLayout.minimumLineSpacing = 0 83 thumbCollectionView.alwaysBounceVertical = false 84 thumbCollectionView.showsHorizontalScrollIndicator = false 85 thumbCollectionView.showsVerticalScrollIndicator = false 86 thumbCollectionView.backgroundColor = .darkGray 87 thumbCollectionView.register(ThumbnailCollectionViewCell.self, forCellWithReuseIdentifier: "thumCell") 88 thumbCollectionView.delegate = self 89 thumbCollectionView.dataSource = self 90 self.view.addSubview(thumbCollectionView) 91 } 92} 93 94extension ViewController: UICollectionViewDelegate { 95 func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 96 if collectionView == thumbCollectionView { 97 mainCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredHorizontally) 98 thumbCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true) 99 } 100 } 101} 102extension ViewController: UICollectionViewDataSource { 103func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 104 if collectionView == self.mainCollectionView { 105 let partitems = model.colors 106 return partitems.count 107 } else { 108 let partitems = model.colors 109 return partitems.count 110 } 111} 112func numberOfSections(in collectionView: UICollectionView) -> Int { 113 return 1 114} 115func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 116 if collectionView == self.mainCollectionView { 117 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mainCell",for: indexPath as IndexPath) as! MainCollectionViewCell 118 cell.backgroundColor = model.colors[indexPath.row] 119 return cell 120 } else { 121 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "thumCell",for: indexPath as IndexPath) as! ThumbnailCollectionViewCell 122 cell.backgroundColor = model.colors[indexPath.row] 123 return cell 124 } 125 } 126} 127extension ViewController { 128 func findCenterIndex() { 129 let center = self.view.convert(self.thumbCollectionView.center, to: self.thumbCollectionView) 130 let collectionViewIndexpath:IndexPath? = thumbCollectionView.indexPathForItem(at: center) 131 collectionViewIndex = collectionViewIndexpath?.row 132 } 133 func scrollViewDidScroll(_ scrollView: UIScrollView) { 134 if scrollView == mainCollectionView { 135 thumbCollectionView.contentOffset.x = mainCollectionView.contentOffset.x/10 136 } else if scrollView == thumbCollectionView { 137 self.findCenterIndex() 138 } 139 } 140} 141class MainCollectionViewCell: UICollectionViewCell { 142 override init(frame: CGRect) { 143 super.init(frame: frame) 144 } 145 required init?(coder aDecoder: NSCoder) { 146 fatalError("init(coder:) has not been implemented") 147 } 148} 149class ThumbnailCollectionViewCell: UICollectionViewCell { 150 override init(frame: CGRect) { 151 super.init(frame: frame) 152 } 153 required init?(coder aDecoder: NSCoder) { 154 fatalError("init(coder:) has not been implemented") 155 } 156} 157class Model { 158 let colors:Array<UIColor> = [ UIColor.white, UIColor.lightGray, UIColor.cyan, UIColor.white, UIColor.lightGray, UIColor.cyan, UIColor.white, UIColor.lightGray, UIColor.cyan, UIColor.white] 159}

補足情報

Swift5・Xcode13.3のIOS13で全てコードでの作成。
下部をscrollViewDidScroll(_ scrollView: UIScrollView)でスクロール検知し、indexPathForItem(at: center)でindexPathを取得しています。combineでインデックスとして上部に値を渡し、selectItem(at indexPath:)で上部のセルも連動したいです。かなり調べましたが、時間がかかっております。申し訳ありませんが何か解決方法が教えていただけないでしょうか?
皆様のお知恵をお借りできると大変助かります!

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

コピペして動作を確認してみました。
おかしな動きになる原因は、下部をドラッグしてスクロールしたことをscrollViewDidScrollで検知し、それに合わせて上部の表示位置を変更していますが、その上部の表示位置変更によって、今度は上部のscrollViewDidScrollが発生し、それによって下部のスクロール位置がまた変更されるためです。それがループしているのだと思います。

scrollViewWillBeginDraggingscrollViewDidEndDraggingを実装し、今どちらのCollectionViewをドラッグしているのか判定できるようにし、scrollViewDidScrollの中で、ドラッグ中でない方のCollectionViewの表示位置を変更すればうまくいくと思います。

投稿2019/12/23 01:56

TakeOne

総合スコア6299

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Cyobi11

2019/12/23 02:39

頂いたアンサーで実装してみたところおかしな動きになることはなく、問題なく実装することができました!!明確な回答でベストアンサーとさせていただきました! また、分からないところができましたら質問をさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問