
사각형형태의 텍스트 입력 상자를 만들고, 입력을 받을 때 입력값이 없으면
"이 곳에 값을 입력해주세요"와 같은 PlaceHolder를 넣어두고 싶었다.
TextField와 TextEditor 중에서 나는 TextEditor를 사용하기로 했다.
나는 박스 사이즈에 맞게 여러줄로 텍스트를 입력받고 싶었다.
그런데, TextField의 경우 기본적으로 한 줄 텍스트에 적합한 구조를 가지고 있었다.
![]() | ![]() | ![]() |
|---|---|---|
| 공간 차지 차이 | 텍스트필드 줄바꿈 차이 | frame으로 사이즈 고정시 차이 |
텍스트 필드는 기본적으로 한 줄로 값을 입력받는 데 최적화되어 있다고 생각했다.
TextEditor가 지정된 영역을 전부 차지하며 텍스트를 한 번에 보여준다면, TextField의 경우에는 문자열의 크기에 맞게 영역을 차지하고 기본적으로는 가로로 커서가 움직이며 문자열을 표현한다.
TextField("여기에 값을 입력해주세요",text: $memo, axis: .vertical)
axis속성값을 지정하면 텍스트가 지정 영역을 넘쳤을 때 보여주는 방향을 조절할 수 있는데, vertical로 설정시 아래로 공간이 확장되긴 한다.
다만 이 경우에도 공간을 미리 가지고 있는 게 아니기 때문인지 엔터로 줄바꿈 조절을 할 수 없다.
TextEditor의 경우에는 줄바꿈이 엔터로 바로 가능했다.
마지막으로, frame 값으로 영역을 지정해주었을 때 TextField는 frame과 별개로 텍스트의 길이에 따라 가변적인 영역을 유지했다.
즉 위 3번째 화면에서 보이는 placeholder가 있는 줄만 클릭했을 때 커서가 뜨면서 동작이 반응했다.
struct TexFieldView: View {
@State var memo : String = ""
var body: some View {
TextField("여기에 값을 입력해주세요",text: $memo, axis: .vertical)
.frame(height: 100)
.border(Color.black)
TextEditor(text: $memo)
.frame(height: 100)
.border(Color.black)
}
}
똑같이 영향을 받은 textEditor에서는 프레임 사이즈에 맞춰 안 어디를 클릭하든 클릭이 인식되고 커서가 나타났다.
다음과 같은 이유로 사각형의 공간이 지정된 텍스트 입력창을 만들 때 TextEditor를 쓰기로 했다.
다만 원래 TextEditor에서는 PlaceHolder를 만드는 방식이 기본적으로 제공되지 않는다.
그래서 맨 처음에는 ZStack 또는 overlay를 활용하여 만들어둔 텍스트에디터 위에 텍스트를 그려주는 방식으로 해보았다.
@State var memo : String = ""
var body: some View {
TextEditor(text: $memo)
.frame(height: 100)
.border(Color.black)
.overlay(alignment : .topLeading) {
if memo.isEmpty {
Text("여기에 값을 입력해주세요")
.foregroundStyle(.gray)
.padding(EdgeInsets(top: 10, leading: 5, bottom: 0, trailing: 0))
}
}
}
커서의 위치와 text의 위치를 비슷하게 하기 위해 padding 값을 조절해주자 그럴듯해보였다.
그러나 이 방식에는 큰 문제가 있었다.
바로 텍스트에디터 위에 쌓인 저 Text를 누를 경우에는 TextEditor가 반응하지 않는다는 것이었다. 정작 커서가 뜨는 곳을 누르지 않고, frame 사이즈에 맞춘 외부를 눌러야 작동했다.
애플 디벨로퍼 포럼의 dev.capps.tech의 답변을 활용했다.
@state var momo : String = "추가 메모를 작성해 보아요"
(...)
let placeholder = "추가 메모를 작성해 보아요"
ZStack {
TextEditor(text: $memo)
.foregroundStyle(memo == placeholder ? .gray : .primary)
.font(.system(size: 22))
.frame(width: 363, height: 101)
.scrollContentBackground(.hidden)
.background(Color(red: 0.85, green: 0.85, blue: 0.85))
.onTapGesture {
if self.memo == placeholder {
self.memo = ""
}
}
}
초기값에 placeholder값을 입력해둔 후 onTapGesture로 placeholder의 원본값과 값을 비교하여 일치하면 ""로 초기화 후 입력을 받도록 설정했다.
이 방법을 사용하면 초기값으로 화면에 placeholder가 나타나기 때문에 이 부분을 클릭해도 바로 선택, 입력이 가능하다.
다만 이 방법의 문제점은 한 번 텍스트에디터가 선택된 후에는 아무 동작 없이 다시 빠져 나간다면, 다시 돌아왔을 때도 텍스트가 비어있는 공간으로 남아있다는 점이다.
placeholder는 정말 일회성인 것....!
고민하다가 일회성 placeholder로 일단 두기로 하고,
주변에 callout으로 설명을 덧붙이기로 했다.