swift 中按下集合视图单元格时如何修复自定义视图中的约束
How to fix constraints in custom view when collection view cell pressed in swift
我有一个测试应用程序,这是我第一次尝试以编程方式创建 100%。我有一个简单的 collectionView,每个单元格中都有一个图像和一个标签。
当我按下单元格时,会弹出一个自定义视图,其中包含红色和蓝色两个视图,将来会有内容,但现在只有两个视图。
我想让该应用程序在纵向和横向模式下都能正常工作,一开始它运行良好。我第一次按下单元格时,弹出视图适用于纵向和横向。
这是我希望在按下单元格时发生的情况,但是当我单击视图使其消失,然后按下任何单元格时,问题就出现了:
第一个方向,无论是横向还是纵向,都很好,但是当我现在改变方向时,问题就出现了,因为按下了第二个或更多的单元格。
我尝试使用首次亮相的视图层次结构,这就是错误屏幕的样子。
我遵循的主要思想是来自该站点的教程:
https://iosrevisited.blogspot.com/2017/10/adaptive-autolayout-programmatically-iphone-x.html
我能够完成本教程,并且效果很好。我所拥有的不同之处在于,我的视图应该在用户需要时出现和消失。
这是具有 collectionView 的视图控制器的代码:
import UIKit
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 100, height: 150)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! TestingCollectionViewCell
cell.backgroundColor = .white
let img = UIImage(named: self.items[indexPath.row])
cell.imageView.image = img
cell.imageName.text = "\(self.items[indexPath.row])"
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("\(items[indexPath.row])")
self.presentInfoView(withInfo: items[indexPath.row])
}
}
class ViewController: UIViewController, BlurDelegate {
func removeBlurView() {
for subview in view.subviews {
if subview.isKind(of: UIVisualEffectView.self) {
subview.removeFromSuperview()
self.infoView.removeFromSuperview()
}
}
}
let infoView: InfoView = {
let view = InfoView()
view.layer.cornerRadius = 5
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
fileprivate var items: [String] = [
"photo1",
"photo2",
"photo3",
"photo4",
"photo5",
"photo6",
"photo7",
"photo8",
"photo9",
"photo10",
"photo11",
"photo12",
"photo13",
"photo14",
"photo15",
"photo16",
"photo17",
"photo18",
"photo19",
"photo20",
"photo21",
"photo22",
"photo23",
"photo24"
]
override func viewDidLoad() {
super.viewDidLoad()
let collection = UICollectionView(frame: view.frame, collectionViewLayout: UICollectionViewFlowLayout())
//allows us to use auto layout constraints
collection.translatesAutoresizingMaskIntoConstraints = false
collection.backgroundColor = .black
view.addSubview(collection)
collection.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
collection.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
collection.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
collection.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
collection.dataSource = self
collection.delegate = self
collection.register(TestingCollectionViewCell.self, forCellWithReuseIdentifier: "cell")
self.navigationItem.title = "Testing"
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
var touch: UITouch? = touches.first
if touch?.view != infoView {
dismissView()
}
}
func dismissView() {
//dismiss(animated: true, completion: nil)
removeBlurView()
}
func setBlurView() {
let blurView = UIVisualEffectView()
blurView.frame = view.frame
blurView.effect = UIBlurEffect(style: .regular)
blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(blurView)
}
func presentInfoView(withInfo info: String) {
setBlurView()
view.addSubview(infoView)
infoView.addView()
let img = UIImage(named: info)
infoView.imageView.image = img
infoView.nameLbl.text = info
infoView.backgroundColor = .white
infoView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
infoView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8).isActive = true
//infoView.widthAnchor.constraint(equalToConstant: view.frame.width - 64).isActive = true
infoView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.8).isActive = true
//infoView.heightAnchor.constraint(equalToConstant: view.frame.height - 64).isActive = true
infoView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -44).isActive = true
infoView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
infoView.alpha = 0
UIView.animate(withDuration: 0.5) {
self.infoView.alpha = 1
self.infoView.transform = .identity
}
}
}
为了清楚起见,我们的目的是让模糊视图随着视图的出现而出现和消失。
这是单元格出现时将出现的视图的代码:
import UIKit
protocol BlurDelegate: class {
func removeBlurView()
}
class InfoView: UIView {
let topView: UIView = {
let view = UIView()
view.backgroundColor = .blue
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let btmView: UIView = {
let view = UIView()
view.backgroundColor = .red
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var portraitConstraints: [NSLayoutConstraint] = []
var landscapeConstraints: [NSLayoutConstraint] = []
override init(frame: CGRect) {
super.init(frame: frame)
NotificationCenter.default.addObserver(self, selector: #selector(toggleConstraints), name: UIDevice.orientationDidChangeNotification, object: nil)
//addView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder: ) has not been implemented")
}
func addView() {
let guide = self.safeAreaLayoutGuide
//image layout
self.addSubview(topView)
let defaultImgTop = topView.topAnchor.constraint(equalTo: guide.topAnchor)
let defaultImgLeading = topView.leadingAnchor.constraint(equalTo: guide.leadingAnchor)
//portrait
let portraitImgTrailing = topView.trailingAnchor.constraint(equalTo: guide.trailingAnchor)
let portraitImgHeight = topView.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: 0.5)
//lbl layouts
self.addSubview(btmView)
let defaultlblTrailing = btmView.trailingAnchor.constraint(equalTo: guide.trailingAnchor)
let defaultLblBottom = btmView.bottomAnchor.constraint(equalTo: guide.bottomAnchor)
//portrait
let portraitLblBottom = btmView.topAnchor.constraint(equalTo: topView.bottomAnchor)
let portraitLblLeading = btmView.leadingAnchor.constraint(equalTo: guide.leadingAnchor)
//imageView landscape constraints
let landscapeImgBottom = topView.bottomAnchor.constraint(equalTo: guide.bottomAnchor)
let landscapeImgWidth = topView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5)
//label landscape constraints
let landscapeLblTop = btmView.topAnchor.constraint(equalTo: guide.topAnchor)
let landscapeLblLeading = btmView.leadingAnchor.constraint(equalTo: topView.trailingAnchor)
let defaultConstriants = [defaultImgTop, defaultImgLeading, defaultLblBottom, defaultlblTrailing]
portraitConstraints = [portraitImgHeight, portraitImgTrailing, portraitLblBottom, portraitLblLeading]
landscapeConstraints = [landscapeImgBottom, landscapeLblTop, landscapeLblLeading, landscapeImgWidth]
self.addConstraints(defaultConstriants)
toggleConstraints()
}
@objc func toggleConstraints() {
if UIDevice.current.orientation.isLandscape {
self.removeConstraints(portraitConstraints)
self.addConstraints(landscapeConstraints)
} else {
self.removeConstraints(landscapeConstraints)
self.addConstraints(portraitConstraints)
}
}
}
我从我在上面添加的网站得到这个视图的想法。我不得不改变一些东西,因为它是一个视图,但它应该是一样的。我认为错误在于此,但我尝试更改纵向和横向的约束,但没有用。我试着把它写下来,看看哪些约束被删除了,然后又更新了,但我似乎无法找到是哪个约束在困扰我。
我知道问题应该出在红色视图的顶部锚点或蓝色视图的底部锚点,但我无法弄清楚哪个是错误的。
我希望这些信息足够了,但请问我是否还有其他需要帮助的地方。
另外,如果不是很麻烦的话,如果您注意到视图出现时,导航栏似乎并没有模糊。这使得自定义视图看起来像是在顶部被截断了。如果您知道一种方法来模糊导航栏,或者尝试将视图的顶部锚点向下推以使其看起来不那么糟糕,我们将不胜感激。
我试过
self.navigationItem.bottomAnchor
我尝试在视图中添加一个带有常量的顶部锚点,但我上面的配置是我能找到的让视图每次都正确显示的最佳方式。
非常感谢
presentInfoView 函数删除 infoView.addView()
override init(frame: CGRect) {
super.init(frame: frame)
NotificationCenter.default.addObserver(self, selector: #selector(toggleConstraints), name: UIDevice.orientationDidChangeNotification, object: nil)
addView()
}
我有一个测试应用程序,这是我第一次尝试以编程方式创建 100%。我有一个简单的 collectionView,每个单元格中都有一个图像和一个标签。
当我按下单元格时,会弹出一个自定义视图,其中包含红色和蓝色两个视图,将来会有内容,但现在只有两个视图。
我想让该应用程序在纵向和横向模式下都能正常工作,一开始它运行良好。我第一次按下单元格时,弹出视图适用于纵向和横向。
这是我希望在按下单元格时发生的情况,但是当我单击视图使其消失,然后按下任何单元格时,问题就出现了:
第一个方向,无论是横向还是纵向,都很好,但是当我现在改变方向时,问题就出现了,因为按下了第二个或更多的单元格。
我尝试使用首次亮相的视图层次结构,这就是错误屏幕的样子。
我遵循的主要思想是来自该站点的教程: https://iosrevisited.blogspot.com/2017/10/adaptive-autolayout-programmatically-iphone-x.html
我能够完成本教程,并且效果很好。我所拥有的不同之处在于,我的视图应该在用户需要时出现和消失。
这是具有 collectionView 的视图控制器的代码:
import UIKit
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 100, height: 150)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! TestingCollectionViewCell
cell.backgroundColor = .white
let img = UIImage(named: self.items[indexPath.row])
cell.imageView.image = img
cell.imageName.text = "\(self.items[indexPath.row])"
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("\(items[indexPath.row])")
self.presentInfoView(withInfo: items[indexPath.row])
}
}
class ViewController: UIViewController, BlurDelegate {
func removeBlurView() {
for subview in view.subviews {
if subview.isKind(of: UIVisualEffectView.self) {
subview.removeFromSuperview()
self.infoView.removeFromSuperview()
}
}
}
let infoView: InfoView = {
let view = InfoView()
view.layer.cornerRadius = 5
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
fileprivate var items: [String] = [
"photo1",
"photo2",
"photo3",
"photo4",
"photo5",
"photo6",
"photo7",
"photo8",
"photo9",
"photo10",
"photo11",
"photo12",
"photo13",
"photo14",
"photo15",
"photo16",
"photo17",
"photo18",
"photo19",
"photo20",
"photo21",
"photo22",
"photo23",
"photo24"
]
override func viewDidLoad() {
super.viewDidLoad()
let collection = UICollectionView(frame: view.frame, collectionViewLayout: UICollectionViewFlowLayout())
//allows us to use auto layout constraints
collection.translatesAutoresizingMaskIntoConstraints = false
collection.backgroundColor = .black
view.addSubview(collection)
collection.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
collection.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
collection.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
collection.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
collection.dataSource = self
collection.delegate = self
collection.register(TestingCollectionViewCell.self, forCellWithReuseIdentifier: "cell")
self.navigationItem.title = "Testing"
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
var touch: UITouch? = touches.first
if touch?.view != infoView {
dismissView()
}
}
func dismissView() {
//dismiss(animated: true, completion: nil)
removeBlurView()
}
func setBlurView() {
let blurView = UIVisualEffectView()
blurView.frame = view.frame
blurView.effect = UIBlurEffect(style: .regular)
blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(blurView)
}
func presentInfoView(withInfo info: String) {
setBlurView()
view.addSubview(infoView)
infoView.addView()
let img = UIImage(named: info)
infoView.imageView.image = img
infoView.nameLbl.text = info
infoView.backgroundColor = .white
infoView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
infoView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8).isActive = true
//infoView.widthAnchor.constraint(equalToConstant: view.frame.width - 64).isActive = true
infoView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.8).isActive = true
//infoView.heightAnchor.constraint(equalToConstant: view.frame.height - 64).isActive = true
infoView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -44).isActive = true
infoView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
infoView.alpha = 0
UIView.animate(withDuration: 0.5) {
self.infoView.alpha = 1
self.infoView.transform = .identity
}
}
}
为了清楚起见,我们的目的是让模糊视图随着视图的出现而出现和消失。
这是单元格出现时将出现的视图的代码:
import UIKit
protocol BlurDelegate: class {
func removeBlurView()
}
class InfoView: UIView {
let topView: UIView = {
let view = UIView()
view.backgroundColor = .blue
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let btmView: UIView = {
let view = UIView()
view.backgroundColor = .red
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var portraitConstraints: [NSLayoutConstraint] = []
var landscapeConstraints: [NSLayoutConstraint] = []
override init(frame: CGRect) {
super.init(frame: frame)
NotificationCenter.default.addObserver(self, selector: #selector(toggleConstraints), name: UIDevice.orientationDidChangeNotification, object: nil)
//addView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder: ) has not been implemented")
}
func addView() {
let guide = self.safeAreaLayoutGuide
//image layout
self.addSubview(topView)
let defaultImgTop = topView.topAnchor.constraint(equalTo: guide.topAnchor)
let defaultImgLeading = topView.leadingAnchor.constraint(equalTo: guide.leadingAnchor)
//portrait
let portraitImgTrailing = topView.trailingAnchor.constraint(equalTo: guide.trailingAnchor)
let portraitImgHeight = topView.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: 0.5)
//lbl layouts
self.addSubview(btmView)
let defaultlblTrailing = btmView.trailingAnchor.constraint(equalTo: guide.trailingAnchor)
let defaultLblBottom = btmView.bottomAnchor.constraint(equalTo: guide.bottomAnchor)
//portrait
let portraitLblBottom = btmView.topAnchor.constraint(equalTo: topView.bottomAnchor)
let portraitLblLeading = btmView.leadingAnchor.constraint(equalTo: guide.leadingAnchor)
//imageView landscape constraints
let landscapeImgBottom = topView.bottomAnchor.constraint(equalTo: guide.bottomAnchor)
let landscapeImgWidth = topView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5)
//label landscape constraints
let landscapeLblTop = btmView.topAnchor.constraint(equalTo: guide.topAnchor)
let landscapeLblLeading = btmView.leadingAnchor.constraint(equalTo: topView.trailingAnchor)
let defaultConstriants = [defaultImgTop, defaultImgLeading, defaultLblBottom, defaultlblTrailing]
portraitConstraints = [portraitImgHeight, portraitImgTrailing, portraitLblBottom, portraitLblLeading]
landscapeConstraints = [landscapeImgBottom, landscapeLblTop, landscapeLblLeading, landscapeImgWidth]
self.addConstraints(defaultConstriants)
toggleConstraints()
}
@objc func toggleConstraints() {
if UIDevice.current.orientation.isLandscape {
self.removeConstraints(portraitConstraints)
self.addConstraints(landscapeConstraints)
} else {
self.removeConstraints(landscapeConstraints)
self.addConstraints(portraitConstraints)
}
}
}
我从我在上面添加的网站得到这个视图的想法。我不得不改变一些东西,因为它是一个视图,但它应该是一样的。我认为错误在于此,但我尝试更改纵向和横向的约束,但没有用。我试着把它写下来,看看哪些约束被删除了,然后又更新了,但我似乎无法找到是哪个约束在困扰我。 我知道问题应该出在红色视图的顶部锚点或蓝色视图的底部锚点,但我无法弄清楚哪个是错误的。
我希望这些信息足够了,但请问我是否还有其他需要帮助的地方。
另外,如果不是很麻烦的话,如果您注意到视图出现时,导航栏似乎并没有模糊。这使得自定义视图看起来像是在顶部被截断了。如果您知道一种方法来模糊导航栏,或者尝试将视图的顶部锚点向下推以使其看起来不那么糟糕,我们将不胜感激。
我试过
self.navigationItem.bottomAnchor
我尝试在视图中添加一个带有常量的顶部锚点,但我上面的配置是我能找到的让视图每次都正确显示的最佳方式。 非常感谢
presentInfoView 函数删除 infoView.addView()
override init(frame: CGRect) {
super.init(frame: frame)
NotificationCenter.default.addObserver(self, selector: #selector(toggleConstraints), name: UIDevice.orientationDidChangeNotification, object: nil)
addView()
}