LoginSignup
23
19

More than 3 years have passed since last update.

SwiftUIで画像をページングする

Last updated at Posted at 2019-12-06

はじめに

今作っているアプリで、Instagramのように写真をページングで表示したいと思い、SwiftUIのCustomViewを作ってみました。

SwiftUIのScrollViewのscrollイベントを検知する方法や、ScrollViewをprogrammaticallyにscrollする方法を見つけるのに苦戦したので、同じことをしたい人にとって きっと役に立つと思います。

完成イメージ

ImagePagerDemo.gif

E7系、かっこいい

ソース

画像、"e7_square","e5_square","doctor_yellow_square"は、お手持ちの画像に置き換えてください。

ImagePager.swift
import SwiftUI

struct ImagePager: View {

    var imageNames: [String]

    @State private var index: Int = 0
    @State private var offset: CGFloat = 0

    var body: some View {
        GeometryReader { geometry in // 1. offset(scroll位置)を操作するため、GeometryReaderを利用
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 0) {
                    ForEach(0..<self.imageNames.count) {
                        Image(self.imageNames[$0])
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(width: geometry.size.width, height: geometry.size.width)
                    }
                }
            }
            .content.offset(x: self.offset) // 2. self.offsetとscrollViewのoffsetをバインディング
            .frame(width: geometry.size.width, height: nil, alignment: .leading)
            .gesture(DragGesture()
                .onChanged({ value in  // 3. Dragを監視。Dragに合わせて、スクロールする。
                    self.offset = value.translation.width - geometry.size.width * CGFloat(self.index)
                })
                .onEnded({ value in // 4. Dragが完了したら、Drag量に応じて、indexを更新
                    let scrollThreshold = geometry.size.width / 2
                    if value.predictedEndTranslation.width < -scrollThreshold {
                        self.index = min(self.index + 1, self.imageNames.endIndex - 1)
                    } else if value.predictedEndTranslation.width > scrollThreshold {
                        self.index = max(self.index - 1, 0)
                    }

                    withAnimation { // 5. 更新したindexの画像をアニメーションしながら表示する。
                        self.offset = -geometry.size.width * CGFloat(self.index)
                    }
                })
            )
        }
    }
}

struct Carousel_Previews: PreviewProvider {
    static var previews: some View {
        ImagePager(imageNames: [
            "e7_square",
            "e5_square",
            "doctor_yellow_square"
        ])
    }
}

解説

  1. offset(scroll位置)を操作するため、GeometryReaderを利用
  2. self.offsetとscrollViewのoffsetをバインディング
  3. Dragを監視。Dragに合わせて、スクロールする。
  4. Dragが完了したら、Drag量に応じて、indexを更新
  5. 更新したindexの画像をアニメーションしながら表示する。

参考

以上です。

23
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
19