use subviews for home and reader
This commit is contained in:
@@ -11,11 +11,51 @@ enum PageTurnMode {
|
||||
case scroll
|
||||
}
|
||||
|
||||
struct Comic {
|
||||
var cover: UIImage
|
||||
var metadata: Metadata
|
||||
var path: URL
|
||||
}
|
||||
|
||||
struct GlobalState: Codable {
|
||||
var comicName: String? = nil
|
||||
}
|
||||
|
||||
struct Metadata: Decodable {
|
||||
var title: String
|
||||
var original_language: String
|
||||
var last_volume: Float
|
||||
var last_chapter: Float
|
||||
var publication_demographic: String
|
||||
var status: String
|
||||
var year: Int?
|
||||
var content_rating: String
|
||||
var state: String
|
||||
var created_at: String
|
||||
var updated_at: String
|
||||
var chapters: [ChapterMetadata]
|
||||
}
|
||||
|
||||
struct ChapterMetadata: Decodable {
|
||||
var chapter: Float
|
||||
var volume: Float
|
||||
var title: String
|
||||
var pages: Int
|
||||
}
|
||||
|
||||
class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
var homeView = UIView()
|
||||
var readerView = UIView()
|
||||
|
||||
var imageView = UIImageView()
|
||||
var images: [UIImage] = []
|
||||
var page = 0
|
||||
var previousImage: UIImage?
|
||||
var currentImage: UIImage?
|
||||
var nextImage: UIImage?
|
||||
var currentPage = 1
|
||||
var mode = PageTurnMode.leftToRight
|
||||
var metadata: Metadata!
|
||||
var currentChapter: Int!
|
||||
var currentPath: URL!
|
||||
|
||||
var leftTap: UITapGestureRecognizer!
|
||||
var rightTap: UITapGestureRecognizer!
|
||||
@@ -29,33 +69,142 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
let backgroundColorDropdownView = UIView()
|
||||
let backgroundColorDropdownButton = UIButton()
|
||||
|
||||
let fileManager = FileManager.default
|
||||
var globalState = getGlobalState()
|
||||
|
||||
let documentsURL = getDocumentsURL().unsafelyUnwrapped
|
||||
|
||||
var comics: [Comic] = []
|
||||
var collectionView: UICollectionView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
view.backgroundColor = .white
|
||||
view.backgroundColor = .clear
|
||||
|
||||
setup()
|
||||
}
|
||||
|
||||
func setupHomeView() {
|
||||
loadComics()
|
||||
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
let spacing: CGFloat = 8
|
||||
layout.minimumInteritemSpacing = spacing
|
||||
layout.minimumLineSpacing = spacing
|
||||
|
||||
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
|
||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
collectionView.dataSource = self
|
||||
collectionView.delegate = self
|
||||
collectionView.backgroundColor = .white
|
||||
collectionView.register(ImageCell.self, forCellWithReuseIdentifier: "ImageCell")
|
||||
homeView.addSubview(collectionView)
|
||||
}
|
||||
|
||||
func setup() {
|
||||
createTestFile()
|
||||
setupImageView()
|
||||
setupGestures()
|
||||
setupTopBar()
|
||||
homeView.translatesAutoresizingMaskIntoConstraints = false
|
||||
readerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(homeView)
|
||||
view.addSubview(readerView)
|
||||
NSLayoutConstraint.activate([
|
||||
homeView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
homeView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
homeView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
homeView.widthAnchor.constraint(equalTo: view.widthAnchor),
|
||||
|
||||
readerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
readerView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
readerView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
readerView.widthAnchor.constraint(equalTo: view.widthAnchor),
|
||||
])
|
||||
if let name = globalState.comicName {
|
||||
globalState.comicName = name
|
||||
saveGlobalState()
|
||||
readComic(name: name)
|
||||
} else {
|
||||
readerView.isHidden = true
|
||||
homeView.isHidden = false
|
||||
setupHomeView()
|
||||
}
|
||||
}
|
||||
|
||||
func loadComics() {
|
||||
do {
|
||||
var directories: [URL] = []
|
||||
|
||||
let contents = try fileManager.contentsOfDirectory(
|
||||
at: documentsURL,
|
||||
includingPropertiesForKeys: [.isDirectoryKey],
|
||||
options: [.skipsHiddenFiles]
|
||||
)
|
||||
|
||||
directories = contents.filter { url in
|
||||
var isDirectory: ObjCBool = false
|
||||
return fileManager.fileExists(atPath: url.path, isDirectory: &isDirectory)
|
||||
&& isDirectory.boolValue
|
||||
}.sorted { $0.path < $1.path }
|
||||
|
||||
for dir in directories {
|
||||
comics.append(
|
||||
Comic(
|
||||
cover: UIImage(
|
||||
contentsOfFile: dir.appendingPathComponent("cover.jpg").path)!,
|
||||
metadata: try JSONDecoder().decode(
|
||||
Metadata.self,
|
||||
from:
|
||||
Data(
|
||||
try String(
|
||||
contentsOfFile: dir.appendingPathComponent(
|
||||
"metadata.json"
|
||||
)
|
||||
.path
|
||||
).utf8),
|
||||
),
|
||||
path: dir,
|
||||
))
|
||||
}
|
||||
} catch {
|
||||
print("Failed to read directories")
|
||||
}
|
||||
}
|
||||
|
||||
func saveGlobalState() {
|
||||
do {
|
||||
try JSONEncoder().encode(self.globalState).write(
|
||||
to: documentsURL.appendingPathComponent("state.json"))
|
||||
} catch {
|
||||
print("failed to save global state")
|
||||
}
|
||||
}
|
||||
|
||||
func setupGestures() {
|
||||
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(_:)))
|
||||
swipeLeft.direction = .left
|
||||
view.addGestureRecognizer(swipeLeft)
|
||||
readerView.addGestureRecognizer(swipeLeft)
|
||||
|
||||
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(_:)))
|
||||
swipeRight.direction = .right
|
||||
view.addGestureRecognizer(swipeRight)
|
||||
readerView.addGestureRecognizer(swipeRight)
|
||||
|
||||
setupTapZones()
|
||||
}
|
||||
|
||||
func readComic(name: String) {
|
||||
readerView.isHidden = false
|
||||
homeView.isHidden = true
|
||||
let new_path = getPathFromComicName(name: name)
|
||||
if let path = new_path {
|
||||
currentPath = path
|
||||
metadata = getMetadata(path: path)!
|
||||
setImages(path: path, metadata: metadata)
|
||||
setupImageView()
|
||||
setupGestures()
|
||||
setupTopBar()
|
||||
imageView.image = currentImage
|
||||
}
|
||||
}
|
||||
|
||||
func setupTapZones() {
|
||||
let leftView = UIView()
|
||||
let rightView = UIView()
|
||||
@@ -65,25 +214,25 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
rightView.translatesAutoresizingMaskIntoConstraints = false
|
||||
topView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
view.addSubview(leftView)
|
||||
view.addSubview(rightView)
|
||||
view.addSubview(topView)
|
||||
readerView.addSubview(leftView)
|
||||
readerView.addSubview(rightView)
|
||||
readerView.addSubview(topView)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
leftView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
leftView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
leftView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
leftView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5),
|
||||
leftView.leadingAnchor.constraint(equalTo: readerView.leadingAnchor),
|
||||
leftView.topAnchor.constraint(equalTo: readerView.topAnchor),
|
||||
leftView.bottomAnchor.constraint(equalTo: readerView.bottomAnchor),
|
||||
leftView.widthAnchor.constraint(equalTo: readerView.widthAnchor, multiplier: 0.5),
|
||||
|
||||
rightView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
rightView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
rightView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
rightView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5),
|
||||
rightView.trailingAnchor.constraint(equalTo: readerView.trailingAnchor),
|
||||
rightView.topAnchor.constraint(equalTo: readerView.topAnchor),
|
||||
rightView.bottomAnchor.constraint(equalTo: readerView.bottomAnchor),
|
||||
rightView.widthAnchor.constraint(equalTo: readerView.widthAnchor, multiplier: 0.5),
|
||||
|
||||
topView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
topView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
topView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
topView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.2),
|
||||
topView.topAnchor.constraint(equalTo: readerView.topAnchor),
|
||||
topView.leadingAnchor.constraint(equalTo: readerView.leadingAnchor),
|
||||
topView.trailingAnchor.constraint(equalTo: readerView.trailingAnchor),
|
||||
topView.heightAnchor.constraint(equalTo: readerView.heightAnchor, multiplier: 0.2),
|
||||
])
|
||||
|
||||
leftView.backgroundColor = .clear
|
||||
@@ -107,12 +256,12 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
topBarView.translatesAutoresizingMaskIntoConstraints = false
|
||||
topBarView.backgroundColor = UIColor.black.withAlphaComponent(0.8) // Or any style
|
||||
topBarView.isHidden = true
|
||||
view.addSubview(topBarView)
|
||||
readerView.addSubview(topBarView)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
topBarView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
|
||||
topBarView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
topBarView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
topBarView.topAnchor.constraint(equalTo: readerView.safeAreaLayoutGuide.topAnchor),
|
||||
topBarView.leadingAnchor.constraint(equalTo: readerView.leadingAnchor),
|
||||
topBarView.trailingAnchor.constraint(equalTo: readerView.trailingAnchor),
|
||||
topBarView.heightAnchor.constraint(equalToConstant: 64),
|
||||
])
|
||||
|
||||
@@ -134,7 +283,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
backgroundColorDropdownView.backgroundColor = UIColor.darkGray
|
||||
backgroundColorDropdownView.translatesAutoresizingMaskIntoConstraints = false
|
||||
backgroundColorDropdownView.isHidden = true
|
||||
view.addSubview(backgroundColorDropdownView)
|
||||
readerView.addSubview(backgroundColorDropdownView)
|
||||
|
||||
let stackView = UIStackView()
|
||||
stackView.axis = .vertical
|
||||
@@ -201,7 +350,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
pageTurnDropdownView.backgroundColor = UIColor.darkGray
|
||||
pageTurnDropdownView.translatesAutoresizingMaskIntoConstraints = false
|
||||
pageTurnDropdownView.isHidden = true
|
||||
view.addSubview(pageTurnDropdownView)
|
||||
readerView.addSubview(pageTurnDropdownView)
|
||||
|
||||
let stackView = UIStackView()
|
||||
stackView.axis = .vertical
|
||||
@@ -269,11 +418,11 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
@objc func handleBackgroundColorOption(_ sender: UIButton) {
|
||||
if let title = sender.currentTitle {
|
||||
switch title.lowercased() {
|
||||
case "white": view.backgroundColor = .white
|
||||
case "gray": view.backgroundColor = .gray
|
||||
case "black": view.backgroundColor = .black
|
||||
case "red": view.backgroundColor = .red
|
||||
case "blue": view.backgroundColor = .blue
|
||||
case "white": readerView.backgroundColor = .white
|
||||
case "gray": readerView.backgroundColor = .gray
|
||||
case "black": readerView.backgroundColor = .black
|
||||
case "red": readerView.backgroundColor = .red
|
||||
case "blue": readerView.backgroundColor = .blue
|
||||
default: break
|
||||
}
|
||||
}
|
||||
@@ -355,81 +504,214 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
imageView.contentMode = UIView.ContentMode.scaleAspectFit
|
||||
imageView.clipsToBounds = true
|
||||
|
||||
view.addSubview(imageView)
|
||||
readerView.addSubview(imageView)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
imageView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
imageView.topAnchor.constraint(equalTo: readerView.topAnchor),
|
||||
imageView.bottomAnchor.constraint(equalTo: readerView.bottomAnchor),
|
||||
imageView.leadingAnchor.constraint(equalTo: readerView.leadingAnchor),
|
||||
imageView.trailingAnchor.constraint(equalTo: readerView.trailingAnchor),
|
||||
])
|
||||
images = getImages()
|
||||
imageView.image = images[0]
|
||||
}
|
||||
|
||||
func changeImage(turn: PageTurn) {
|
||||
if images.count == 0 {
|
||||
return
|
||||
}
|
||||
let (chapter, page) = getChapterAndPageFromTurn(
|
||||
chapter: currentChapter, page: currentPage, turn: turn)
|
||||
if (chapter, page) == (currentChapter, currentPage) { return }
|
||||
let vol = Int(metadata.chapters[currentChapter - 1].volume)
|
||||
switch turn {
|
||||
case .next: page = min(images.count - 1, page + 1)
|
||||
case .previous: page = max(0, page - 1)
|
||||
case .next:
|
||||
previousImage = currentImage
|
||||
currentImage = nextImage
|
||||
imageView.image = currentImage
|
||||
let (c, p) = getChapterAndPageFromTurn(chapter: chapter, page: page, turn: turn)
|
||||
nextImage = getImage(chapter: c, volume: vol, page: p, path: currentPath)
|
||||
case .previous:
|
||||
nextImage = currentImage
|
||||
currentImage = previousImage
|
||||
imageView.image = currentImage
|
||||
let (c, p) = getChapterAndPageFromTurn(chapter: chapter, page: page, turn: turn)
|
||||
previousImage = getImage(chapter: c, volume: vol, page: p, path: currentPath)
|
||||
}
|
||||
imageView.image = images[page]
|
||||
}
|
||||
}
|
||||
|
||||
func getImages() -> [UIImage] {
|
||||
let fileManager = FileManager.default
|
||||
let supportedExtensions = ["png", "jpg", "jpeg"]
|
||||
|
||||
guard
|
||||
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first
|
||||
else {
|
||||
print("Documents directory not found.")
|
||||
return []
|
||||
currentPage = page
|
||||
currentChapter = chapter
|
||||
}
|
||||
|
||||
do {
|
||||
let contents = try fileManager.contentsOfDirectory(
|
||||
at: documentsURL, includingPropertiesForKeys: nil
|
||||
)
|
||||
func getImage(chapter: Int, volume: Int, page: Int, path: URL) -> UIImage! {
|
||||
// let supportedExtensions = ["png", "jpg", "jpeg"]
|
||||
|
||||
var images: [UIImage] = []
|
||||
var testPath = path
|
||||
testPath.appendPathComponent(String(format: "volume_%04d", volume))
|
||||
testPath.appendPathComponent(String(format: "chapter_%04d_image_%04d.png", chapter, page - 1))
|
||||
if !fileManager.fileExists(atPath: testPath.path) {
|
||||
print("Did not find image at path")
|
||||
return nil
|
||||
}
|
||||
return UIImage(contentsOfFile: testPath.path)!
|
||||
}
|
||||
|
||||
for file in contents {
|
||||
if supportedExtensions.contains(file.pathExtension.lowercased()) {
|
||||
print("Loading image: \(file.lastPathComponent)")
|
||||
if let image = UIImage(contentsOfFile: file.path) {
|
||||
images.append(image)
|
||||
func getChapterAndPageFromTurn(chapter: Int, page: Int, turn: PageTurn) -> (Int, Int) {
|
||||
switch turn {
|
||||
case .next:
|
||||
if metadata.chapters.count >= chapter + 1 {
|
||||
if page + 1 > metadata.chapters[chapter - 1].pages {
|
||||
return (chapter + 1, 1)
|
||||
} else {
|
||||
print("Failed to load image.")
|
||||
return (chapter, page + 1)
|
||||
}
|
||||
} else {
|
||||
print("No image files found in Documents directory.")
|
||||
return (chapter, min(metadata.chapters[chapter - 1].pages, page + 1))
|
||||
}
|
||||
case .previous:
|
||||
if page < 2 {
|
||||
if chapter > 1 {
|
||||
return (
|
||||
chapter - 1,
|
||||
metadata.chapters[chapter - 1].pages
|
||||
)
|
||||
} else {
|
||||
return (chapter, page)
|
||||
}
|
||||
} else {
|
||||
return (chapter, max(1, page - 1))
|
||||
}
|
||||
}
|
||||
return images
|
||||
} catch {
|
||||
print("Error reading contents of Documents directory: \(error)")
|
||||
}
|
||||
return []
|
||||
|
||||
func getMetadata(path: URL) -> Metadata? {
|
||||
do {
|
||||
let json = Data(
|
||||
try String(contentsOfFile: path.appendingPathComponent("metadata.json").path)
|
||||
.utf8)
|
||||
let metadata = try JSONDecoder().decode(Metadata.self, from: json)
|
||||
return metadata
|
||||
|
||||
} catch {
|
||||
print("Error reading stuff")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setImages(path: URL, metadata: Metadata) {
|
||||
var directories: [URL] = []
|
||||
|
||||
do {
|
||||
let contents = try fileManager.contentsOfDirectory(
|
||||
at: path,
|
||||
includingPropertiesForKeys: [.isRegularFileKey],
|
||||
options: [.skipsHiddenFiles]
|
||||
)
|
||||
|
||||
directories = contents.filter { url in
|
||||
var isDirectory: ObjCBool = false
|
||||
return fileManager.fileExists(atPath: url.path, isDirectory: &isDirectory)
|
||||
&& isDirectory.boolValue
|
||||
}.sorted { $0.path < $1.path }
|
||||
let dir: URL = directories[0]
|
||||
let ps: [String] = try fileManager.contentsOfDirectory(atPath: dir.path).sorted()
|
||||
let current = dir.appendingPathComponent(ps[0])
|
||||
let next = dir.appendingPathComponent(ps[1])
|
||||
currentImage = UIImage(contentsOfFile: current.path)
|
||||
nextImage = UIImage(contentsOfFile: next.path)
|
||||
let path_meta = current.lastPathComponent.components(separatedBy: "_")
|
||||
assert(path_meta[0] == "chapter")
|
||||
currentChapter = Int(path_meta[1])!
|
||||
} catch {
|
||||
print("failed to set images")
|
||||
}
|
||||
}
|
||||
|
||||
func getPathFromComicName(name: String) -> URL? {
|
||||
for comic in comics {
|
||||
if comic.metadata.title == name {
|
||||
return comic.path
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func createTestFile() {
|
||||
func getGlobalState() -> GlobalState {
|
||||
let fileManager = FileManager.default
|
||||
if let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
|
||||
.first
|
||||
{
|
||||
if let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
|
||||
do {
|
||||
let contents = try fileManager.contentsOfDirectory(atPath: documentsURL.path)
|
||||
if contents.isEmpty {
|
||||
let fileURL = documentsURL.appendingPathComponent("dummy.txt")
|
||||
let data = Data(".".utf8)
|
||||
try? data.write(to: fileURL)
|
||||
}
|
||||
let json = Data(
|
||||
try String(
|
||||
contentsOfFile: documentsURL.appendingPathComponent("state.json").path
|
||||
).utf8)
|
||||
return try JSONDecoder().decode(GlobalState.self, from: json)
|
||||
} catch {
|
||||
print("Error reading directory contents: \(error)")
|
||||
}
|
||||
}
|
||||
return GlobalState(comicName: nil)
|
||||
}
|
||||
|
||||
func getDocumentsURL() -> URL? {
|
||||
if let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
|
||||
.first
|
||||
{
|
||||
return documentsURL
|
||||
}
|
||||
print("failed to get documents dir")
|
||||
return nil
|
||||
}
|
||||
|
||||
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int)
|
||||
-> Int
|
||||
{
|
||||
return comics.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
|
||||
-> UICollectionViewCell
|
||||
{
|
||||
let cell =
|
||||
collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath)
|
||||
as! ImageCell
|
||||
cell.imageView.image = comics[indexPath.item].cover
|
||||
return cell
|
||||
}
|
||||
|
||||
// Size for cells in a grid layout
|
||||
func collectionView(
|
||||
_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
|
||||
sizeForItemAt indexPath: IndexPath
|
||||
) -> CGSize {
|
||||
let spacing: CGFloat = 8
|
||||
let itemsPerRow: CGFloat = 3
|
||||
let totalSpacing = (itemsPerRow - 1) * spacing
|
||||
let width = (collectionView.bounds.width - totalSpacing) / itemsPerRow
|
||||
return CGSize(width: width, height: width)
|
||||
}
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
let selectedComic = comics[indexPath.item]
|
||||
|
||||
readComic(name: selectedComic.metadata.title)
|
||||
}
|
||||
}
|
||||
|
||||
class ImageCell: UICollectionViewCell {
|
||||
let imageView = UIImageView()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
imageView.clipsToBounds = true
|
||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
contentView.addSubview(imageView)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
imageView.topAnchor.constraint(equalTo: contentView.topAnchor),
|
||||
imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||
imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
||||
imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user