นี่เป็นส่วนที่สองของบทความเกี่ยวกับการสร้างโคลน Spotify UI ด้วย autoLayout โดยทางโปรแกรม หากคุณพลาดส่วนแรกไม่ต้องกังวล - โปรดไปและตรวจสอบทันที
ในบทความนี้ เราจะเพิ่มรูปภาพจำลองและพยายามทำให้ UI เหมือนกับของ Spotify
นี่คือสิ่งที่เราจะทำในวันนี้ ?
นี่คือสิ่งที่เราทิ้งไว้ในตอนแรก:
ขั้นตอนต่อไปคือการสร้างเซลล์ที่กำหนดเอง เริ่มด้วยการสร้างชื่อ SubCustomCell
.
ขั้นแรก สร้างไฟล์ Swift ใหม่ภายในโฟลเดอร์โครงการและตั้งชื่อเป็น SubCustomCell.swift
. ไฟล์นี้จะมีเซลล์ที่กำหนดเองซึ่งจะแสดงเพลย์ลิสต์ หลังจากสร้างไฟล์แล้ว ให้ลองเพิ่มโค้ดด้านล่างและเริ่มต้นเซลล์ อาจเป็นด้วย backgroundColor
เพื่อดูการเปลี่ยนแปลง UI เมื่อเราลงทะเบียนเซลล์ด้วย collectionView
.
import UIKit
class SubCustomCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .red
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
จากนั้นเราก็ลงทะเบียน SubCustomCell
ภายใน CustomCell.swift
ภายใน init
บล็อก. แทนที่ UICollectionViewCell.self
ด้วย
ชอบด้านล่างSubCustomCell
collectionView.register(SubCustomCell.self, forCellWithReuseIdentifier: cellId)
นอกจากนี้ เราจำเป็นต้องทำการแก้ไขใน cellForItemAt
และทำให้เป็นไปตาม SubCustomCell
ดังต่อไปนี้
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SubCustomCell
// cell.backgroundColor = .yellow
return cell
}
คุณควรเห็น backgroundColor
เปลี่ยนเป็น red
.
ถึงจุดนี้ทุกอย่างควรจะตรงไปตรงมาและชัดเจน
ตอนนี้เราจะเติมเซลล์ด้วยรูปภาพจำลอง และสร้าง ImageView
ภายในแต่ละเซลล์ ฉันดาวน์โหลดรูปภาพสุ่มจาก pexels.com แล้ว แต่คุณสามารถใช้รูปภาพใดก็ได้ที่คุณชอบ (รวมถึงรูปภาพเหล่านี้ด้วย) คุณสามารถค้นหาได้ในไฟล์โครงการบน Github
มาสร้าง UIImageView
. กันเถอะ ภายใน SubCustomCell.swift
และสร้างข้อจำกัดบางอย่าง
let ImageView : UIImageView = {
let iv = UIImageView()
iv.backgroundColor = .yellow
return iv
}()
และเพิ่มลงใน view
ภายใน init
บล็อกโดยใช้ addSubView
.
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(ImageView)
}
ทีนี้มาสร้าง ImageView
. กัน ใช้พื้นที่ทั้งหมดภายในเซลล์โดยมีข้อจำกัดด้านล่าง
ImageView.translatesAutoresizingMaskIntoConstraints = false
ImageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
ImageView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
ImageView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
ImageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
LeftAnchor
แทนสมอเซลล์ด้านซ้ายrightAnchor
หมายถึงสมอขวาของเซลล์bottomAnchor
แสดงถึงจุดยึดด้านล่างของเซลล์topAnchor
หมายถึง สมอบนสุดของเซลล์
และด้วยการทำ ImageView
สมอด้านบนของเซลล์เท่ากับสมอด้านบนของเซลล์ (และทำเช่นเดียวกันสำหรับ ImageView
สมอซ้าย ขวา และล่าง) ทำให้ ImageView
ใช้พื้นที่ทั้งหมดของ SubCustomCell
(เซลล์)
หมายเหตุ:ก่อนอื่นคุณต้องใช้ translatesAutoresizingMaskIntoConstraints
เพื่อให้สามารถใช้ข้อจำกัดกับองค์ประกอบได้ อย่าลืมโทร isActive
คุณสมบัติและกำหนดให้กับ true
– หากไม่ทำเช่นนั้น ข้อจำกัดจะไม่ทำงานและจะไม่มีอะไรเปลี่ยนแปลง
ImageView
น่าจะมีรูปนะ มาเพิ่มกันเถอะ
let ImageView : UIImageView = {
let iv = UIImageView()
iv.backgroundColor = .yellow
// we have >image1< file inside the project
iv.image = UIImage(named: "image1")
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
return iv
}()
และหากคุณสร้างและเรียกใช้แอป คุณจะเห็นผลลัพธ์และรูปภาพที่เราเพิ่มลงใน SubCustomCell
.
เย็น ?. ตอนนี้มีองค์ประกอบที่เราควรเพิ่มใน SubCustomCell
ที่จะเสร็จสิ้นขึ้น เราต้องการชื่อที่จะแสดงชื่อเพลย์ลิสต์:UILabel
.
สำหรับชื่อเรื่องจะเป็นดังนี้:
let TitleLabel : UILabel = {
let lb = UILabel()
lb.textColor = UIColor.lightGray
lb.font = UIFont.systemFont(ofSize: 16)
lb.font = UIFont.boldSystemFont(ofSize: 20)
lb.text = "Evening Music"
return lb
}()
ฉันแค่ใส่ข้อความสุ่มลงไป - คุณสามารถใส่อะไรก็ได้ที่คุณชอบ ขั้นตอนต่อไปคือการเพิ่มองค์ประกอบในมุมมองและกำหนดข้อจำกัดบางประการ ชื่อเรื่องจะอยู่ที่ด้านล่างของ ImageView
.
เพิ่มเพื่อดู:
addSubview(TitleLabel)
การใช้ข้อจำกัดสำหรับทั้ง ImageView
และ TitleLabel
ImageView.translatesAutoresizingMaskIntoConstraints = false
ImageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
ImageView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
ImageView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
ImageView.heightAnchor.constraint(equalToConstant: 240).isActive = true
ImageView.bottomAnchor.constraint(equalTo: TitleLabel.topAnchor).isActive = true
TitleLabel.translatesAutoresizingMaskIntoConstraints = false
TitleLabel.topAnchor.constraint(equalTo: ImageView.bottomAnchor,constant: 10).isActive = true
TitleLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 5).isActive = true
TitleLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -5).isActive = true
เอาล่ะ!
เราทำให้รูปภาพใช้พื้นที่ส่วนใหญ่ในเซลล์ และส่วนที่เหลือจะใช้ชื่อ อย่างที่คุณเห็น คุณสามารถเลื่อนทั้งแนวนอนในแต่ละส่วนและแนวตั้งได้ทั้งหน้าจอ
ตอนนี้เรากำลังใส่ข้อมูลจำลองลงในเซลล์เพื่อให้รู้สึกเหมือนเป็นจริง เพื่อที่ฉันได้สร้าง JSON
ไฟล์ที่มีข้อมูลสุ่มสำหรับส่วนและเพลย์ลิสต์
ขั้นแรก มาสร้างสองโครงสร้าง Section
และ Playlist
. เราสร้างไฟล์แยกต่างหากสำหรับแต่ละโครงสร้าง
section.swift
import Foundation
struct Section {
var title : String
var playlists : NSArray
init(dictionary:[String : Any]) {
self.title = dictionary["title"] as? String ?? ""
self.playlists = dictionary["playlists"] as? NSArray ?? []
}
}
playlist.swift
//
// playlist.swift
// spotifyAutoLayout
//
// Created by admin on 12/6/19.
// Copyright © 2019 Said Hayani. All rights reserved.
//
import Foundation
struct PlayList {
var title: String
var image : String
init(dictionary : [String : Any]) {
self.title = dictionary["title"] as? String ?? ""
self.image = dictionary["image"] as? String ?? ""
}
}
แล้วข้างใน ViewController.swift
เราสร้างฟังก์ชันที่ดึง JSON ให้เราและเก็บผลลัพธ์ไว้ในอาร์เรย์
print("attempt to fetch Json")
if let path = Bundle.main.path(forResource: "test", ofType: "json") {
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
if let jsonResult = jsonResult as? [ Any] {
// do stuff
jsonResult.forEach { (item) in
let section = Section(dictionary: item as! [String : Any])
// print("FEtching",section.playlists)
self.sections.append(section)
}
self.collectionView.reloadData()
}
} catch {
// handle error
}
}
}
The fetchJson
เรียกฟังก์ชันภายใน ViewDidLoad
กระบวนการ. เรายังมีตัวแปรที่เรียกว่า sections
ที่เราเก็บผลลัพธ์:
var sections = [Section]()
ขั้นตอนต่อไปคือการส่งข้อมูลจาก ViewController
ถึง CustomCell
. เพื่อที่เราจะสร้างตัวแปรภายใน CustomCell
ซึ่งจะได้รับข้อมูลแต่ละส่วน:
var section : Section?{
didSet{
print("section ✅",self.section)
}
}
เราใช้ cellForItemAt
ภายใน ViewController
วิธีการส่งข้อมูลโดยตรงไปยัง CustomCell
.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CustomCell
cell.section = sections[indexPath.item]
return cell
}
หมายเหตุ:เราเรียก self
. เสมอ .collectionView.reloadData()
ทุกครั้ง fetchJson
เรียกว่าบล็อกด้านล่างภายใน CustomCell
ก็จะถูกเรียกเช่นกัน ตรวจสอบคอนโซล shift
+ คำสั่ง + C:
var section : Section? {
didSet{
print("section ✅",self.section)
}
}
สิ่งแรกที่เราเปลี่ยนคือการตั้งชื่อหัวข้อ:
var section : Section? {
didSet{
print("section ✅",self.section)
guard let section = self.section else {return}
self.titleLabel.text = section.title
}
}
แล้วคุณจะเห็นว่าแต่ละส่วนมีชื่อเฉพาะบนหน้าจอ ?.
ถึงเวลาส่งข้อมูลลงไปที่ SubCustomCell
. เราทำสิ่งเดียวกันกับที่เราทำข้างต้น เราต้องส่ง playlists
อาร์เรย์ เราจึงสร้างตัวแปรชื่อ playlists
ภายใน CustomCell
.
var playlists : [PlayList]() //empty
ขั้นแรก เราแมปผ่าน playlists
จาก JSON
. จากนั้นเราเพิ่มแต่ละเพลย์ลิสต์ด้วย playlists
var.
var section : Section? {
didSet{
print("section ✅",self.section)
guard let section = self.section else {return}
self.titleLabel.text = section.title
// append to playlists array
self.section?.playlists.forEach({ (item) in
let playlist = PlayList(dictionary: item as! [String : Any])
self.playlists.append(playlist)
})
self.collectionView.reloadData()
}
}
ความสนใจ! หากคุณพยายามเรียกใช้แอป อาจเกิดปัญหาได้ เนื่องจากเราลืมกำหนดจำนวนส่วน เนื่องจากขณะนี้เราได้รับข้อมูลจาก JSON ตัวเลขจึงควรเป็นแบบไดนามิกตามจำนวนส่วนที่เรามี จำนวนส่วนควรเท่ากับจำนวนส่วนใน JSON
จึงต้องแก้ไข numberOfItemsInSection
ภายใน ViewController
ไปด้านล่าง :
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return sections.count
}
เราทำสิ่งเดียวกันกับวิธีการเดียวกันภายใน CustomCell.swift
– แต่ในที่นี้เราพิจารณาเลขของ playlists
แทน
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.playlists.count
}
ขั้นตอนสุดท้ายที่เราต้องทำคือส่งแต่ละเพลย์ลิสต์ Object
ถึง SubCustomCell
ภายใน cellForItemAt
ใน CustomCell.swift
.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SubCustomCell
// here ?
cell.playlist = playlists[indexPath.item]
return cell
}
และเราจะได้ข้อมูลนั้นใน SubCustomCell
ผ่าน playlist
และสุดท้ายแสดงชื่อและภาพของเพลย์ลิสต์
var playlist : PlayList? {
didSet{
print("Playlist ?",self.playlist)
guard let playlist = self.playlist else {return}
// The Image ?
self.ImageView.image = UIImage(named: playlist.image)
// the playlist title ?
self.TitleLabel.text = self.playlist?.title
}
}
ฉันคิดว่าตอนนี้ทุกอย่างน่าจะทำงานได้ดีเหมือนด้านล่าง ?
การอัปเดต UI ครั้งสุดท้าย:เราต้องเพิ่มช่องว่างภายในและระยะขอบใน section
และ playlist
และทำให้เพลย์ลิสต์มีขนาดเล็กลงเล็กน้อย
ขั้นแรกให้เพิ่มช่องว่างภายในสำหรับชื่อส่วน ในการทำเช่นนั้น เราเพียงแค่ให้ constant
คุณสมบัติค่าตัวเลขบางส่วนภายในเซลล์ส่วน CustomCell
และภายใน setupSubCells
:
collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor,constant: 15).isActive = true
และถ้าคุณเห็น collectionView
. ทั้งหมด เข้ามาที่ด้านล่างของ titleLabel
สิ่งที่เราต้องทำคือเพิ่มพื้นที่โดยเพิ่ม 15
:
ต่อไปเรามาที่ชื่อเรื่องของ playlist
. ซึ่งจะอยู่ภายใน SubCustomCell
และเราเพียงแค่ต้องเพิ่มพื้นที่เพิ่มเติมที่ด้านล่างของ ImageView
ImageView.bottomAnchor.constraint(equalTo: TitleLabel.topAnchor,constant: -15).isActive = true
เรามีค่าคงที่ตรงนั้นอยู่แล้ว เพื่อให้ใช้งานได้ ค่าควรเป็น -15
สุดท้ายเพลย์ลิสต์ต้องเล็กลงเล็กน้อย ง่ายมาก เราแค่สร้าง playlist
ความสูงและความกว้างของเซลล์เท่ากับ section
ความสูงของเซลล์หารด้วย 2 เช่นเดียวกับด้านล่าง:
CustomCell.swift
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = frame.height / 2
let height = frame.height / 2
return CGSize(width: width, height: height)
}
ทำให้ความสูงของ ImageView เท่ากับ 150
เช่นกัน
//SubCutomCell.swift
ImageView.heightAnchor.constraint(equalToConstant: 150).isActive = true
แล้วนี่ไง ?.
สมบูรณ์แบบ! ฉันคิดว่ามันเพียงพอแล้วสำหรับวันนี้ ฉันไม่ต้องการให้บทความนี้ยาวเกินไป ดังนั้นเราจะมีอีกส่วนหนึ่งที่เราจะเพิ่ม TabBar
และคำอธิบาย ตลอดจนไอคอนบางรายการสำหรับเพลย์ลิสต์
ดู ซอร์สโค้ดแบบเต็มบน GitHub ?.
ขอบคุณที่สละเวลา. ฉันหวังว่าฉันไม่ได้พลาดอะไร ถ้าฉันได้โปรด @พูดถึงฉันบน Twitter หรือหากคุณมีคำถามหรือส่วนเพิ่มเติมในโพสต์นี้ ประตูก็เปิดกว้างสำหรับทุกคนเสมอ ขอบคุณค่ะ??.
สมัครสมาชิก ไปที่รายชื่ออีเมลของฉันเพื่อรับการแจ้งเตือนเมื่อมีการเผยแพร่ส่วนที่สามของบทช่วยสอนนี้
อย่างไรก็ตาม เมื่อเร็วๆ นี้ ฉันได้ทำงานร่วมกับกลุ่มวิศวกรซอฟต์แวร์ที่แข็งแกร่งสำหรับหนึ่งในแอปพลิเคชันมือถือของฉัน องค์กรนั้นยอดเยี่ยม และผลิตภัณฑ์ได้รับการจัดส่งเร็วมาก เร็วกว่าบริษัทและ freelancer อื่นๆ ที่ฉันเคยทำงานด้วย และฉันคิดว่าฉันสามารถแนะนำพวกเขาสำหรับโครงการอื่นๆ ได้อย่างแท้จริง ส่งอีเมลถึงฉันหากคุณต้องการติดต่อ — [email protected]