Swift PageController 和图像的 ScrollView 布局问题 iOS
Swift ScrollView Layout Issue With PageController and Images iOS
我不知道如何为带有 imageView 的 scrollView 设置约束。
我正在使用带有 pageConroller 的滚动视图来浏览一堆图像。
看下图我的布局。
// imageView 代码
for index in 0..<drinksImagesArray.count {
frame.origin.x = scrollView.frame.size.width * CGFloat(index)
frame.size = scrollView.frame.size
let imageView = UIImageView(frame: frame)
imageView.contentMode = .scaleAspectFit
imageView.image = UIImage(named: imagesArray[index].name)
self.scrollView.addSubview(imageView)
}
scrollView.contentSize = CGSize(width: scrollView.frame.size.width * CGFloat(imagesArray.count), height: scrollView.frame.size.height)
scrollView.delegate = self
有什么建议吗?谢谢!
Layout
使用 auto-layout 你会好运得多 --- 它可以为你处理所有的帧大小和 .contentSize
。
这是一个简单的例子 - 它使用一个视图控制器,在 Storyboard 中添加了一个滚动视图,所以它应该很容易与您的代码集成:
class ScrollingImagesViewController: UIViewController {
@IBOutlet var scrollView: UIScrollView!
var drinksImagesArray: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// however you're populating your array...
drinksImagesArray = [
"drink1",
"drink2",
"drink3",
// etc...
]
// create a horizontal stack view
let stack = UIStackView()
stack.axis = .horizontal
stack.alignment = .fill
stack.distribution = .fillEqually
stack.spacing = 0
// add the stack view to the scroll view
stack.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(stack)
// use scroll view's contentLayoutGuide for content constraints
let svCLG = scrollView.contentLayoutGuide
NSLayoutConstraint.activate([
// stack view constrained Top / Bottom / Leading / Trailing of scroll view CONTENT guide
stack.topAnchor.constraint(equalTo: svCLG.topAnchor),
stack.bottomAnchor.constraint(equalTo: svCLG.bottomAnchor),
stack.leadingAnchor.constraint(equalTo: svCLG.leadingAnchor),
stack.trailingAnchor.constraint(equalTo: svCLG.trailingAnchor),
// stack view height == scroll view FRAME height
stack.heightAnchor.constraint(equalTo: scrollView.frameLayoutGuide.heightAnchor),
])
// create image views and add them to the stack view
drinksImagesArray.forEach { imgName in
let v = UIImageView()
v.backgroundColor = .lightGray
v.contentMode = .scaleAspectFit
// make sure we load a valid image
if let img = UIImage(named: imgName) {
v.image = img
}
stack.addArrangedSubview(v)
}
// stack distribution is set to .fillEqually, so we only need to set the
// width constraint on the first image view
// unwrap it
if let firstImageView = stack.arrangedSubviews.first {
firstImageView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor).isActive = true
}
}
}
编辑
查看您的故事板后...
Auto-layout 似乎不喜欢添加 UINavigationBar
和 UIToolbar
以及 UIScrollView
作为子视图。特别是,它似乎混淆了滚动视图的框架相关约束。
解决方法是首先为滚动视图添加约束:
- 顶部到导航栏底部
- 底部到页面控制顶部
- 前导和尾随 safe-area
故事板/界面生成器会抱怨滚动视图配置不正确。您可以忽略它,或者 select 滚动视图并将歧义设置为从不验证:
然后,在您的视图控制器中 class,我们需要为要添加到滚动视图的堆栈视图创建一个高度约束,并在 viewDidLayoutSubviews()
中设置该高度常量。
完整代码如下:
//
// WasserhaushaltViewController.swift
// deSynthTheOceans
//
// Created by robinsonhus0 on 24.03.20.
// Copyright © 2020 robinsonhus0. All rights reserved.
//
import UIKit
import AVFoundation
import Charts
import FSCalendar
import HealthKit
struct WasserSpeicher: Codable {
let wassermenge: Double
let speicherdatum: String
let speicherStelle: Double
}
class WasserhaushaltViewController: UIViewController, UIScrollViewDelegate {
@IBOutlet weak var diagrammView: UIView!
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var pageControl: UIPageControl!
let drinksImagesArray = ["tapWater", "water", "milk", "cola", "coffee", "tea", "juice", "beer"]
var imageIndex = Int()
struct Drinks {
var name: String
var tagesMengeFactor: Double
var gesamtMengeFactor: Double
}
var frame = CGRect(x: 0, y: 0, width: 0, height: 0)
var pageNumber = CGFloat()
@IBOutlet weak var todaysWaterConsumptionLabel: UILabel!
@IBOutlet weak var waterGoalProgress: UIProgressView!
@IBOutlet weak var waterGoalLabel: UILabel!
@IBOutlet weak var wasserMengeStepper: UIStepper!
@IBOutlet weak var motivationTextView: UITextView!
@IBOutlet weak var wasserglasButton: UIBarButtonItem!
@IBOutlet weak var kleineFlascheButton: UIBarButtonItem!
@IBOutlet weak var grosseFlascheButton: UIBarButtonItem!
@IBOutlet weak var overAllWaterConsumptionLabel: UILabel!
// added
let scrollingImagesStackView = UIStackView()
var stackHeightConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
pageControl.numberOfPages = drinksImagesArray.count
setupDrinkImages()
}
func setupDrinkImages() {
// set stack view properties
scrollingImagesStackView.axis = .horizontal
scrollingImagesStackView.alignment = .fill
scrollingImagesStackView.distribution = .fillEqually
scrollingImagesStackView.spacing = 0
// add the stack view to the scroll view
scrollingImagesStackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(scrollingImagesStackView)
// use scroll view's contentLayoutGuide for content constraints
let svCLG = scrollView.contentLayoutGuide
NSLayoutConstraint.activate([
// stack view constrained Top / Bottom / Leading / Trailing of scroll view CONTENT guide
scrollingImagesStackView.topAnchor.constraint(equalTo: svCLG.topAnchor),
scrollingImagesStackView.bottomAnchor.constraint(equalTo: svCLG.bottomAnchor),
scrollingImagesStackView.leadingAnchor.constraint(equalTo: svCLG.leadingAnchor),
scrollingImagesStackView.trailingAnchor.constraint(equalTo: svCLG.trailingAnchor),
])
// create the stack view height constraint - it will be updated in viewDidLayoutSubviews
stackHeightConstraint = scrollingImagesStackView.heightAnchor.constraint(equalToConstant: 0)
stackHeightConstraint.isActive = true
// create image views and add them to the stack view
drinksImagesArray.forEach { imgName in
let v = UIImageView()
v.backgroundColor = .orange
v.contentMode = .scaleAspectFit
// make sure we load a valid image
if let img = UIImage(named: imgName) {
v.image = img
}
scrollingImagesStackView.addArrangedSubview(v)
}
// stack distribution is set to .fillEqually, so we only need to set the
// width constraint on the first image view
// unwrap it
if let firstImageView = scrollingImagesStackView.arrangedSubviews.first {
firstImageView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor).isActive = true
}
scrollView.delegate = self
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// since we have a UINavigationBar and a UIToolBar in the view hierarchy,
// we need to set this here
// Note: if the view size changes
// stack view height == scroll view FRAME height
stackHeightConstraint.constant = scrollView.frame.height
}
// func setupDrinkImages() {
// for index in 0..<drinksImagesArray.count {
// frame.origin.x = scrollView.frame.size.width * CGFloat(index)
// frame.size = scrollView.frame.size
//
// let imageView = UIImageView(frame: frame)
// imageView.contentMode = .scaleAspectFit
// imageView.image = UIImage(named: drinksImagesArray[index])
// self.scrollView.addSubview(imageView)
// }
// scrollView.contentSize = CGSize(width: scrollView.frame.size.width * CGFloat(drinksImagesArray.count), height: scrollView.frame.size.height)
// scrollView.delegate = self
// }
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
pageControl.currentPage = Int(pageNumber)
}
}
您的(修改后的)故事板太大,无法在此处添加...如果您对上述更改有任何疑问,请在此处:https://pastebin.com/2Q1uFUgL
我不知道如何为带有 imageView 的 scrollView 设置约束。 我正在使用带有 pageConroller 的滚动视图来浏览一堆图像。
看下图我的布局。
// imageView 代码
for index in 0..<drinksImagesArray.count {
frame.origin.x = scrollView.frame.size.width * CGFloat(index)
frame.size = scrollView.frame.size
let imageView = UIImageView(frame: frame)
imageView.contentMode = .scaleAspectFit
imageView.image = UIImage(named: imagesArray[index].name)
self.scrollView.addSubview(imageView)
}
scrollView.contentSize = CGSize(width: scrollView.frame.size.width * CGFloat(imagesArray.count), height: scrollView.frame.size.height)
scrollView.delegate = self
有什么建议吗?谢谢!
Layout
使用 auto-layout 你会好运得多 --- 它可以为你处理所有的帧大小和 .contentSize
。
这是一个简单的例子 - 它使用一个视图控制器,在 Storyboard 中添加了一个滚动视图,所以它应该很容易与您的代码集成:
class ScrollingImagesViewController: UIViewController {
@IBOutlet var scrollView: UIScrollView!
var drinksImagesArray: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// however you're populating your array...
drinksImagesArray = [
"drink1",
"drink2",
"drink3",
// etc...
]
// create a horizontal stack view
let stack = UIStackView()
stack.axis = .horizontal
stack.alignment = .fill
stack.distribution = .fillEqually
stack.spacing = 0
// add the stack view to the scroll view
stack.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(stack)
// use scroll view's contentLayoutGuide for content constraints
let svCLG = scrollView.contentLayoutGuide
NSLayoutConstraint.activate([
// stack view constrained Top / Bottom / Leading / Trailing of scroll view CONTENT guide
stack.topAnchor.constraint(equalTo: svCLG.topAnchor),
stack.bottomAnchor.constraint(equalTo: svCLG.bottomAnchor),
stack.leadingAnchor.constraint(equalTo: svCLG.leadingAnchor),
stack.trailingAnchor.constraint(equalTo: svCLG.trailingAnchor),
// stack view height == scroll view FRAME height
stack.heightAnchor.constraint(equalTo: scrollView.frameLayoutGuide.heightAnchor),
])
// create image views and add them to the stack view
drinksImagesArray.forEach { imgName in
let v = UIImageView()
v.backgroundColor = .lightGray
v.contentMode = .scaleAspectFit
// make sure we load a valid image
if let img = UIImage(named: imgName) {
v.image = img
}
stack.addArrangedSubview(v)
}
// stack distribution is set to .fillEqually, so we only need to set the
// width constraint on the first image view
// unwrap it
if let firstImageView = stack.arrangedSubviews.first {
firstImageView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor).isActive = true
}
}
}
编辑
查看您的故事板后...
Auto-layout 似乎不喜欢添加 UINavigationBar
和 UIToolbar
以及 UIScrollView
作为子视图。特别是,它似乎混淆了滚动视图的框架相关约束。
解决方法是首先为滚动视图添加约束:
- 顶部到导航栏底部
- 底部到页面控制顶部
- 前导和尾随 safe-area
故事板/界面生成器会抱怨滚动视图配置不正确。您可以忽略它,或者 select 滚动视图并将歧义设置为从不验证:
然后,在您的视图控制器中 class,我们需要为要添加到滚动视图的堆栈视图创建一个高度约束,并在 viewDidLayoutSubviews()
中设置该高度常量。
完整代码如下:
//
// WasserhaushaltViewController.swift
// deSynthTheOceans
//
// Created by robinsonhus0 on 24.03.20.
// Copyright © 2020 robinsonhus0. All rights reserved.
//
import UIKit
import AVFoundation
import Charts
import FSCalendar
import HealthKit
struct WasserSpeicher: Codable {
let wassermenge: Double
let speicherdatum: String
let speicherStelle: Double
}
class WasserhaushaltViewController: UIViewController, UIScrollViewDelegate {
@IBOutlet weak var diagrammView: UIView!
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var pageControl: UIPageControl!
let drinksImagesArray = ["tapWater", "water", "milk", "cola", "coffee", "tea", "juice", "beer"]
var imageIndex = Int()
struct Drinks {
var name: String
var tagesMengeFactor: Double
var gesamtMengeFactor: Double
}
var frame = CGRect(x: 0, y: 0, width: 0, height: 0)
var pageNumber = CGFloat()
@IBOutlet weak var todaysWaterConsumptionLabel: UILabel!
@IBOutlet weak var waterGoalProgress: UIProgressView!
@IBOutlet weak var waterGoalLabel: UILabel!
@IBOutlet weak var wasserMengeStepper: UIStepper!
@IBOutlet weak var motivationTextView: UITextView!
@IBOutlet weak var wasserglasButton: UIBarButtonItem!
@IBOutlet weak var kleineFlascheButton: UIBarButtonItem!
@IBOutlet weak var grosseFlascheButton: UIBarButtonItem!
@IBOutlet weak var overAllWaterConsumptionLabel: UILabel!
// added
let scrollingImagesStackView = UIStackView()
var stackHeightConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
pageControl.numberOfPages = drinksImagesArray.count
setupDrinkImages()
}
func setupDrinkImages() {
// set stack view properties
scrollingImagesStackView.axis = .horizontal
scrollingImagesStackView.alignment = .fill
scrollingImagesStackView.distribution = .fillEqually
scrollingImagesStackView.spacing = 0
// add the stack view to the scroll view
scrollingImagesStackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(scrollingImagesStackView)
// use scroll view's contentLayoutGuide for content constraints
let svCLG = scrollView.contentLayoutGuide
NSLayoutConstraint.activate([
// stack view constrained Top / Bottom / Leading / Trailing of scroll view CONTENT guide
scrollingImagesStackView.topAnchor.constraint(equalTo: svCLG.topAnchor),
scrollingImagesStackView.bottomAnchor.constraint(equalTo: svCLG.bottomAnchor),
scrollingImagesStackView.leadingAnchor.constraint(equalTo: svCLG.leadingAnchor),
scrollingImagesStackView.trailingAnchor.constraint(equalTo: svCLG.trailingAnchor),
])
// create the stack view height constraint - it will be updated in viewDidLayoutSubviews
stackHeightConstraint = scrollingImagesStackView.heightAnchor.constraint(equalToConstant: 0)
stackHeightConstraint.isActive = true
// create image views and add them to the stack view
drinksImagesArray.forEach { imgName in
let v = UIImageView()
v.backgroundColor = .orange
v.contentMode = .scaleAspectFit
// make sure we load a valid image
if let img = UIImage(named: imgName) {
v.image = img
}
scrollingImagesStackView.addArrangedSubview(v)
}
// stack distribution is set to .fillEqually, so we only need to set the
// width constraint on the first image view
// unwrap it
if let firstImageView = scrollingImagesStackView.arrangedSubviews.first {
firstImageView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor).isActive = true
}
scrollView.delegate = self
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// since we have a UINavigationBar and a UIToolBar in the view hierarchy,
// we need to set this here
// Note: if the view size changes
// stack view height == scroll view FRAME height
stackHeightConstraint.constant = scrollView.frame.height
}
// func setupDrinkImages() {
// for index in 0..<drinksImagesArray.count {
// frame.origin.x = scrollView.frame.size.width * CGFloat(index)
// frame.size = scrollView.frame.size
//
// let imageView = UIImageView(frame: frame)
// imageView.contentMode = .scaleAspectFit
// imageView.image = UIImage(named: drinksImagesArray[index])
// self.scrollView.addSubview(imageView)
// }
// scrollView.contentSize = CGSize(width: scrollView.frame.size.width * CGFloat(drinksImagesArray.count), height: scrollView.frame.size.height)
// scrollView.delegate = self
// }
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
pageControl.currentPage = Int(pageNumber)
}
}
您的(修改后的)故事板太大,无法在此处添加...如果您对上述更改有任何疑问,请在此处:https://pastebin.com/2Q1uFUgL