[Swift] UITextView - PlaceHolder ์ ์ฉํ๊ธฐ
UITextView๋ฅผ ์ฌ์ฉํ๋ฉด ์์ ๊ฐ์ด ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ ์ ๋ ฅ๋ฐ์ ์ ์๋ค.
๊ทธ๋ฌ๋ ๋ฌด์์ ์ ๋ ฅํด์ผํ๋์ง ์ฌ์ฉ์ ์ ์ฅ์์๋ ์ ๋๋ก ์ ์๊ฐ ์๋ค.
๊ทธ๋์ PlaceHoler๋ผ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํด๋ณด๊ธฐ๋ก ํ๋ค.
TextFiled๋ PlaceHoler ์์ฑ์ด ์๋๊ฒ์ผ๋ก ์๋๋ฐ,
TextView๋ ๋ธ๋ฆฌ๊ฒ์ดํธ๋ฅผ ํ์ฉํด ๋ฐ๋ก ์ปค์คํ ํด์ค์ผ ๊ฐ๋ฅํ๋ค๊ณ ํ๋ค.
extension UpdatePhoneBookView: UITextViewDelegate {
// ์๋ ํจ์๋ค์ UITextViewDelegate ํ๋กํ ์ฝ์ ํฌํจ๋ ๋ฉ์๋๋ค
// 1. ์ฌ์ฉ์๊ฐ ํ
์คํธ ๋ทฐ์ ์
๋ ฅ์ ์์ํ ๋ ํธ์ถ๋๋ ๋ฉ์๋
func textViewDidBeginEditing(_ textView: UITextView) {
//ํ
์คํธ ๋ทฐ์ ํ์ฌ ํ
์คํธ ์์์ด ํ๋ ์ด์คํ๋ ํ
์คํธ ์์์ธ์ง ํ์ธ
guard textView.textColor == .systemGray4 else { return }
//์์์ด ํ์์ด๋ผ๋ฉด ํ
์คํธ ๋ทฐ์ ๋ด์ฉ์ ๋น์ฐ๊ณ , ํ
์คํธ ์์์ ์ด๋์ด ํ์์ผ๋ก ๋ณ๊ฒฝํ์ฌ ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ์ค๋น
textView.text = nil
textView.textColor = .darkGray
}
// 2. ์ฌ์ฉ์๊ฐ ํ
์คํธ ๋ทฐ์ ์
๋ ฅ์ ๋ง์น ๋ ํธ์ถ๋๋ ๋ฉ์๋
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty{
// ํ๊ทธ์ ๋ฐ๋ผ ์ ์ ํ ํ๋ ์ด์คํ๋ ํ
์คํธ๋ฅผ ์ค์
if textView.tag == 1 {
textView.text = "์ด๋ฆ์ ์
๋ ฅํ์ธ์."
} else if textView.tag == 2 {
textView.text = "์ ํ๋ฒํธ๋ฅผ ์
๋ ฅํ์ธ์."
}
//ํ๋ ์ด์คํ๋ ํ
์คํธ์ ์์์ ํ์์ผ๋ก ๋ณ๊ฒฝ
textView.textColor = .systemGray4
}
}
}
๊ฐ๋ ์ฑ์ ์ํด extension์ผ๋ก ๋ธ๋ฆฌ๊ฒ์ดํธ๋ฅผ ์ฑํํด ํ๋จ์ ๋ฐ๋ก ๋นผ์ฃผ์๋ค.
ํ์ง๋ง ์ฌ๊ธฐ์ ์๋ก ๋ฐ๊ฒฌํ ์ค๋ฅ...
์์ ์ ์ด๋ฆ์ ์ ๋ ฅํ ๋๋ .systemGray4๋ก ๋ณด์ธ๋ค๋ ์ ์ด๋ค.
import UIKit
import CoreData
class UpdatePhoneBookViewCotroller: UIViewController {
var updatePhoneBookView: UpdatePhoneBookView!
var phoneBookViewController: PhoneBookViewController? //๋ณ์๊ฐ nil์ผ ์ ์์
var phoneBook: PhoneBook? // ์์ ํ ๋ฐ์ดํฐ
let coreDataManager = CoreDataManager()
//๋ค๋น๊ฒ์ด์
๋ฐ - "์ ์ฉ" ๋ฒํผ
lazy var saveButton: UIBarButtonItem = {
let button = UIBarButtonItem(title: "์ ์ฉ", style: .plain, target: self, action: #selector(saveButtonTapped))
return button
}()
override func loadView() {
// UpdatePhoneBookView๋ฅผ ๊ธฐ๋ณธ ๋ทฐ๋ก ์ค์
updatePhoneBookView = UpdatePhoneBookView(frame: UIScreen.main.bounds)
self.view = updatePhoneBookView
}
override func viewDidLoad() {
super.viewDidLoad()
//๋ค๋น๊ฒ์ด์
๋ฐ ์ค์
navigationItem.rightBarButtonItem = saveButton
updatePhoneBookView.randomImageButton.addTarget(self, action: #selector(randomImageButtonTapped), for: .touchDown)
if let phoneBook = phoneBook {
// ์ ๋ฌ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ทฐ์ ํ์
title = "\(phoneBook.name!)"
updatePhoneBookView.inputName.text = phoneBook.name
updatePhoneBookView.inputPhoneNumber.text = phoneBook.phoneNumber
updatePhoneBookView.inputName.textColor = .darkGray //๐๐๐๐์ถ๊ฐ์ฌํญ๐๐๐๐
updatePhoneBookView.inputPhoneNumber.textColor = .darkGray //๐๐๐๐์ถ๊ฐ์ฌํญ๐๐๐๐
if let imageData = phoneBook.image {
updatePhoneBookView.profileImage.image = UIImage(data: imageData)
}
}
}
// MARK: - ์๋ฒ ๋ฐ์ดํฐ ๋ถ๋ฌ์ค๋ ๋ฉ์๋
// ์๋ฒ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ - ๋น๋๊ธฐ์ ์ผ๋ก ๋์ํ๋ ํจ์๋ก ๋ฆฌํดํ์ด ์๋, ์ฝ๋ฐฑ ํจ์๋ก ์ค๊ณ
private func fetchData<T: Decodable>(url: URL, completion: @escaping (T?) -> Void) {
print(#function)
let session = URLSession(configuration: .default)
session.dataTask(with: URLRequest(url: url)) { data, response, error in
guard let data = data, error == nil else {
print("๋ฐ์ดํฐ ๋ก๋ ์คํจ")
completion(nil)
return
}
let successRange = 200..<300
if let response = response as? HTTPURLResponse, successRange.contains(response.statusCode) {
guard let decodeData = try? JSONDecoder().decode(T.self, from: data) else {
print("๋ฐ์ดํฐ๊ฐ ์์")
completion(nil)
return
}
completion(decodeData)
} else {
print("์๋ต ์ค๋ฅ")
completion(nil)
}
}.resume()
}
// MARK: - ์๋ฒ์์ ๋๋ค ํฌ์ผ๋ชฌ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋ ๋ฉ์๋
private func pokemonInfoData() {
let urlComponents = URLComponents(string: "https://pokeapi.co/api/v2/pokemon/\(Int.random(in: 1...1000))")
guard let url = urlComponents?.url else {
print("์๋ชป๋ URL")
return
}
// ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์ค๋ ๋ฉ์๋ ์ถ์ถ
fetchData(url: url) { [weak self] (pokemon: Pokemon?) in
// guard let ์ ํตํด self๋ฅผ ๋ค์ ๊ฐํ์ฐธ์กฐ๋ฅผ ํ์ฌ ์์ ํ๊ฒ ์ฌ์ฉ
guard let self, let pokemon else { return }
// ๋ฉ์ธ ์ค๋ ๋๋ก ์ค์ ์ ํด์ฃผ์ง ์์ผ๋ฉด ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋์์ ๋์๊ฐ์ ์์ข์
guard let imageUrl = URL(string: pokemon.sprites.frontDefault) else { return }
// image ๋ฅผ ๋ก๋ํ๋ ์์
์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ฐ๋ ๋ ์์
: Data(contensOf:)
if let data = try? Data(contentsOf: imageUrl) {
if let image = UIImage(data: data) {
// ์ด๋ฏธ์ง๋ทฐ์ ์ด๋ฏธ์ง๋ฅผ ๊ทธ๋ฆฌ๋ ์์
์ UI ์์
์ด๊ธฐ ๋๋ฌธ์ ๋ค์ ๋ฉ์ธ ์ฐ๋ ๋์์ ์์
.
DispatchQueue.main.async {
self.updatePhoneBookView.profileImage.image = image
}
}
}
}
}
//MARK: - @objc ๋ฉ์๋
//"๋๋ค ์ด๋ฏธ์ง ์์ฑ" ๋ฒํผ ์ก์
@objc
func randomImageButtonTapped(){
pokemonInfoData()
}
//"์ ์ฉ" ๋ฒํผ ์ก์
@objc
func saveButtonTapped(){
if let name = updatePhoneBookView.inputName.text,
let phoneNumber = updatePhoneBookView.inputPhoneNumber.text,
let image = updatePhoneBookView.profileImage.image {
if let phoneBook = phoneBook {
// ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ์
๋ฐ์ดํธ
coreDataManager.updateData(currentPhoneNumer: phoneBook.phoneNumber!, newName: name, newPhoneNumber: phoneNumber, newImage: image)
} else {
// ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ์์ฑ
coreDataManager.createData(name: name, phoneNumber: phoneNumber, image: image)
}
self.navigationController?.popViewController(animated: true)
}
}
}
import UIKit
import SnapKit
class UpdatePhoneBookView: UIView {
let updatePhoneBookViewCotroller = UpdatePhoneBookViewCotroller()
var phoneBookViewController: PhoneBookViewController?
var profileImage: UIImageView = {
let image = UIImageView()
image.layer.borderColor = UIColor.systemGray4.cgColor
image.contentMode = .scaleAspectFit
image.clipsToBounds = true
image.layer.borderWidth = 1
image.layer.cornerRadius = 100
return image
}()
lazy var randomImageButton: UIButton = {
let button = UIButton()
button.setTitle("๋๋ค ์ด๋ฏธ์ง ์์ฑ", for: .normal)
button.backgroundColor = .systemGray5
button.setTitleColor(.black, for: .normal)
button.layer.cornerRadius = 20
return button
}()
var inputName: UITextView = {
let textView = UITextView()
textView.textColor = .systemGray4
textView.font = .systemFont(ofSize: 16)
textView.backgroundColor = .white
textView.text = "์ด๋ฆ์ ์
๋ ฅํ์ธ์."
textView.tag = 1
// ํ
๋๋ฆฌ ์ค์
textView.layer.borderColor = UIColor.systemGray4.cgColor
textView.layer.borderWidth = 1.0
textView.layer.cornerRadius = 8.0
return textView
}()
var inputPhoneNumber: UITextView = {
let textView = UITextView()
textView.textColor = .systemGray4
textView.font = .systemFont(ofSize: 16)
textView.backgroundColor = .white
textView.text = "์ ํ๋ฒํธ๋ฅผ ์
๋ ฅํ์ธ์."
textView.tag = 2
// ํ
๋๋ฆฌ ์ค์
textView.layer.borderColor = UIColor.systemGray4.cgColor
textView.layer.borderWidth = 1.0
textView.layer.cornerRadius = 8.0
return textView
}()
override init(frame: CGRect) {
super.init(frame: frame)
configureUI()
inputName.delegate = self
inputPhoneNumber.delegate = self
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func configureUI(){
self.backgroundColor = .white
[profileImage, randomImageButton, inputName, inputPhoneNumber].forEach{ self.addSubview($0) }
//์คํ ๋ ์ด์์...
}
}
//MARK: -PlaceHolder ์ค์
extension UpdatePhoneBookView: UITextViewDelegate {
// ์๋ ํจ์๋ค์ UITextViewDelegate ํ๋กํ ์ฝ์ ํฌํจ๋ ๋ฉ์๋๋ค
// 1. ์ฌ์ฉ์๊ฐ ํ
์คํธ ๋ทฐ์ ์
๋ ฅ์ ์์ํ ๋ ํธ์ถ๋๋ ๋ฉ์๋
func textViewDidBeginEditing(_ textView: UITextView) {
//ํ
์คํธ ๋ทฐ์ ํ์ฌ ํ
์คํธ ์์์ด ํ๋ ์ด์คํ๋ ํ
์คํธ ์์์ธ์ง ํ์ธ
guard textView.textColor == .systemGray4 else { return }
//์์์ด ํ์์ด๋ผ๋ฉด ํ
์คํธ ๋ทฐ์ ๋ด์ฉ์ ๋น์ฐ๊ณ , ํ
์คํธ ์์์ ์ด๋์ด ํ์์ผ๋ก ๋ณ๊ฒฝํ์ฌ ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ์ค๋น
if textView.text == "์ด๋ฆ์ ์
๋ ฅํ์ธ์." || textView.text == "์ ํ๋ฒํธ๋ฅผ ์
๋ ฅํ์ธ์." {
textView.text = nil
textView.textColor = .darkGray
} else {
textView.textColor = .darkGray //์ฌ์ฉ์๊ฐ ๊ฐ์ ์
๋ ฅ๋ ์ํ ์ผ ๋
}
}
// 2. ์ฌ์ฉ์๊ฐ ํ
์คํธ ๋ทฐ์ ์
๋ ฅ์ ๋ง์น ๋ ํธ์ถ๋๋ ๋ฉ์๋
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty{
if textView.tag == 1 {
textView.text = "์ด๋ฆ์ ์
๋ ฅํ์ธ์."
} else if textView.tag == 2 {
textView.text = "์ ํ๋ฒํธ๋ฅผ ์
๋ ฅํ์ธ์."
}
//ํ๋ ์ด์คํ๋ ํ
์คํธ์ ์์์ ํ์์ผ๋ก ๋ณ๊ฒฝ
textView.textColor = .systemGray4
}
}
}