I have a test app that I am trying to create 100% programmatically for the first time. I have a simple collectionView that has an image and a label in each cell.
When I press the cell, a custom view pops up with two views, red and blue, that in the future will have content, but for now it is just two views.
I wanted to have the app work in both portrait and landscape orientation, and in the beginning it works well. The first time I press the cell the pop up view works on both portrait and landscape orientation.
This is what i want to happen anytime a cell is pressed, but the problem arises when i clicked out of the view to make it disappear, then press any cell:
the first orientation, whether it be landscape or portrait, it is fine, but the problem arises when i change the orientation now, for the second or more cell pressed.
I tried to use the debut view hierarchy and this is what the error screen looks like.
The main idea that I am following is the tutorial from this site: https://iosrevisited.blogspot.com/2017/10/adaptive-autolayout-programmatically-iphone-x.html
I was able to complete this tutorial, and it worked fine. The difference that I have is that mine is in a view that is suppose to appear and disappear whenever the user wants.
This is the code for the view controller that has the 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
}
}
}
for a little clarity, what is was trying to go for was to have a blur view appear and disappear with the view coming up.
this is the code for the view that will appear when the cell appears:
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)
}
}
}
I got the idea in this view from the site I added above. I had to change some things since it is a view, but it should work the same. I think the error is in this, but I tried changing the constraints for portrait and landscape, but it didn't work. I tried writing it down to see which constraints were removed then updated again, but I just can't seem to find which one it is that is messing with me. I know that the problem should be in the top anchor for the red view, or the bottom anchor for the blue view, but I can't figure out which one is faulty or wrong.
I hope that this is enough information, but please ask me if there is anything else I can help with.
also, if it isn't much trouble, if you noticed when the view appears, it seems that the navigation bar doesn't blur. This makes it look like the custom view is cut off at the top. If you know a way to either blur the navigation bar, or try and push the top anchor of the view down so it doesn't look that bad, it would be greatly appreciated.
I have tried to use
self.navigationItem.bottomAnchor
and i tried to add a top anchor with a constant to the view, but the configuration i have above is the best way that i could find to get the view to appear right each time and perfectly. Thank you very much
presentInfoView function remove infoView.addView()
override init(frame: CGRect) {
super.init(frame: frame)
NotificationCenter.default.addObserver(self, selector: #selector(toggleConstraints), name: UIDevice.orientationDidChangeNotification, object: nil)
addView()
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.