튜토리얼

15

분 소요

검색창 프로토타입을 만드는 방법

ProtoPie의 "indexOf" 및 "lowerCase" 함수를 사용해 완전히 작동하는 검색 필드/바를 프로토타입으로 제작하세요.

Jeff Clarke, UX Designer & ProtoPie Educator

빠른 요약

거의 모든 디지털 경험에는 어떤 형태로든 검색 경험이 포함되며, 언젠가는 그 경험을 프로토타이핑해야 할 가능성이 높습니다. 작동하는 검색창은 대부분의 프로토타이핑 도구의 기능 범위를 넘어서는 경우가 많아, 디자이너인 우리는 종종 검색 경험이 여러 대표적인 상태에서 어떻게 보이는지 몇 장의 스크린샷으로 보여 주며 그 경험을 흉내 내곤 합니다.

💡 이 제한은 ProtoPie에서는 존재하지 않습니다!

ProtoPie의 고급 코드 없는 로직 모델을 사용하면 진정으로 기능하는 검색창 경험을 빠르고 쉽게 만들 수 있습니다. 또한 많은 프로토타이핑 도구가 시각적 스타일을 재사용하기 위해 컴포넌트를 만들 수 있는 기능을 제공하지만, ProtoPie는 한 걸음 더 나아가 인터랙션은 물론 이 튜토리얼에서 더 중요한 로직까지 재사용할 수 있게 해 줍니다.

아래 데모를 보고 무엇을 만들 수 있는지 확인해 보세요.


prototype that includes a functioning search bar


검색창 프로토타입

시작 Pie 파일완성된 Pie 파일

개요

  • 배우게 될 내용

  • 시작하기 전에

  • 단계별 가이드

  • 1부: 검색 설정하기

  • 2부: 검색창에 결과 표시하기

  • 3부: 대소문자 구분 없이 검색하기

  • 4부: 결과 접기

  • 왜 이게 작동할까요?

  • 이것으로 끝! 파이처럼 쉽습니다!

  • 완전히 작동하는 검색창으로 프로토타입을 한 단계 끌어올리세요

배우게 될 내용

이 튜토리얼을 끝내면 다음을 배우게 됩니다

  • 내장된 indexOf()lowerCase() 함수를 사용하는 방법.

  • 컴포넌트가 씬 및 서로 간에 통신하도록 만드는 방법.

  • 컴포넌트 안에 재사용 가능한 로직을 구축하는 방법

  • 작동하는 검색 경험을 얼마나 빠르고 쉽게 만들 수 있는지. 정말 그렇습니다! 이게 얼마나 쉬운지 놀라게 될 거예요!

완료 시간: 15분 이하

시작하기 전에

먼저 시작 Pie 파일을 열어 보세요. 여기에는 8곡이 나열된 모의 음악 앱이 들어 있습니다. 목록 상단에는 검색 상자가 있습니다. 목록의 각 곡은 'Song'이라는 컴포넌트의 복사본입니다. 모든 곡의 구조가 동일하기 때문에 컴포넌트로 만든 것입니다.

같은 작업을 8번 반복하는 대신, 컴포넌트를 사용해 구조를 한 번만 만들고 씬에는 8개의 복사본을 배치한 다음 각 복사본마다 커버 아트, 노래 제목, 아티스트를 맞춤 설정했습니다.

검색창을 작동시키기 위해 씬과 Song 컴포넌트의 마스터 복사본 내부에서 모두 작업할 예정입니다.

단계별 가이드

1부: 검색 설정하기

먼저 메인 씬의 검색창에 인터랙션을 추가해 봅시다.

  • Search field 입력 레이어에 Detect 트리거를 추가하세요. 감지할 속성으로 Text를 선택합니다.


Add a Detect Trigger to the Search Field input layer


Detect 트리거

  • Send Response를 추가하세요. 채널은 "Send to Current Scene"을 선택합니다. 메시지는 SEARCH를 사용하고, "Send Value Together" 체크박스를 선택합니다. 나타나는 상자에 다음 공식을 사용하세요: ``Search field.text


Add a Send response


Send Response

💡 무슨 일이 일어나고 있나요?

Detect 트리거는 검색창의 텍스트 속성 값이 바뀔 때마다 실행됩니다. 키를 누를 때마다 SEARCH 메시지가 검색창의 내용과 함께 씬으로 전송됩니다. 이 메시지를 듣도록 설정된 모든 대상은 이를 수신하고 응답할 수 있습니다. 다음 단계에서 이를 해 보겠습니다!

노래 목록의 각 항목을 컴포넌트로 만드는 장점은 마스터 컴포넌트 안에 로직을 넣을 수 있고, 그 로직이 모든 복사본에 포함된다는 점입니다. 이렇게 하면 각 컴포넌트가 검색과 일치하는지 스스로 판단하도록 만들 수 있습니다.

  • Song 컴포넌트의 마스터 복사본으로 이동하세요.


Go to the Component Scene


Component Scene

이제 Song 컴포넌트의 마스터 복사본을 편집하고 있으므로, 여기서 하는 모든 작업은 메인 씬의 모든 복사본에 자동으로 복제됩니다. 이제 컴포넌트가 SEARCH 메시지에 반응하도록 만들어 봅시다.

  • Receive 트리거를 추가하세요. 채널은 "Receive from Current Scene"을 선택합니다. 메시지는 SEARCH를 사용합니다. "Assign to Variable" 체크박스를 선택하세요. 현재 컴포넌트에는 변수가 없으므로 새로 만들어야 합니다.


Add a Receive trigger


Receive Trigger

💡 Receive 트리거를 설정할 때는 메시지 그리고 메시지를 받는 채널이 해당 Send Response에서 사용한 값과 일치해야 합니다.

  • 컴포넌트에 변수를 만들고 이름을 searchKeyword로 지정하세요. 타입은 Text로 설정합니다.


Create a variable called searchKeyword


searchKeyword라는 변수를 생성

  • 이제 이전 단계에서 만든 Receive 트리거로 돌아가서 "Assign to Variable" 아래에서 새로 만든 searchKeyword 변수를 선택하세요.


Choose the newly created variable under assign to variable


Assign to Variable에서 새로 만든 변수를 선택

💡 Pie가 값과 함께 전달된 메시지를 받으면, 먼저 그 값을 변수에 할당해야만 사용할 수 있습니다. 지금 우리가 Assign to Variable을 선택하는 이유가 바로 그것입니다.

2부: 검색창에 결과 표시하기

이제 Song 컴포넌트가 씬에서 검색 키워드를 받을 수 있게 설정했습니다. 이제 키워드가 노래 제목의 일부와 일치하는지 확인해 보고자 합니다.

조건식에서 ProtoPie의 내장 indexOf() 함수를 사용할 것입니다. indexOf()는 어떤 텍스트 안에 다른 텍스트가 존재하는지 살펴봅니다. 이 함수는 sourcesearchValue라는 두 개의 매개변수와 함께 작동합니다.

  • source는 검색하려는 텍스트입니다. 여기서는 Song 제목입니다.

  • searchValuesource 안에서 찾고 싶은 키워드입니다. 이것은 변수 searchValue에 전달한 값이 됩니다.

indexOf()를 실행하면 발견된 텍스트의 위치를 나타내는 숫자, 또는 일치하는 항목이 없을 경우 -1을 반환합니다. 우리는 두 가지 경우만 중요합니다:

  • 함수가 -1을 반환하면 이 곡은 검색과 일치하지 않으며, 따라서 검색 결과에서 제외되어야 합니다.

  • 함수가 -1이 아닌 무엇이든 반환하면 이 곡은 검색과 일치하므로 결과에 포함되어야 합니다.

indexOf()가 어떻게 동작하는지 봅시다!

  • 여전히 Song 컴포넌트의 마스터 복사본에서, Receive 트리거 아래에 조건을 추가하세요.

  • 조건에서는 첫 번째 가능성, 즉 일치하지 않는 경우를 확인할 것입니다.

  • 첫 번째 드롭다운에서 "Formula"를 선택합니다.

  • 다음 공식을 사용하고 OK를 클릭하세요: indexOf('``Title'``.text, searchKeyword)

  • 연산자로 = (같음)을 그대로 선택한 상태로 두고, 아래 상자에 -1을 입력하세요.


Use ProtoPie’s built-in indexOf() function in our condition


조건에서 ProtoPie의 내장 indexOf() 함수 사용

💡 Operator는 ProtoPie에게 비교를 어떻게 수행할지 지시합니다. 조건 가운데에 있는 아이콘 줄 — > ≥ < ≤ = ≠ — 을 보세요. 이것이 ProtoPie에서 사용할 수 있는 모든 연산자입니다.

  • 일치하지 않을 때는 곡을 숨깁니다. 조건 아래에 Opacity Response를 추가하세요. 컴포넌트의 최상위 컨테이너인 Song 레이어를 선택합니다. 불투명도를 0으로, 지속 시간을 0으로 설정하세요. 지속 시간을 0으로 설정하면 불투명도 변화가 애니메이션되지 않습니다. 즉시 발생합니다.


Add an Opacity Response under our condition


조건 아래에 Opacity Response 추가

이제 두 번째 가능성, 즉 검색과 일치하는 경우를 처리해야 합니다.

  • 또 다른 조건을 추가하세요. 상단 부분에는 동일한 공식을 사용합니다: indexOf('``Title'``.text, searchKeyword).

  • 이번에는 (같지 않음) 연산자를 선택합니다. 값에는 다시 -1을 사용하세요.


Add another condition under the Receive trigger


Receive 트리거 아래에 다른 조건 추가

더 명확하게 하기 위해 조건의 이름을 바꿔 봅시다.

  • 첫 번째 조건을 더블클릭하고 이름을 NO MATCH로 바꾸세요

  • 두 번째 조건을 더블클릭하고 이름을 MATCH로 바꾸세요


Let’s rename our conditions
  • 조건 이름을 바꿔 봅시다*

이 시점에서 검색은 작동해야 합니다. 메인 씬으로 돌아가 봅시다.

  • 미리보기를 실행해 보세요. 입력하는 동안 검색어와 일치하지 않는 곡은 사라지고, 백스페이스를 누르면 다시 나타나는 것을 볼 수 있어야 합니다.


Preview of search bar prototype in the preview window


미리보기 창에서 작업을 미리보기

몇 가지 간단한 단계만으로 작동하는 검색 경험의 기반을 만들었습니다!

작동은 합니다. 하지만 아마도 문제를 발견했을 것입니다. 대문자 “C”로 검색하면 세 곡이 계속 표시됩니다. 하지만 소문자 “c”로 검색하면 결과가 나오지 않습니다.


Search bar prototype shows different search results for lowercase and uppercase letters


소문자와 대문자에 따라 다른 검색 결과

이 문제를 해결해 봅시다!

3부: 대소문자 구분 없이 검색하기

indexOf() 함수를 사용할 때는 대소문자가 중요합니다. 이 함수 입장에서는 Cc가 같은 것이 아닙니다. 하지만 이런 동작에 만족한다면 사용자 경험은 좋지 않을 것입니다.

이 문제를 해결하려면 대소문자 민감성을 식에서 제거해야 합니다. 우리의 접근 방식은 indexOf() 함수를 실행하기 전에 검색 키워드 그리고 노래 제목을 둘 다 소문자로 변환하는 것입니다.

ProtoPie에는 lowerCase()라는 또 다른 내장 함수를 사용할 수 있습니다. 이름 그대로 텍스트를 소문자로 변환합니다. 예를 들어, lowerCase("ProtoPie is the BEST!!")protopie is the best!!를 반환합니다.

lowerCase()가 어떻게 동작하는지 봅시다!

여전히 메인 씬에서, Detect 트리거 아래의 Send Response를 수정해 봅시다.

  • "Send Value Together" 아래 상자에서 기존 공식을 다음과 같이 lowerCase() 함수를 사용하도록 수정하세요: lowerCase('Search field'.text). 이렇게 하면 검색창에 입력한 내용의 소문자 버전을 모든 컴포넌트가 받게 됩니다.


Modified existing formula to use the lowerCase() function


기존 공식을 lowerCase() 함수 사용하도록 수정

💡 lowerCase() 함수 이름의 대문자 “C”에 주목하세요. 함수 이름도 대소문자를 구분합니다. 작은 “c”를 사용해 lowercase()라고 잘못 입력하면 공식이 작동하지 않습니다.

indexOf()를 실행하기 전에 Song title에도 같은 작업을 해야 합니다.

  • Song 컴포넌트의 마스터 복사본을 다시 편집하세요.

  • 두 조건 모두 수정해야 합니다. 첫 번째 조건을 클릭하고 다음과 같이 공식을 수정하세요: indexOf(lowerCase('Title'.text), searchKeyword)


first condition


첫 번째 조건 수정

**💡 무슨 일이 일어나고 있나요? **

함수는 다른 함수 안에 중첩될 수 있으며, 따라서 다른 함수의 매개변수로 사용할 수 있습니다.

indexOf() 함수는 첫 번째 매개변수로 Text를 기대하므로, Text를 출력하는 모든 함수를 사용할 수 있습니다. 바로 lowerCase() 함수가 그렇게 합니다! 함수가 이렇게 중첩되면 안쪽 함수가 바깥 함수보다 먼저 실행됩니다. 그 결과 indexOf()는 노래 제목을 소문자로 변환한 상태로 작동합니다.

  • 두 번째 조건의 공식도 동일하게 수정하세요.


second condition


두 번째 조건 수정

메인 씬으로 돌아가 다시 미리보기 하세요. 이제 검색이 대소문자를 구분하지 않아야 합니다.

4부: 결과 접기

검색은 완전히 작동하지만, 검색과 일치하지 않는 곡들이 있던 자리에 빈 공간이 남습니다. 결과가 표시될 때 이를 접어서 정리하고 싶습니다.

메인 씬에서 컴포넌트로 메시지를 보낼 수 있었던 것처럼, 컴포넌트끼리도 서로 메시지를 보낼 수 있습니다. 하지만 그 전에, 서로를 구분할 수 있도록 컴포넌트를 수정해야 합니다.

  • Song 컴포넌트의 마스터 복사본을 편집하세요.

  • id라는 변수를 만드세요. 기본값인 Number 타입으로 두세요. "Make Overridable" 체크박스를 선택합니다.


variable called id


id라는 변수 만들기

💡 "Make Overridable"을 선택하면 씬의 각 컴포넌트 복사본이 id에 대해 서로 다른 값을 가질 수 있습니다.

  • 메인 씬으로 돌아가세요. 각 Song 컴포넌트 복사본의 오른쪽 속성 패널에는 "Overrides" 섹션이 있으며, 새로 만든 id 변수를 편집할 수 있다는 것을 확인할 수 있습니다.


The Overrides section in the property panel


속성 패널의 Overrides 섹션

  • 각 컴포넌트 복사본의 id에 서로 다른 값을 지정하세요. 순차적인 값을 사용합니다.

  • 예: 첫 번째 항목 “The Celebrated Ways”의 값을 1로 지정

  • 두 번째 항목 “Feel Again”의 값을 2로 지정

  • 세 번째 항목 “Good Enemy”의 값을 3로 지정

  • 등등.


Give each component a different value for id


각 컴포넌트의 id 값을 다르게 지정

💡 **이 순차적인 번호 매기기는 우리의 로직에서 매우 중요해집니다. **

다행히 복사본의 레이어 이름은 id가 가져야 하는 값과 일치합니다. 잠시 시간을 내어 Song 1id:1인지, Song 2id:2인지 등을 Song 8까지 다시 확인하세요.

이제 마법이 일어나게 해 봅시다!

  • Song 컴포넌트의 마스터 복사본을 다시 편집하세요.

  • "NO MATCH" 조건 아래에 Send Response를 추가하세요. 채널은 "Send to Current Scene"을 선택합니다. 메시지는 REORDER를 사용합니다. "Send Value Together" 체크박스를 선택하고 아래에 나타나는 상자에는 id 공식을 사용하세요.


Send Response under the condition


조건 아래에 Send Response 추가

  • hiding_id라는 새 변수를 만드세요. 기본 Number 타입으로 둡니다.


new variable called hiding_id


hiding_id라는 새 변수 만들기

  • "NO MATCH" 조건 아래에 Send Response를 추가하세요.

  • Receive Trigger를 추가하세요. 채널은 "Receive from Current Scene"을 선택합니다. 메시지는 REORDER를 사용합니다. "Assign to Variable" 옆 체크박스를 선택하세요.

  • Receive Trigger에서 "Assign to Variable" 아래 새로 만든 hiding_id 변수를 선택하세요.


hiding_id variable


hiding_id 변수 선택

계속하기 전에 무엇이 일어날지 짚고 넘어가는 것이 중요합니다.

우리는 "NO MATCH" 조건에서 Send Response를 사용해 REORDER 메시지를 브로드캐스트했습니다. 컴포넌트들이 서로 대화할 수 있다고 가정하면, Song 컴포넌트의 이 특정 복사본은 다른 모든 복사본에게 “나는 id:x.입니다. 검색과 일치하지 않으므로 숨깁니다. 다른 모든 컴포넌트는 그에 맞게 다시 정렬하세요.”라고 말하는 셈입니다.

이 시점에서 메시지를 보낸 복사본을 포함하여 Song 컴포넌트의 모든 복사본이 그 메시지를 받게 됩니다. 또한 메시지를 처음 보낸 컴포넌트의 id도 함께 보내 hiding_id라는 변수에 할당했습니다. Receive에서는 각 복사본이 자신의 idhiding_id와 비교합니다.

핵심은 여기입니다:

받는 쪽의 id가 보내는 쪽의 id보다 크면 (즉, id > hiding_id) 받는 쪽의 위치를 한 칸 위로 이동시킬 것입니다. 그래서 각 곡에 id 값을 줄 때 순차 번호를 사용해야 했던 것입니다.

실행되는 모습을 봅시다.

  • Receive Response 아래에 조건을 추가하세요. 첫 번째 드롭다운에서 변수 id를 선택합니다. > (greater than) 연산자를 클릭하세요. 아래 드롭다운에서 hiding_id 변수를 선택합니다.


Condition under the Receive Response


Receive Response 아래에 조건 추가

  • 조건 아래에 Song 레이어에 Move Response를 추가하세요. "Position" 드롭다운에서 "Move By"를 선택하고, Y 상자에 -84를 입력합니다. 마지막으로 지속 시간을 0으로 설정해 이 이동이 애니메이션되지 않도록 합니다.


Added Move Response to the Song layer


조건 아래에 Song 레이어에 Move Response 추가

이것만 하면 됩니다! 이제 메인 씬으로 돌아가 미리보기를 확인하세요. 검색이 완전히 작동해야 합니다!

왜 이게 작동할까요?

왜 이것이 작동하는지 아직 조금 헷갈린다면, 로직을 다시 정리해 봅시다. 위의 내용이 모두 이해된다면 건너뛰어도 좋습니다.

숨기기, 초기화, 재정렬은 매번 키 입력마다 일어납니다

검색창에 글자를 입력할 때마다 모든 컴포넌트는 이전에 일치했는지 여부를 기억하지 않은 채 현재 검색과 일치하는지 판단합니다. 일치하면 이미 보이고 원래 위치에 있더라도 스스로를 초기화합니다(위치와 불투명도 모두). 일치하지 않으면 이미 숨겨져 있더라도 스스로를 숨깁니다. 스스로를 숨기는 모든 항목은 자신의 id와 함께 REORDER 메시지를 브로드캐스트하며, 그 아래에 있는 모든 컴포넌트(예: 숨는 컴포넌트보다 id가 큰 컴포넌트)는 84픽셀 위로 이동합니다.

예를 하나 살펴봅시다. 우선 첫 3곡만 보고 나머지는 무시하겠습니다.

  1. “The Celebrated Ways”

  2. “Feel Again”

  3. “Good Enemy”

사용자가 검색창에 문자 n을 입력한다고 가정해 봅시다. 다음과 같이 진행됩니다:

  • Song 1은 일치하지 않아 스스로를 숨깁니다.

  • Song 1은 자신의 id 값과 함께 모든 컴포넌트에 REORDER를 브로드캐스트합니다.

  • Song 2는 일치하므로 스스로를 초기화합니다.

  • Song 2는 Song 1로부터 REORDER를 받아 첫 번째 자리로 이동합니다.

  • Song 3은 일치하므로 스스로를 초기화합니다.

  • Song 3은 Song 1로부터 REORDER를 받아 두 번째 자리로 이동합니다.

이제 사용자가 검색창에 계속 입력한다고 가정해 봅시다. 다음으로 입력하는 문자는 e이며, 검색어는 ne가 됩니다. 다음과 같이 진행됩니다:

  • Song 1은 일치하지 않아 이미 숨겨져 있었더라도 다시 스스로를 숨깁니다.

  • Song 1은 모든 컴포넌트에 REORDER를 브로드캐스트합니다.

  • Song 2는 일치하지 않아 스스로를 숨깁니다.

  • Song 2는 모든 컴포넌트에 REORDER를 브로드캐스트합니다.

  • Song 2는 Song 1로부터 REORDER를 받아 첫 번째 자리로 이동하지만, 이미 숨겨져 있으므로 보이지 않습니다.

  • Song 3은 일치하므로 스스로를 초기화하고, 원래 위치인 3번 자리로 다시 돌아갑니다.

  • Song 3은 Song 1로부터 REORDER를 받아 두 번째 자리로 이동합니다.

  • Song 3은 또한 Song 2로부터 REORDER를 받아 다시 한 번 첫 번째 자리로 이동합니다.

이것으로 끝! 파이처럼 쉽습니다!

작동하는 검색 경험을 만들면서 ProtoPie의 가장 강력한 기능들 중 여러 가지를 성공적으로 활용했습니다:

  • 함수와 공식

  • indexOf()lowerCase() 함수를 사용하는 방법을 배웠습니다

  • 이 함수들을 서로 중첩해 공식 안에서 복잡한 정보 조작을 수행하는 방법을 배웠습니다

  • Send & Receive

  • Send와 Receive를 사용해 메인 씬이 모든 컴포넌트와 통신하고, 컴포넌트끼리도 서로 통신하도록 만들었습니다.

  • 기능형 컴포넌트

  • 컴포넌트는 시각적 스타일 측면에서 재사용 가능할 뿐만 아니라, 기능적으로도 재사용 가능하도록 만들었습니다! 실제로 Song 컴포넌트가 경험을 구현하는 대부분의 작업을 수행합니다.

무엇보다도, 이렇게 쉽게 작동하도록 만들 수 있었다는 사실을 직접 확인하셨기를 바랍니다. 내장 함수는 단지 몇 개만 사용되었고 — 가장 중요한 것은 — 코드가 전혀 없었다는 것!

완전히 작동하는 검색창으로 프로토타입을 한 단계 끌어올리세요

검색하고, 클릭하고, 감탄할 준비가 되셨나요? 그렇다면 ProtoPie를 시작하고 검색창 튜토리얼을 따라 끊김 없는 사용자 경험을 만들어 보세요.

무료로 시작하기

프로토타이핑에 대해 더 배우고 싶으신가요?

[도움이 되었나요? 알려 주세요!]