프로필 수정 화면 구현 이전 글

0.Overview

.

.

.

프로필 수정 화면을 구현하기 위한 기본 UI이다. 

여기서 다룰 내용은 TextField와 TextView에 관련된 내용이다.

 

🧐 TextField vs TextView

먼저 둘 다 텍스트를 편집하기 위한 객체이다. 사용자로부터 텍스트를 입력받고, UI에 반영한다

 

TextField와 TextView의 차이가 뭘까, 사실 난 TextField의 존재만 알았다.

TextField에 2줄 이상의 텍스트가 입력되지 않자 해결 방법을 찾다가 TextView를 알게 되었다. 이게 힌트다.

 

TextField는 한 줄만 입력 받을 수 있고, TextView는 여러 줄 입력 받을 수 있다.

 

또 다른 차이로는, Placeholder 설정 방식이다.

TextField의 경우 Placeholder를 스토리보드에서 쉽게 설정 해줄 수 있는 반면, TextView는 코드로만 구현이 가능하다. (TextField도 물론 코드로 구현 가능하다.)

 

* Placeholder란, TextField 혹은 TextView에 사용자가 아무 것도 입력하지 않았을 때 나타나는 텍스트이다.

아래 이미지를 보면, Username 입력 칸에 'Username'이라고 표시된 부분이 바로 Placeholder이다.

 

Username 입력창은 한 줄만 입력받아도 충분하기 때문에 TextField이고, Bio 입력창은 여러 줄 입력 가능하도록 TextView로 구현했다.

여기에 텍스트를 입력하면, 다음과 같이 입력된 텍스트가 나타난다.

 

아직 초보라 스토리보드를 많이 활용하는데, 스토리보드에서 TextField를 클릭하면 우측 인스펙터 영역의 attribute inspector 탭에서 Placeholder를 쉽게 설정할 수 있다.

 

반면에 TextView는 코드로 따로 구현해야 한다.

    class MyProfileEditViewController: UIViewController {
    	// 프로퍼티 선언
    	@IBOutlet weak var bioTextView: UITextView!
        var placeholderLabel: UILabel!
        .
        .

viewDidLoad 함수에 다음과 같이 placeholder에 들어갈 문구, 폰트, 색상, 크기, 위치 등을 지정해준다.

        // bioTextViewD의 placeHolder 설정
        placeholderLabel = UILabel()
        placeholderLabel.numberOfLines = 0
        placeholderLabel.text = "Bio"
        placeholderLabel.font = UIFont.systemFont(ofSize: (bioTextView.font?.pointSize)!)
        bioTextView.addSubview(placeholderLabel)
        placeholderLabel.textColor = .lightGray
        placeholderLabel.isHidden = !bioTextView.text.isEmpty
        placeholderLabel.sizeToFit()
        placeholderLabel.frame.origin = CGPoint(x: 0, y: (bioTextView.font?.pointSize)! / 2)

그러면 아래처럼 Bio라는 Placeholder가 설정된 것을 확인할 수 있다. 하지만 텍스트를 입력했을 때 사라지지 않는다.

텍스트를 입력했을 때 placeholder가 사라지도록 하기 위해서는 텍스트가 입력될 때마다 글자수를 확인하여 placeholder의 숨김 여부를 결정하도록 해야 한다.

 

다음과 같이 구현할 수 있다.

// 텍스트 입력할 때마다 placeholderLabel의 숨김 여부 결정
@objc private func textDidChange(_ notification: Notification) {
        placeholderLabel.isHidden = !bioTextView.text.isEmpty
}
// NotificationCenter에 textDidChange 등록
NotificationCenter.default.addObserver(self,
                                       selector: #selector(textDidChange(_:)),
                                       name: UITextView.textDidChangeNotification,
                                       object: bioTextView)

전체 코드

//  MyProfileEditViewController.swift

import UIKit

class MyProfileEditViewController: UIViewController {
    
    
    @IBOutlet weak var bioTextView: UITextView!
    var placeholderLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupAttribute()
    }
    
    @objc private func textDidChange(_ notification: Notification) {
            placeholderLabel.isHidden = !bioTextView.text.isEmpty
    }
    
    func setupAttribute() {
        
        // NotificationCenter에 textDidChange 등록
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(textDidChange(_:)),
                                               name: UITextView.textDidChangeNotification,
                                               object: bioTextView)
        
        // bioTextViewD의 placeHolder 설정
        placeholderLabel = UILabel()
        placeholderLabel.numberOfLines = 0
        placeholderLabel.text = "Bio"
        placeholderLabel.font = UIFont.systemFont(ofSize: (bioTextView.font?.pointSize)!)
        bioTextView.addSubview(placeholderLabel)
        placeholderLabel.textColor = .lightGray
        placeholderLabel.isHidden = !bioTextView.text.isEmpty
        placeholderLabel.sizeToFit()
        placeholderLabel.frame.origin = CGPoint(x: 0, y: (bioTextView.font?.pointSize)! / 2)
    }

}

 

 

 

참고 링크

https://ios-development.tistory.com/693

 

[iOS - swift] TextView placeholder 적용 방법

placeholder 적용 textView 초기화 text를 placeHolder 문자열, color를 placeHolder 색상으로 변경 delegate 설정 // ViewController.swift let textViewPlaceHolder = "텍스트를 입력하세요" lazy var textView..

ios-development.tistory.com

https://roniruny.tistory.com/151

 

[iOS] NotificationCenter?

🔹 Notification? observer들에게 전달되는 구조체로 정보가 담겨있고, 해당 알림을 등록한 observer에게만 전달됩니다. 구조체는 아래와 같이 구성되어 있습니다. 1️⃣ name : 전달하고자 하는 notificati

roniruny.tistory.com

 

지금 진행 중인 프로젝트가 SNS와 성격이 비슷하다. 그래서 SNS의 기본적인 기능, 그 중에서도 프로필 화면 관련해서 겪은 시행착오를 토대로 알게 된 내용을 정리해 보려 한다.

 

다룰 내용은 다음과 같다.

 

1. UITextVeiw에 Placeholder 설정하기(UITextField와 UITextField의 차이)

가장 먼저 기본 UI를 구성해야 한다. UIImageView나 UILabel 등의 배치 및 Constraints(제약조건) 설정 등의 기본적인 내용 보다는, UITextField와 UITextView의 차이, UITextVIew의 placeholder 설정 방법 등 새로 알게 된 내용 위주로 정리하려 한다. 

 

2. 다른 뷰컨트롤러로 데이터 전달 (Delegate Pattern)

사용할 뷰컨트롤러는 총 두 개이다. 하나는 '내 프로필 화면', 다른 하나는 '내 프로필 수정 화면'이다.

'내 프로필 화면'에서 '프로필 수정' 버튼을 눌렀을 때, 기존 프로필 정보(프로필 사진, 사용자 이름, 소개 글)을 '프로필 수정 화면'으로 넘겨주는 기능을 구현할 것이다.

 

3. 카메라 / 앨범 접근 후 사진 가져오기

프로필 사진을 업로드하기 위한 기능이다. UIImagePicker를 사용해 사진을 가져오는 방법, 카메라 / 앨범 접근을 위해 '접근허용' 설정 방법 등을 다룰 것이다.

 

4. 수정된 프로필 정보를 이전 뷰(내 프로필 화면)으로 전달하기 (Delegate Pattern)

2번 내용과 비슷하다. 굳이 따로 다룰 필요가 있을까 싶긴 한데.. 마무리 느낌으로 ^~^

사실 지금 하고 있는 프로젝트에서는 이 부분이 가장 문제이다.. 블로그에서는 간단히 뷰컨트롤러 -> 뷰컨트롤러 간의 데이터 전달이라 비교적 쉽다. 하지만 프로젝트에서는 뷰컨트롤러 -> 셀 로 전달해야 하는데, 뷰컨트롤러와 셀의 swift 파일이 달라서 그런지 셀에 접근하는 방법을 모르겠다.. 어차피 서버와 연동하면 서버에서 데이터를 받아오면 그만이니 큰 문제는 아닌 것 같긴 한데, 찝찝한걸....구구절절,,,,

아무튼 여기선 간단히 구현해보려 한다.

.

.

.

짠 후다닥 만든 허접한 기본 화면.. 차근차근 시작해 보자!!

ViewController에서 버튼을 누르면 다른 ViewController로 이동하는,, ViewController간 데이터 전달은 간단하다.

 

아래 처럼 왼 쪽 ViewController의 'Next Button'을 눌러 오른 쪽 하늘 색 배경의 SecondViewController로 이동하고자 하는 경우, 아래 코드로 쉽게 구현할 수 있다.

단, 코드에서 SecondViewController에 접근하기 위해, 오른쪽 인스펙터 영역에 보이는 것 처럼 Class와 Storyboard ID를 등록해주어야 한다.

이렇게 구현하는 방법을 present 방식이라 하는데, viewController간 화면 전환은 이 방법 말고도 다양하다.

 

.

.

.

 

본론으로 들어가서, 내가 작업하고 있는 상황은 위와는 조금 다르다.

 

ViewController 위에  CollectionViewCell이 있고, CollectionViewCell 위에 각각의 셀을 따로 swift 파일로 만들어서 작업하고 있었다. 말이 좀 복잡한데,, 다음과 같은 상황이다.

ViewController 위에 CollectionView가 있다. 그 위에 FirstCollectionViewCell을 추가해주었다. (Cell 등록 및 구현 방법은 코드 참고)

실행시키면 다음과 같이 나타난다.

CollectionView의 Section0에 FirstCollectionViewCell이 추가 되었다. 해당 셀의 Next Button을 눌렀을 때 Second View Controller로 화면이 이동하는 것이 목표이다.

 

간단히 정리하자면 ViewController가 FirstCollectionViewCell의 버튼 기능을 위임 받으면 된다. 이를 'Delegate Pattern'이라 칭한다. 한 객체가 다른 객체의 기능을 위임 받아 대신 동작할 수 있도록 하는 것이다.

 

 

 

 

Delegate Pattern을 적용하는 방법

 

1. 위임을 요청할 메소드를 프로토콜로서 정의한다.

   - 'Next Button'을 눌렀을 때의 동작을 위임할 것이므로 다음과 같이 정의해준다.

// ViewController.swift
protocol CollectionViewCellDelegate {
    func nextButtonDidTap(index: Int)
}

 

2. 위임받을 동작에 대한 함수를 구현 해준다.

   - 'Next Button'을 눌렀을 때 Main 스토리보드에 있는 SecondViewController로 이동하도록 한다. 맨 처음 ViewController간  화면전환 구현 코드와 동일하다. "SecondVC" 자리에 스토리보드 아이디를 입력하면 된다.

// ViewController.swift
extension ViewController: CollectionViewCellDelegate {
    func nextButtonDidTap(index: Int) {
        let secondViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondVC") as! SecondViewController
        secondViewController.modalPresentationStyle = .fullScreen
        self.present(secondViewController, animated: true)
    }
}

 

 

2. index 프로퍼티를 생성하고 index 값을 넘겨준다.

// FirstCollectionViewCell.swift
    @IBOutlet weak var nextButton: UIButton!
    
    var index: Int = 0
    var delegate: CollectionViewCellDelegate?
    
    @IBAction func nextButtonDidTap(_ sender: Any) {
        self.delegate?.nextButtonDidTap(index: index)
    }

 

 

3. 셀 생성시 프로토콜 변수의 레퍼런스를 ViewController로 설정하고 해당 셀의 index를 위임 받을 cell의 index 프로퍼티로 설정한다.

   - 이 부분은 정확히 이해 못했는데... 셀을 등록하고 나서 주석 처리 부분 사이의 코드 두 줄을 입력해서 index를 넘겨주는 것 같다.

// ViewController.swift
func collectionView(_ collectionView: UICollectionView,
                    cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(
            withReuseIdentifier: FirstCollectionViewCell.identifier,
            for: indexPath) as? FirstCollectionViewCell else {
                fatalError()
            }

	// 이 부분!
        cell.index = indexPath.row
        cell.delegate = self
        //

        return cell
}

 

끝!!!!!

쫘잔..

 

 

참고 링크

https://juhyeoklee.github.io/ios/ios-post06/

 

[iOS] Delegation Pattern 을 이용한 Cell 안의 버튼 이벤트 처리

AppJam 회고

juhyeoklee.github.io

 

인스타그램에서 상대방 프로필에 들어갔을 때, 아무 게시글도 올리지 않았을 경우 'No posts yet'이라는 텍스트와 함께 뜨는 화면이 있다. 그런 화면을 'empty view'라 하는 것 같다.

 

나의 경우 컬렉션 뷰를 여러 섹션으로 나눠서 각 섹션 별로 셀을 다루는 작업을 하고 있었는데, 특정 섹션에서 셀 개수가 0일 때 empty view를 띄우는 것이 목적이었다.

이런 느낌.. section 2의 cell 개수가 0일 때 empty view 띄우는 것이 목적

특정 섹션의 셀 개수에 접근하는 부분을 코드로 어떻게 작성해야할 지 몰라 헤맸는데, 생각보다 간단했다.

// Declaration
func numberOfItems(inSection section: Int) -> Int

 

(해당 컬렉션 뷰 이름).numberOfItems(inSection: (해당 섹션 번호))

 

로 접근하면 된다.

 

실제로 사용할 땐 다음과 같이 if문을 사용하여 해당 섹션의 데이터 수가 0일 경우 이미지 뷰의 isHidden 값을 false로 바꾸어 화면에 나타나게 할 수 있다. 이미지 뷰는 컬렉션 뷰 자체에 구현해주면 된다.

if (profileCollectionView.numberOfItems(inSection: 2) == 0) {
            no_posts.isHidden = false
        }

 

그러면 다음과 같이 나타난다.

 

섹션1 색상을 하늘색으로 넣으려 했는데 실수로 뷰컨트롤러와 같은 색인 연보라 색으로 넣어서 티가 안나네.......중요한 건 아니니까 뭐..

셀 개수가 1개 이상일 때

 

셀 개수가 0개일 때

 

 

 

 

참고 링크

https://developer.apple.com/documentation/uikit/uicollectionview/1618016-numberofitems

 

Apple Developer Documentation

 

developer.apple.com

https://mini-min-dev.tistory.com/115

 

[iOS] 아무 데이터가 없을 때 나오는 화면,엠티뷰(empty view) 만들기

iOS 개발을 하면, 가장 자주 만들어야 할 화면이 바로 테이블 뷰와 컬렉션 뷰일 거다. 테이블 뷰(TableView)와 컬렉션 뷰(CollectionView)는 모두 같은 형태의 데이터를 표출할 때 큰 틀만 만들어두고, 그

mini-min-dev.tistory.com

 

+ Recent posts