UIKit Programmatically Design
Xcode’da yeni bir proje oluşturduğunuzda, varsayılan olarak Main.storyboard proje içerisinde gelir.
Storyboard olmayan bir yaklaşımla gitmek istiyorsanız ve her şeyi kod ile ayarlamak istiyorsanız, yapmamız gereken birkaç adım var.
- İşe mevcut projemizde var olan main.storyboard u çöpe yollamak ile başlıyalım.
2. Daha sonra referans olarak storyboard gösterilen yerlerden de silmemiz gerekiyor.
Proje → Info → Main Storyboard File Base Name
3. Son olarak info dosyamızdan Main storyboard kısmını da info dan siliyoruz.
Projeden kaldırdığımız main.storyboard da initial controller olarak default şekilde uygulamamız ViewController ile başlıyordu fakat şimdi main.storyboardu projeden kaldırdığımız için SceneDelegate de projemizin hangi controllerdan başlayacağını belirtmemiz gerekiyor.
iOS 13 ve sonrasında SceneDelegate, AppDelegate’in bazı sorumluluklarını üstlenir. Özellikle AppDelegate’ten UIWindow ile ilgili olarak artık SceneDelegate’te UIScene var. Bir uygulama, çoğunlukla uygulama arayüzünü ve uygulama içeriğini işleyen birden fazla sahneye sahip olabilir. Yani, SceneDelegate, ekranda UI terma ve veri olarak görüntülenenlerden sorumludur.
SceneDelegate classı içerisinde uygulamanın başlıyacağı Controller tanımlanıyor.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(frame: windowScene.coordinateSpace.bounds)
window?.windowScene = windowScene
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
}
}
scene methodu icerisinde başlangıçta gidilecek controlleri ayarladik. SceneDelegete classı içerisinde uygulamanın yaşam dongülerinin yer aldığı fonksiyonlar mevcut uygulama başlarken, arka plana alındığında ,ve ya kapatıldığında neler olacağı bu class içerisindeki methodlar aracılığı ile gerçekleştiririz.
Projeyi başlattığımızda herhangi problem ve ya uyarı ile karşılaşmadık şimdi storyboard olmadan kullanıcı arayüzü elemanlarımızı constraitler kullanarak çok daha efektif oluşturma aşamasına geçelim.
Projemizde UITableView içerisinde custom cell oluşturup ui elemanları burada kullanalım.
- İlk iş olarak default tableview oluşturalım.
import UIKit
class ViewController: UIViewController {
// MARK: PROPERTIES
// MARK: UI ELEMENTS
var tableView : UITableView = {
let tableView = UITableView()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.translatesAutoresizingMaskIntoConstraints = false
return tableView
}()
// MARK: FUNCTIONS
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.backgroundColor = .systemBackground
configureTableView()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.frame = view.bounds
}
func configureTableView(){
tableView.delegate = self
tableView.dataSource = self
view.addSubview(tableView)
}
}
// MARK: EXTENSIONS
extension ViewController : UITableViewDelegate , UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "test"
return cell
}
}
2. Şimdi Custom Cell olusturalim.
New File → UITableViewCell ile yeni bir dosya oluşturuyoruz.
import UIKit
class CustomTableViewCell: UITableViewCell {
// MARK: PROPERTIES
// MARK: UI ELEMENTS
// MARK: FUNCTIONS
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
3. ViewController da tanımladığımız tableview ve extensiondaki cellforrowat fonksiyonunda UITabViewCell yerine CustomTableViewCell olarak güncellemeliyiz.
// MARK: UI ELEMENTS
var tableView : UITableView = {
let tableView = UITableView()
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "cell")
tableView.translatesAutoresizingMaskIntoConstraints = false
return tableView
}()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? CustomTableViewCell else {
return UITableViewCell()
}
cell.textLabel?.text = "test"
return cell
}
4. Artık CustomTableViewCell i tableview içerisinde tanımladık şimdi kullanmak istediğimiz ui elemanlarını constraintler ile birlikte bu class içerisine tanımlayabiliriz.
import UIKit
class CustomTableViewCell: UITableViewCell {
// MARK: PROPERTIES
// MARK: UI ELEMENTS
var filmImageView : UIImageView = {
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
image.contentMode = .scaleAspectFill
image.layer.cornerRadius = 10
image.layer.masksToBounds = true
return image
}()
var filmLabel : UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(filmImageView)
contentView.addSubview(filmLabel)
}
// MARK: FUNCTIONS
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
//image
filmImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5).isActive = true
filmImageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5).isActive = true
filmImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5).isActive = true
filmImageView.widthAnchor.constraint(equalToConstant: 100).isActive = true
//label
filmLabel.leadingAnchor.constraint(equalTo: filmImageView.trailingAnchor, constant: 25).isActive = true
filmLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
filmLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? CustomTableViewCell else {
return UITableViewCell()
}
cell.filmLabel.text = "deneme"
cell.filmImageView.image = UIImage(systemName: "house")
return cell
}
filmLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true
//film label trailing constrainti contentview trailing tarafindan -20 iceride
Unutmamiz gereken en onemli noktalardan biride ui elemanlarini olusturuken ;
label.translatesAutoresizingMaskIntoConstraints = false
bu şu anlama geliyor görünümün otomatik yeniden boyutlandırma olsun mu olmasın mı biz false degeri vericez.
cellForRowAt methodu içerisinde oluşturduğumuz ui ler için deneme ve house image kullanıp constraintlerimizi doğru olarak oluşturduğumuzdan emin olmak istiyoruz. layoutSubview içerisinde yazdığımız kodlar incelenirse istediğimiz constraintleri vermiş olduğunu gördük, örnek olarak deneme label altına birtane daha label ekleyip constraintslerini vermek istersek bu fonksiyona ekleyeceğimiz kod parçası
filmLabel.leadingAnchor.constraint(equalTo: filmImageView.trailingAnchor, constant: 25).isActive = true
filmLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
filmLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true
//detayLabel filmLabel altina ekleyip constraint verelim
//ilk once top constraint
//filmLabel bottomAnchora sabitledik
detayLabel.topAnchor.constraint(equalTo: filmLabel.bottomAnchor, constant: 5).isActive = true
//daha sonra leading constraint
detayLabel.topAnchor.constraint(equalTo: filmImageView.trailingAnchor, constant: 25).isActive = true
//daha sonra yatayda nerede olacagini belirledik
detayLabel.centerYAnchor.constraint(equalTo: filmLabel.centerYAnchor).isActive = true