SwiftUI:如何让ScrollView移动一项



我的图像列表是一个水平滚动列表。列表中的图像显示为全屏宽度。默认情况下,它是连续移动的,然而,我想让它一次移动一个项目,我怎么能做到这一点。

我在这里搜索,有一些类似的问题与Android有关,但与iOS无关,特别是SwiftUI。

private struct PresentedImageList: View {
var images: [ImageViewModel]
var body: some View {
GeometryReader { gr in
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .top, spacing: 6) {
ForEach(self.images, id: .self) { image in
KFImage(source: .network(image.fileURL))
.resizable()
.frame(width: gr.size.width)
.aspectRatio(1.77, contentMode: .fit)
}
}
}.background(Color.black)
}
}
}

如果您有一个ScrollView出现,那么您可以简单地添加

.onAppear {
UIScrollView.appearance().isPagingEnabled = true
}

这段代码位于ScrollView闭包的末尾。

整个代码将是

private struct PresentedImageList: View {
var images: [ImageViewModel]
var body: some View {
GeometryReader { gr in
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .top, spacing: 6) {
ForEach(self.images, id: .self) { image in
KFImage(source: .network(image.fileURL))
.resizable()
.frame(width: gr.size.width)
.aspectRatio(1.77, contentMode: .fit)
}
}
}
.onAppear {
UIScrollView.appearance().isPagingEnabled = true
}
}
}
}

但是,如果出现多个ScrollView,则添加的代码将影响所有出现的ScrollView。

因此,在这种情况下,您可以使用TabView,而不是HStackView。

var body: some View {

GeometryReader { gr in
ScrollView(.horizontal, showsIndicators: false) {
TabView(alignment: .top, spacing: 6) {
ForEach(self.images, id: .self) { image in
KFImage(source: .network(image.fileURL))
.resizable()
.frame(width: gr.size.width)
.aspectRatio(1.77, contentMode: .fit)
}
}

//.tabViewStyle(PageTabViewStyle.page(indexDisplayMode: .never)) 
// --> in case you don't want the indicators
}
}
}

SwiftUI中,此选项不可用。所以需要使用UIKit

struct ContentView: View {
var images: [ImageViewModel]
var body: some View {
GeometryReader { gr in
ScrollViewUI(hideScrollIndicators: false) {
HStack(alignment: .top, spacing: 0) {
ForEach(self.images, id: .self) { image in
VStack {
KFImage(source: .network(image.fileURL))
.resizable()
.frame(width: gr.size.width-6,alignment: .center)
.aspectRatio(1.77, contentMode: .fit)
}
.frame(width: gr.size.width,alignment: .center)
}
}
}
}
}
}

ScrollViewUI

struct ScrollViewUI<Content: View>: UIViewControllerRepresentable {
var content: () -> Content
var hideScrollIndicators: Bool = false
init(hideScrollIndicators: Bool, @ViewBuilder content: @escaping () -> Content) {
self.content = content
self.hideScrollIndicators = hideScrollIndicators
}
func makeUIViewController(context: Context) -> ScrollViewController<Content> {
let vc = ScrollViewController(rootView: self.content())
vc.hideScrollIndicators = hideScrollIndicators
return vc
}
func updateUIViewController(_ viewController: ScrollViewController<Content>, context: Context) {
viewController.hostingController.rootView = self.content()
}
}

ScrollViewController

class ScrollViewController<Content: View>: UIViewController, UIScrollViewDelegate {
var hideScrollIndicators: Bool = false
lazy var scrollView: UIScrollView = {
let view = UIScrollView()
view.delegate = self
view.showsVerticalScrollIndicator = !hideScrollIndicators
view.showsHorizontalScrollIndicator = !hideScrollIndicators
view.bounces = false
view.backgroundColor = .clear
view.isPagingEnabled = true
return view
}()
init(rootView: Content) {
self.hostingController = UIHostingController<Content>(rootView: rootView)
self.hostingController.view.backgroundColor = .clear
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var hostingController: UIHostingController<Content>! = nil
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(scrollView)
view.backgroundColor = .clear
self.makefullScreen(of: self.scrollView, to: self.view)
self.hostingController.willMove(toParent: self)
self.scrollView.addSubview(self.hostingController.view)
self.makefullScreen(of: self.hostingController.view, to: self.scrollView)
self.hostingController.didMove(toParent: self)
}
func makefullScreen(of viewA: UIView, to viewB: UIView) {
viewA.translatesAutoresizingMaskIntoConstraints = false
viewB.addConstraints([
viewA.leadingAnchor.constraint(equalTo: viewB.leadingAnchor),
viewA.trailingAnchor.constraint(equalTo: viewB.trailingAnchor),
viewA.topAnchor.constraint(equalTo: viewB.topAnchor),
viewA.bottomAnchor.constraint(equalTo: viewB.bottomAnchor),
])
}
}

最新更新