Экран запуска моего приложения представляет собой коллекцию. Если пользователь выбирает, он / она может «заблокировать» приложение, используя Face ID / Touch ID при запуске приложения. Я делаю это, представляя контроллер представления, который содержит UIVisualEffectView
поверх моего контроллера представления коллекции. Я делаю снимок экрана моего контроллера представления коллекции в viewDidLoad
, затем помещаю снимок экрана в UIImageView
ниже UIVisualEffectView
.
Проблема в том, что представление коллекции не загружается, когда делается снимок экрана и появляется контроллер UIVisualEffectView
. Снимок экрана содержит панель навигации, но содержимое представления просто черное. Я вызываю функцию для отображения контроллера представления визуальных эффектов в функции viewDidLoad
представления коллекции.
Есть ли способ загрузить данные представления коллекции, прежде чем сделать снимок экрана в viewDidLoad
? Данные хранятся в Core Data. Я уже пытался переместить функции Core Data с viewWillAppear
на viewDidLoad
, но это также не сработало.
РЕДАКТИРОВАТЬ: я смог решить мою проблему, но не путем загрузки данных UICollectionView
в ViewDidLoad, так как это кажется невозможным. Я добавил UIVisualEffectView
прямо поверх моего UICollectionView
. Я также добавил его в качестве подпредставления к UIApplication.shared.keyWindow
, чтобы он отображался над панелью навигации. Отредактированный код внизу.
Вот мой код:
Для контроллера представления коллекции:
import UIKit
import CoreData
import LocalAuthentication
var ssImage: UIImage?
class AlbumViewController: UIViewController {
// MARK: - Properties
@IBOutlet weak var albumCollectionView: UICollectionView!
var albums: [NSManagedObject] = []
// MARK: - Actions
func getScreenShot()-> UIImage? {
var screenshotImage :UIImage?
let layer = UIApplication.shared.keyWindow!.layer
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
guard let context = UIGraphicsGetCurrentContext() else {return nil}
layer.render(in:context)
screenshotImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
ssImage = screenshotImage
print("Got screenshot.")
return screenshotImage
}
// ViewDidLoad and ViewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Core Date functions
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "Album")
let sortDescriptor = NSSortDescriptor(key: "albumName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
fetchRequest.sortDescriptors = [sortDescriptor]
do {
albums = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
//Setup
self.albumCollectionView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
if AppSettings.requiresLogin == true {
getScreenShot()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let rootController = storyboard.instantiateViewController(withIdentifier: "authenticateVC") as! LockedLaunchVC
self.present(rootController, animated: false, completion: nil)
}
}
//Core Data functions
func save(name: String) {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let entity =
NSEntityDescription.entity(forEntityName: "Album",
in: managedContext)!
let albumName = NSManagedObject(entity: entity,
insertInto: managedContext)
albumName.setValue(name, forKeyPath: "albumName")
do {
try managedContext.save()
albums.append(albumName)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
//Collection View functions
extension AlbumViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return albums.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let reuseIdentifier = "AlbumCell"
// get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! AlbumsViewCell
//Core Data methods
let albumName = albums[indexPath.row]
cell.albumNameLabel?.text = albumName.value(forKeyPath: "albumName") as? String
//Return the finished cell
return cell
}
}
Для контроллера UIVisualEffectView:
import UIKit
import LocalAuthentication
class LockedLaunchVC: UIViewController {
let bioIDAuth = BiometricIDAuth()
@IBOutlet weak var screenshotImageView: UIImageView!
@IBAction func unlockButtonTapped(_ sender: UIButton) {
authAndDismiss()
}
func authAndDismiss(){
bioIDAuth.authenticateUser() {
self.dismiss(animated: true, completion: nil)
print("Locked VC dismissed.")
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.modalTransitionStyle = .crossDissolve
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
screenshotImageView.image = ssImage
}
}
РЕДАКТИРОВАТЬ: пересмотренный код для моего контроллера представления коллекции:
import UIKit
import CoreData
class AlbumViewController: UIViewController {
// MARK: - Properties
@IBOutlet weak var albumCollectionView: UICollectionView!
@IBOutlet weak var lockedBlurView: UIVisualEffectView!
@IBOutlet weak var lockedLabelView: UIView!
@IBOutlet weak var lockedLabel: UILabel!
var albums: [NSManagedObject] = []
let bioIDAuth = BiometricIDAuth()
// MARK: - Actions
@IBAction func unwindToAlbumsScreen(sender: UIStoryboardSegue) {
}
@IBAction func unlockButtonTapped(_ sender: UIButton) {
bioIDAuth.authenticateUser() {
UIView.animate(withDuration: 0.25, animations: {self.lockedBlurView.alpha = 0})
}
}
// ViewDidLoad and ViewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Core Date functions
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "Album")
let sortDescriptor = NSSortDescriptor(key: "albumName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
fetchRequest.sortDescriptors = [sortDescriptor]
do {
albums = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
//Setup to do when the view will appear
self.albumCollectionView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
lockedLabelView.layer.cornerRadius = 12
switch bioIDAuth.biometricType() {
case .faceID:
lockedLabel.text = "Albums are locked. Tap anywhere to use Face ID to unlock."
case .touchID:
lockedLabel.text = "Albums are locked. Tap anywhere to use Touch ID to unlock."
default:
lockedLabel.text = "Albums are locked. Tap anywhere to use your passcode to unlock."
}
if AppSettings.requiresLogin == false {
lockedBlurView.alpha = 0
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if AppSettings.requiresLogin == true {
let curWin = UIApplication.shared.keyWindow
curWin?.addSubview(lockedBlurView)
}
}
//Core Data functions
func save(name: String) {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let entity =
NSEntityDescription.entity(forEntityName: "Album",
in: managedContext)!
let albumName = NSManagedObject(entity: entity,
insertInto: managedContext)
albumName.setValue(name, forKeyPath: "albumName")
do {
try managedContext.save()
albums.append(albumName)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
//Collection View functions
extension AlbumViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return albums.count
}
// make a cell for each cell index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let reuseIdentifier = "AlbumCell"
// get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! AlbumsViewCell
//Core Data methods
let albumName = albums[indexPath.row]
cell.albumNameLabel?.text = albumName.value(forKeyPath: "albumName") as? String
//Return the finished cell
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let albumNameFromCell = albums[indexPath.row]
albumNameTapped = albumNameFromCell.value(forKeyPath: "albumName") as! String
self.performSegue(withIdentifier: "albumCellTappedSegue", sender: self)
}
}