質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.31%

Q&A

解決済

1回答

687閲覧

swiftUI scrollView scrollTo で 要素が一つだけ飛ばされてスクロールされる

RAKUDA

総合スコア10

0グッド

0クリップ

投稿2023/10/23 23:30

編集2023/10/23 23:31

実現したいこと

scrollToで一つ一つスクロールできるようにしたい。

前提

環境
xcode 15.01
ios17

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

なぜか5だけ飛ばされる
しかも0~4ときて5を押した時だけ。
6から5を押すと何事もなくスクロールされる。

該当のソースコード

swift

1import SwiftUI 2 3struct ContentView: View { 4 @State var aitem = 9 5 6 var body: some View { 7 VStack{ 8 let a = Array<Int>(1...20) 9 ForEach(0..<5) { row in 10 HStack(spacing: 0) { 11 ForEach(0..<4) { column in 12 Button { 13 aitem = (row * 4 + column) 14 } label: { 15 Text((row * 4 + column).description) 16 .padding(20) 17 } 18 } 19 } 20 } 21 HorizontalWheelPicker_cigma(initialCenterItem: 7, selection: $aitem, items: a) 22 } 23 } 24} 25 26 27struct HorizontalWheelPicker_beta<Item: Equatable>: View { 28 var position: Int 29 @Binding var positioningItem: Item 30 31 var items: [itemWithID<Item>] 32 @State private var scrollID: Int? 33 let numItem: Int 34 let str: String = "" 35 36 init (initialCenterItem item: Item, 37 selection: Binding<Item> = Binding.constant(0), 38 numItem: Int = 5, items: [Item]) { 39 self.position = items.firstIndex(of: item)! 40 self._positioningItem = selection 41 self.numItem = numItem 42 self.items = items.map { itemWithID(item: $0) } 43 print("init") 44 } 45 46 struct itemWithID<T>: Identifiable { 47 let id = UUID() 48 let item: T 49 } 50 51 var body: some View { 52 if #available(iOS 17.0, *) { 53 VStack { 54 GeometryReader { geometry in 55 let width = geometry.size.width 56 let itemWidth = width / CGFloat(numItem) 57 58 ScrollViewReader { proxy in 59 ScrollView(.horizontal, showsIndicators: false) { 60 LazyHStack(alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/, spacing: 0) { 61 ForEach(0..<items.count, id: \.self) { index in 62 if 0..<items.count ~= index { 63 Text(index.description) 64 .id(items[index].id) 65 .frame(width: itemWidth) 66 } 67 } 68 } 69 .scrollTargetLayout() 70 .onAppear { 71 proxy.scrollTo(items[0].id, anchor: .center) 72 } 73 .safeAreaPadding(.horizontal, itemWidth * CGFloat(numItem / 2)) 74 .onChange(of: positioningItem) { _ in 75 print(items[reIndex(items, item: positioningItem)]) 76 withAnimation { 77 print("\(positioningItem) : \(reIndex(items, item: positioningItem))") 78 proxy.scrollTo(items[reIndex(items, item: positioningItem)].id, anchor: .center) 79 } 80 } 81 } 82 } 83 .scrollTargetBehavior(.viewAligned) 84 .scrollPosition(id: $scrollID) 85 } 86 } 87 } 88 } 89 90 func reIndex(_ idItems: [itemWithID<Item>], item: Item) -> Int { 91 for i in 0..<idItems.count { 92 if idItems[i].item == item { 93 return i 94 } 95 } 96 return 0 97 } 98}

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

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

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

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

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

hoshi-takanori

2023/10/24 18:29

たぶん、itemWidth が整数じゃないと誤差が生じてるような…。
RAKUDA

2023/10/25 00:21

floorで切り捨てたら正常な動作になりました。
RAKUDA

2023/10/25 00:23

幅が細かいと、中央に合わせきれない ということでしょうか?
hoshi-takanori

2023/10/25 01:28

想像ですが、浮動小数点で座標を計算する際の誤差かと…。
RAKUDA

2023/10/25 02:32

次からframeの指定には気をつけるようにします。 ありがとうございました。
guest

回答1

0

自己解決

widthに指定していた数値の少数を切り捨てると正常になりました。
コメントにもあるように、浮動小数点を使用して座標計算する際の誤差によるものではないかと言う結論に至りました。

回答してくださったhoshi-takanori様、大変ありがとうございました。

投稿2023/10/25 02:38

編集2023/10/25 02:40
RAKUDA

総合スコア10

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問