brunch

You can make anything
by writing

C.S.Lewis

by Kenny Hong Aug 15. 2017

[번역글] Framer로 Apple 뮤직 앱 만들기 3

Recreating the Apple Music app in Framer

이전 글 : [번역글] Framer로 Apple 뮤직 앱 만들기(1)

이전 글 : [번역글] Framer로 Apple 뮤직 앱 만들기(2)




15. Progress Bar와 타이머 만들기

Progress Bar 추가하기

오디오 플레이어에는 내장된 progress bar가 있습니다. 이제 불러오도록 하겠습니다.

audio.showProgress = yes


포함된 progressBar는 표준 SliderComponent입니다 (화면 맨 위에 나타납니다).


그러나 SliderComponent는 사용자 정의가 가능하므로 원래 progree Bar디자인과 똑같이 보이게 만들수 있습니다. 다음 속성을 사용하게 되면요:

audio.progressBar.props =
     width: 311
     height: 3
     backgroundColor: "#DBDBDB"
     knobSize: 7
     x: Align.center
     y: 363
     parent: $.Now_Playing

앨범 커버와 같은 넓이, 311포인트, 그리고 3포인트 높이. 슬라이더  색은 밝은 회색으로 값은 "#DBDBDB"입니다.


knob 크기 또한 매우 작기 때문에  knobSize를 7로 설정해 줍니다.


$ .Now_Playing을 부모로 설정하게 되면 Now Playing 화면을 기준으로 값을 설정해 주시면 됩니다. Align.center를 사용하여 수평으로 중심을 맞추고, 위로부터 363 지점을 배치합니다.


SliderComponent의 왼쪽 부분은 fill 레이어도 자식 레이어이므로 별도로 색상을 설정해야 합니다:

audio.progressBar.fill.backgroundColor = "#8C8C91"


knob 에도 fill과 같은 색상값을 줍니다.

audio.progressBar.knob.props =
     backgroundColor: audio.progressBar.fill.backgroundColor
     shadowColor: null

(shadowColornull로 설정함으로써 dafault 그림자를 제거했습니다.)



에러 발생, 하지만 걱정하지 마세요

그나저나, 오디오 플레이어를 사용할 때 Framer 하단에 에러 메시지가 표시된 것을 발견하셨을 것입니다.


하지만 걱정할 필요는 없습니다. 모듈이 한동안 업데이트되지 않았기 발생한 에러인데요.


브라우저에서 프로젝트를 볼 때 오류가 표시되지 않도록 숨길 수 있는 방법이 있습니다:

Framer.Extras.ErrorDisplay.disable()

저는 이 라인을 프로젝트의 시작 부분에 추가했습니다.


시간 재생 카운터 추가

Progress bar 바로 아래, 왼쪽에는 Time Played 카운터가 필요합니다. 방법은 저희가 위에서 해오던 데로 하면 됩니다...

audio.showTime = yes


... 원하는 위치와 텍스트를 설정할 수 있습니다.

audio.time.props =
     x: audio.progressBar.x
     y: audio.progressBar.y + 7.5
     color: audio.progressBar.fill.backgroundColor
     style:
         fontSize: "14px"
     parent: $.Now_Playing

그리고 audio.progressBar보다 7.5포인트 아래에 배치하도록 하겠습니다.


오디오 플레이어 모듈은 텍스트 레이어 이전 시대의 모듈이므로 audio.time은 일반적인 레이어라고 생각하시면 됩니다. 그렇기 때문에 fontSizestyle 속성에 픽셀 단위로 설정해야 합니다.


남은 시간 카운터 추가

또한 남은 시간을 카운트해주는 기능 또한 있는데요.

audio.showTimeLeft = yes


쉽게 audio.timeLeftaudio.time과 동일한 속성을 제공하면 되는데요  몇 가지 차이점이 있습니다.

오른쪽 가장자리 인 maxX는 progressBar와 일치해야 합니다.

텍스트는 "right"에 정렬되어야 합니다.

audio.timeLeft.props =
     maxX: audio.progressBar.maxX
     y: audio.time.y
     color: audio.time.color
     style:
         fontSize: audio.time.style.fontSize
         textAlign: "right"
     parent: $.Now_Playing


여러분도 느끼셨다시피 모든 게 제 위치에 갔으므로, Sketch 파일에 있는 $ .Progress_bar를 숨기도록 하겠습니다.

$.Progress_bar.visible = no


브라우저에서 오픈  -  Framer에서 오픈




16. 볼륨 슬라이더 다시 만들기

Audio Player 모듈에는 볼륨 슬라이더도 있습니다. 예상대로 작동합니다 : 그럼 실행에 보도록 할까요...

audio.showVolume = yes


... 그리고 속성 값을 주도록 하겠습니다 :

audio.volumeBar.props =
     width: 266
     height: 3
     backgroundColor: audio.progressBar.backgroundColor
     knobSize: 28
     x: 50
     y: 564
     parent: $.Now_Playing
     value: 0.75

backgroundColorprogressBar 백그라운드 값과 같습니다. 현재 스케치 디자인에서의 볼륨은 75 %로 설정되었으므로 SliderComponent의 value 또한. 75로 설정하도록 하겠습니다.


fill 색상은 progressBar 색상과 동일합니다.

audio.volumeBar.fill.backgroundColor =
audio.progressBar.fill.backgroundColor


knob은 기본 흰색 색상을 유지하지만 그림자가 다르며 단지 0.5 포인트의 매우 얇은 border가 있습니다.

audio.volumeBar.knob.props =
     borderColor: "#ccc"
     borderWidth: 0.5
     shadowY: 3
     shadowColor: "rgba(0,0,0,0.2)"
     shadowBlur: 4


정상적으로 배치가 되었다면, 원래 스케치 레이어를 숨기도록 하겠습니다.

$.Volume_slider.visible = no
브라우저에서 오픈  -  Framer에서 오픈



17. Framer Design에서 Mini Player 그리기

Now Playing 화면을 아래쪽으로 드래그하면 탭 바 바로 위에 있는 작은 Mini Player로 전환됩니다.


Mini Player 디자인은 현재 스케치 파일에 없습니다. 아주 간단한데요, 투명한 배경과 앨범 아트의 비니 앨범 아트와 노래 제목이 미니 버전에 들어가게 됩니다.


그래서... 한번 Mini Player를 만들어 볼까요? 코드를 잠시 제쳐두고, Command + 1을 눌러 디자인 모드로 이동해 보도록 하죠.


저희의 디자인 화면은 여전히 비어 있습니다. 'Apple iPhone 7' 아트보드를 추가하면서 시작해 보도록 하겠습니다.

제가 이미 올바른 치수와 위치를  알기 위해 템플릿으로 스크린 샷을 만들었습니다. 다운로드하시고 아트보드로 드래그하세요.


추가된 Play 버튼이 있을 것입니다, 왜냐하면 저희는 하나씩 필요하기 때문이죠.


Retina 해상도로 인해 너무 커 보이지만 Sketch (또는 Framer Code)와 마찬가지로 속성 필드에서 계산을 사용할 수 있습니다. 따라서 너비를 750에서 750/2로 변경하면 올바른 크기로 가정할 수 있습니다.


실수로 템플릿을 선택하거나 드래그할 수 없도록 템플릿을 잠그는 것이 가장 좋습니다. 스크린 샷을 선택하고 ⌘L을 입력하십시오 (또는 마우스 오른쪽 버튼으로 클릭하고 'Lock'을 선택하십시오).


화면을 확대하고 먼저 Play 버튼을 만들어 보도록 하겠습니다.


'Play' 버튼 만들기

지금 Framer Design 에는 삼각형을 만들 방법이 없습니다.(적어도 이 글을 쓰고 있는 2017 년 7 월 현재까지는)


그러나 우리는 mask를 사용하면 가능합니다. 사각형을 회전하고 다른 사각형으로 클립 할 수 있습니다. 재생 버튼을 다시 만들려면이 두 세트가 필요하겠죠.


(그런데 재생 버튼과 앞으로 버튼이 원본과 정확히 같지 않은 경우가 단계를 건너뛰고 SVG를 검색할 수 있는 왼쪽 하단의 아이콘으로 이동할 수 있습니다.)


첫 번째 단계 : 두 개의 20 x 12 포인트 직사각형을 그리고 그중 하나를 31도 회전시킵니다.

두 개의 사각형, 회전 된 사각형 중 하나

회전된 사각형에 검은색으로 칠해 주세요.


수평으로 된 하나의 '마스크'에 이름을 붙여 (따로따로 두기가 쉬워지도록) 레이어의 맨 위에 드래그하여 검은색으로 만듭니다.


그리고 자연스럽게 부모의 클립을 사용하여 자식을 마스크 해야 합니다.


이제 첫 번째 삼각형이 생깁니다.


수평 사각형은 회전 된 사각형을 마스크한다.

버튼의 아래쪽 부분을 복사하고 마스킹된 직사각형의 회전을 조정할 수 있습니다. 자연스럽게 -31도가 되어야 합니다.


두 개의 작은 삼각형을 결합하여 큰 삼각형 만들기

'마스크'사각형에는 여전히 기본 (투명) 파란색 배경이 있습니다. Fill checkbox란의 선택을 취소하여 무색으로 만듭니다.


보기에는 좋아 보이지만 너무 작아 쉽게 tap 할 수 없어 보이므로 그 위에 40 포인트 스퀘어를 그리도록 하겠습니다.


(이제 왜 제가 스크린 샷에 파란색 윤곽선을 추가 하신지 아실 거라 이해되시죠.)


스퀘어 크기가 더 커지므로 자동으로 다른 레이어의 부모가 됩니다. 정확히 저희가 원하던 바입니다.


이름을 Mini Button Play로 변경하고 Fill을 꺼서 투명하게 만듭니다.


Next 버튼 만들기

Next 버튼은 더 작은 삼각형을 가지고 있지만 다시 새로 그려야 할 필요는 없습니다.


Play 버튼에서 두 개의 '마스크'레이어를 선택합니다...

...  ⌘D를 사용하여 복사합니다.

그들을 끌어서 다음 Next 버튼과 일렬로 만듭니다.

그런 다음 오른쪽 '마스크'레이어를 선택하고 오른쪽으로 드래그하여 위치를 조정합니다.


기억할 점 : 클릭할 때 키를 누른 상태에서 '마스크'레이어 만 선택하고 내용 / 자식은 선택하지 않도록 주의하세요.

밑부분에도 동일한 작업을 수행 한 다음 모든 항목을 선택하고 복사하여 두 번째 삼각형을 만듭니다.

벌써 꽤 많은 레이어들이 만들어졌습니다. 프로토 타입에 이 버튼들을 실제로 사용하지는 않겠지 만 모든 (8 개) 레이어를 선택하고 ⌘↩ 를 입력하여 부모 레이어에 넣으면 좀 더 정리할 수 있습니다.

오른쪽 클릭 메뉴에서 'Add Parent'를 선택하십시오.

... Mini Button Next라는 이름을 붙였습니다.

Pause 버튼

Pause 버튼은 쉽습니다. 두 개의 직사각형에 약간의 경계 반경이 있습니다.


Play 버튼과 마찬가지로 상단에 사각형을 그려줌으로써 더 큰 영역을 만듭니다. 그리고 Mini Button Pause라는 이름을 지정합니다.

트랙 이름

노래 제목에 쓰일 기본 글꼴은 SF UI Text (기본 크기는 16 포인트)입니다.


앨범 아트

Now Playing 화면에서 Mini Player로 전환할 때 큰 앨범 커버가 축소됩니다. 그렇기 때문에 앨범 아트가 Mini Player에는 필요하지 않습니다, 그러나 디자인에서 드로잉함으로써 코드에서 올바른 위치와 그림자 값을 갖게 됩니다.


앨범 아트 이미지는 48 포인트 정사각형이며 테두리 반경은 3 포인트입니다. 단순히 기본 색상으로 레이어를 그릴 수 있습니다. (그리고 어차피 나중에는 숨길 것입니다.)


그림자 값은  검은색 30% 이어야 하며, y-offset은 3포인트이고 blur는 10포인트입니다.


레이어의 이름을 Mini Album Cover로 지정합니다.


Mini Player의 배경

Mini Player를 탭 하면 색이 바뀌기 때문에 배경을 별도의 레이어로 만듭니다.


배경은 375 x 64 포인트, 색은 50% 불투명 한 매우 가벼운 흰색에 가까운 # F6F6F6입니다.


이름은 Mini Player Background로 지정하십시오.


Mini Player Background는 다른 레이어의 부모가 되었을 가능성이 높으므로 레이어 목록에서 해당 하위 항목을 선택하고 다시 드래그하는 것이 가장 좋습니다.


'Mini Player'부모 레이어

이제 모든 레이어를 선택하고 ⌘↩ 'Add Parent'를 수행 한 다음 새 레이어 레이어 이름을 Mini Player로 지정할 수 있습니다.


Target 설정

코드에서 작업할 레이어의 대상을 target 설정해야 합니다. 오른쪽에 있는 작은 원을 클릭하여 다음 레이어 타깃을 지정하세요.

Mini Player

Mini Album Cover

Mini Button Play

Mini Button Pause

Mini Button Background


이제 레이어 목록이 다음과 같이 보입니다:

모두 설정이 되었다면. 템플릿을 더 이상 필요로 하지 않으므로 마우스 오른쪽 버튼으로 클릭하고 '숨기기'(⌘;)를 선택하여 Mini player.png를 숨기도록 합니다.


그리고 또한 아트 보드 자체의 (기본) 흰색 배경이 필요하지 않으므로 불투명도를 0%로 설정합니다.

브라우저에서 오픈  -  Framer에서 오픈




18. Code에서 Mini player 조정하기

지금 재생 중 화면과 미니 플레이어 간 전환 방법

자, 트릭이 하나 있습니다.


Mini Player는 Now Playing 스크린 안에 언제나 있습니다, 그냥 Now Playing을 숨기는 거죠, 밑에 그림처럼요.

미니 플레이어가 지금 재생 중 화면에 숨겨져 있고 지금 재생 중 화면이 화면에서 완전히 사라지지 않습니다.


이미 말했다시피 앨범 커버는 '큰'플레이어와 '작은'플레이어 사이를 전환할 때 크기와 위치를 변경하는 별도의 레이어입니다.


Mini Player 배치

Now_Playing의 ScrollComponent 안에 Mini_Player를 놓고 y를 0으로 변경하여 맨 위에 놓습니다.

Mini_Player.props =
 parent: scroll_now_playing.content
 y: 0


Mini Player가 Now Playing 화면의 ScrollComponent에 안에 배치됨

Blur 효과 추가

Blur 효과는 CSS 필터이며 다른 CSS 속성과 마찬가지로 레이어의 style 속성에 설정합니다.


backdrop-filter는 아직 표준화되지 않았으며 WebKit에서만 작동하므로 앞에 -webkit을 붙여줍니다:

style:
     "-webkit-backdrop-filter": "blur(50px)"

(반경 50 픽셀의 배경에 Gaussian Blur를 설정하고 있습니다.)


그러나 실제로 camelCase로도 작성할 수도 있습니다:

Mini_Player.props =
     parent: scroll_now_playing.content
     y: 0
     style:
         webkitBackdropFilter: "blur(50px)"


Chrome 참고 사항 :

Chrome에서 필터를 사용하려면 브라우저의 '실험용 웹 플랫폼 기능'플래그를 활성화해야 합니다. 다음은 플래그 화면에 대한 링크입니다.

chrome://flags/#enable-experimental-web-platform-features


Chrome은 -webkit 프리픽스 없이 CSS 속성을 작성하기를 원합니다. 하지만 물론 둘 다 작성할 수 있습니다.

Mini_Player.props =
     parent: scroll_now_playing.content
     y: 0
     style:
         webkitBackdropFilter: "blur(50px)"         # Safari 용
         backdropFilter: "blur(50px)"                      # Chrome 용


Play 및 Pause 버튼의 위치 지정

이제 버튼을 재 정렬해야 합니다. Play 버튼은 처음에는 Puase 버튼이 있는 자리에 표시되어야 합니다.


먼저 Mini_Button_PlayMini_Button_Pause와 같은 가로 위치를 지정합니다...

Mini_Button_Play.x = Mini_Button_Pause.x


... 그러고 나서 Mini_Button_Pause를 숨 깁니다.

Mini_Button_Pause.visible = no


재생 버튼이 올바른 위치에 있고 일시 중지 버튼이 숨겨져 있다


Play 및 Pause 버튼을 탭에 반응시키기

Audio 모듈의 플레이어 객체에 다음과 같은 (표준 HTML5 오디오) 기능을 사용하여 음악을 play() 및 pause()에 사용할 수도 있습니다.

Mini_Button_Play.onTap ->
     audio.player.play()

Mini_Button_Pause.onTap ->
     audio.player.pause()
     audio.controls.showPlay()

(물론 showPlay()가 모든 것이 작동하도록 트리거 되어야 합니다.)


이제 Audio Player의 controls.showPause() controls.showPlay() 함수에서 이러한 버튼을 표시하거나 사라지게 할 것입니다. 'Audio player' fold로 돌아가서 다음과 같이 표시 여부를 변경하는 라인을 추가하세요.

# When «Play» is tapped
audio.controls.showPause = ->
     @image = $.Button_Pause.image
     $.Album_Cover.animate "playing"
 
     Mini_Button_Play.visible = no
     Mini_Button_Pause.visible = yes

# When «Pause» is tapped
audio.controls.showPlay = ->
     @image = $.Button_Play.image
     $.Album_Cover.animate "paused"
 
     Mini_Button_Play.visible = yes
     Mini_Button_Pause.visible = no

이 작업을 수행하면 모든 버튼이 동시에 변경됩니다 Play 또는 Pause 버튼이 (크기에 상관없이) 탭에 의해 독립적으로 진행됩니다.


브라우저에서 오픈  -  Framer에서 오픈



19. 미니 플레이어 앨범 표지의 작은 버전

우리는 이제 앨범 커버를 위한 추가 상태를 만들 것입니다. Mini Player 에 들어갈 작고 정밀한 앨범 카버가 배치될 것입니다.


하지만 아마 여러분도 눈치채셨다시피 음악을 재생할 때 앨범 표지가 Mini Player 뒤에 있습니다. 그것은 placeBefore()로 쉽게 고칠 수 있습니다.

$.Album_Cover.placeBefore Mini_Player


이제, 새로운 State "mini"에 대해 Mini_Album_Cover의 속성을 복사할 수 있습니다. 이 앨범은 디자인에서 만든 작은 앨범 표지입니다.  frame, shadowColor, shadowY 및 shadowBlur를 사용합니다...

$.Album_Cover.states.mini =
     frame: Mini_Album_Cover.frame
     shadowColor: Mini_Album_Cover.shadowColor
     shadowY: Mini_Album_Cover.shadowY
     shadowBlur: Mini_Album_Cover.shadowBlur
     shadowSpread: Mini_Album_Cover.shadowSpread
     scale: Mini_Album_Cover.scale

... 그리고 shadowSpreadscale 또한 설정합니다. 왜냐하면 이러한 속성은 다른 State에 의해 변경되었기 때문입니다. ($. Album_Cover의 기본값은 shadowSpread0이고 scale1입니다.)


그리고, Mini_Album_Cover가 보이면 안 되고 속성만 복사를 해야 하기에 숨기도록 하겠습니다.

Mini_Album_Cover.visible = no


이제 테스트해보면, 앨범 커버에서 탭을 사용하여 새로운 "mini"상태로 애니메이션을 적용할 수 있습니다.

$.Album_Cover.onTap ->
     $.Album_Cover.animate "mini"


브라우저에서 오픈  -  Framer에서 오픈




20. Now Playing 화면에서 Mini Player로 전환

지금까지는 다 괜찮아 보입니다, 그럼 이제 Mini Player를 숨기도록 하겠습니다.

Mini_Player.opacity = 0

(애니메이션을 사용하기에 opacity를 사용해야 합니다, visible을 사용 하게되면 애니메이션 시 보이지 않기 때문입니다.)


나중에 Mini Player가 언제 사용되는지  곧 이유를 알게 되실 것입니다. 그렇기에 먼저 miniPlayerActive라는 변수를 생성합니다. 지금은 우선 'no'라고 설정합니다.

miniPlayerActive = no


스크롤 동작 듣기

Now Playing 스크린이 아래로 드래그가 되면  onScroll 이벤트가 실행되게 됩니다. 이 이벤트는 사용자가 위 또는 아래로 스크롤할 때마다 트리거 됩니다.

scroll_now_playing.onScroll ->

원래 앱에서 사용자는 화면 상단에서 Now Playing 화면을 100 포인트로 드래그하면 Mini Player로 전환됩니다.


그런데 벌써 Now Playing 화면은 위에 28 포인트가 배치되어 있으므로 사용자가 72포인트를 스크롤할 때 애니메이션이 시작됩니다.


그러나 실제로는 콘텐츠의 가장자리를 넘어서 스크롤을 하고 있기 때문에 스크롤 값인 scrollYnegative 값 또한 확인합니다.


(이벤트 핸들러에 print maxi_player.scrollY을 넣으면 테스트해볼 수 있습니다.)

scroll_now_playing.onScroll ->
     if scroll_now_playing.scrollY < -72


스크롤 동작 고정

이제 사용자가 이를 멀리 스크롤하여 전환을 시작했지만, 몇 가지 문제가 있습니다.

Now Playing 화면은 '아래로 스크롤'상태가 됩니다.

사용자가 애니메이션을 적용하는 동안 훨씬 더 아래로 스크롤할 수 있습니다.

이럴 때는 ScrollComponent를 초기 상태로 신속하게 reset 함으로 문제를 해결할 수 있습니다.


ScrollComponent를 리셋하는 방법입니다:


사용자가 아래로 스크롤할 때 반동으로 다시 올라오는 순간이 있는데요, 저희는 그순간 에니매이션이 일어나지 않도록 만들것입니다.


또한 추가 스크롤을 막음으로써 알려진 시작 지점에서 전환을 시작할 수 있습니다.


자그럼, 단계별로 이야기해보겠습니다:

# Make the Scroll Component jump to its content’s position
scroll_now_playing.y = scroll_now_playing.content.y + 28

(여기서는 scrollY를 사용하지 않지만 스크롤할 때 증가하는 content 레이어의 y 위치를 주의해야 합니다.)


따라서 사용자가 빠른 스와이프를 통해  몇 포인트를 더 아래로 스크롤할 수 있게 되더라 ScrollComponent는 언제나 같은 위치에서 멈추게 됩니다.


이제 콘텐츠를 맨 위로 이동합니다.

#...content을 초기 위치로 리셋한다
scroll_now_playing.scrollToPoint
     y: 0
     no

scrollToPoint() 함수는  'animate'인수를 no로 설정하면 애니메이션 없이 즉각적으로 발생합니다.


그러면 더 이상의 스크롤을 방지할 수 있죠:

# … and block any more movement
scroll_now_playing.speedY = 0

수직 스크롤 속도, speedY는 상대 값입니다. 1 (기본값)으로 설정하면 콘텐츠가 사용자 손가락을 부지런히 따라갈 것이고 0.5는 절반 속도로 움직이고 0은 전혀 움직이지 않을 것입니다.


(또는 scrollVertical를 사용 중지할 수 있습니다.)


지금까지 한이야기를 모으면 다음과 같이 보입니다:

scroll_now_playing.onScroll ->
 
     if scroll_now_playing.scrollY < -72    # 100포인트 빼기 28포인트
 
         # Component를  내용의 위치로 이동시킨다
         scroll_now_playing.y=scroll_now_playing.content.y+28
 
         #... 내용을 초기 위치로 리셋한다
         scroll_now_playing.scrollToPoint
             y: 0
             no
 
         #... 더 이상의 움직임을 차단한다
         scroll_now_playing.speedY = 0

직접 트라이해보세요.  원하는 만큼 위아래로 스크롤할 수 있지만 밑으로 당기는 순간 모든 것이 고정됩니다.


72 포인트 정도 스크롤을 내리면 스크롤이 차단 된다

자 이제 마음에 준비를 해야 됩니다. 왜냐면 동시에 9 개의 애니메이션을 다른 타이밍으로 실행하게 될꺼니까요.


애니메이션의 첫 번째 세트

여섯 번째 애니메이션의 첫 번째 세트가 즉시 시작되고 1/3 초 동안 실행됩니다.

# -- 첫 번째 애니메이션 세트 = 0.3 초 이상 -- #
firstSetDuration = 0.3

0.3 초 동안 이런 일이 생기게 됩니다 :

Mini Player 표시하고 (opacity)

투명 회색 오버레이 숨깁니다 (opacity)

뒷면의 Library화면 리셋하고 (scaleX, y, borderRadius)...

... For You 스크린에서도 똑같이 적용합니다

Status Bar를 검은색으로 다시 만듭니다 (invert).

Tab Bar를 위로 움직입니다 (y)


자그럼 만들어 볼까요.


Mini Player를 불러오겠습니다 : opacity 값을 설정해서 가져옵니다.

Mini_Player.animate
     opacity: 1
     options:
         time: firstSetDuration


투명한 회색 오버레이 숨겨 보겠습니다 : opacity를 0으로 만들겠습니다.

overlay.animate
     opacity: 0
     options:
         time: firstSetDuration


다음으로, scroll_libraryscroll_for_you를 화면의 맨 위로 이동하고 수평 스케일을 리셋하고 border radius 값을 제거합니다.

scroll_library.animate
     scaleX: 1
     y: 0
     borderRadius: 0
     options:
         time: firstSetDuration
 
scroll_for_you.animate
     scaleX: 1
     y: 0
     borderRadius: 0
     options:
         time: firstSetDuration

(그중 하나는 실제로 표시되지 않지만 어쨌든 애니메이션으로 만들 수 있습니다.)


이전에 우리는 Status Bar을 흰색으로 invert 했습니다. 이제 Status Bar 기본값을 : 0으로 주도록 합니다.

$.Status_Bar.animate
     invert: 0
     options:
         time: firstSetDuration


Tab bar바닥을 maxY로 설정하면 화면 아래쪽으로 슬라이드 됩니다.

$.Tabs.animate
     maxY: Screen.height
     options:
         time: firstSetDuration

변수인 firstSetDuration를 사용해서 애니메이션 재생시간을 설정했기 때문에, 애니메이션 설정을 느리게 만들어 보여줄 수 있습니다


마치 3 초의 지속 시간으로 움직이는 것처럼...

# -- 첫 번째 애니메이션 세트 = 0.3 초 이상 -- #
firstSetDuration = 0.3 * 10


... 밑에 GIF를 보시죠 :

브라우저에서 오픈  -  Framer에서 오픈



두 번째 애니메이션 세트

다음 두 애니메이션은 즉시 시작되지만 느려지고 미묘한 바운스가 발생하게 됩니다.

# -- 두 번째 애니메이션 세트 = 0.7 초 이상 -- #
secondSetDuration = 0.7


0.7 초 동안 이런 일이 생기게 됩니다 :

Now Playing 화면 (Mini Player를 포함) 전체를 아래쪽으로 이동합니다 (y, borderRadius)

앨범 커버를 Mini Player 사이즈에 맞춥니다. (State 애니메이션)


Mini Player가 여전히 표시되어야 하기 때문에 모든 것을 애니메이션으로 표시하고 싶지 않으므로 Now Playing 화면의 상단을 Tab Bar의 높이 + Mini Player의 높이로 이동합니다.

scroll_now_playing.animate
     y: Screen.height - $.Tabs.height - Mini_Player.height + 1
    borderRadius:
         topLeft: 0
         topRight: 0
     options:
         time: secondSetDuration
         curve: Spring(damping: 0.77)

(추가 1포인트를 넣어 작은 틈이 생기지 않게 해줍니다)


Mini Player에 둥근 모서리가 생기지 않게 border radius 없애도록 하겠습니다.


추가된 Spring 커브는 기본값 인 0.5 대신 'damping' 0.77로 값을 줍니다.


또한. Album_Cover를 "mini"상태로 변할 때와 동일한 값을 주도록 합니다. 합니다.

$.Album_Cover.animate "mini",
     time: secondSetDuration
     curve: Spring(damping: 0.77)


"mini"를 만들 때처럼 '애니메이션 옵션'이 포함되지 않았지만 ("play"및 "paused"에서 한 것처럼) 원하는 duration 값과 curver값을 여기에 추가할 수 있습니다.


다음은 지금까지 넣은 8가지 애니메이션의 속도의 10 분의 1로 만든 GIF입니다:

브라우저에서 오픈  -  Framer에서 오픈



마지막 애니메이션 : Now Playing 화면 숨기기

마지막 애니메이션은 delay가 되어 0.5 초 후에 시작됩니다.  왜냐하면 스크린이 페이드 아웃되기 전에 Mini Player가 나타나야 되기 때문입니다.

$.Now_Playing.animate
     opacity: 0
     options:
         delay: 0.5
         time: 0.5

(여기에서는 ScrollComponent 내부에 있는 $. Now_Playing 스케치 레이어의 opacity를 애니메이션으로 처리합니다.)

그 결과 이렇게 보입니다:


브라우저에서 오픈  -  Framer에서 오픈

이제 Mini Player가 애니메이션에서 나왔기 때문에 다음과 같은 라인을 적을 수 있게 되었습니다.

# Mini Player가 이제 작동합니다
miniPlayerActive = yes


애니메이션 타이밍을 비교하고 싶다면 밑에 원래 앱의 10 배 속도 느린 동영상이 있습니다.

원래 앱의 두 플레이어 간의 전환이 속도의 1/10로 이루어집니다.




21. Mini Player에서 Now Playing으로 전환

이제 어떻게 다시 Now Playing으로 돌아가는 방법도 찾아봐야겠죠. 사용자가 Mini Player를 탭 하면 Now Playing 화면으로 나오도록 만들어 보겠습니다.


Mini Player의 배경 레이어에서 onTap을 설정합니다

Mini_Player_Background.onTap ->

왜 Background를 설정하였냐고요? 이 방법을 사용하면 Play와 Pause 버튼을 계속 사용할 수 있기 때문이죠.


Tab 피드백

거의 잘눈에 띄지 않지만 Mini Player를 탭 할 때 페이지가 슬라이드 되어 올라오기 전 피드백으로 약간 더 어둡게 됩니다.


약간 어두운 회색의 "rgba (228,228,228,0.5)"(50 % 투명도가 있고요)로 애니메이션을 적용하기 전에 originalcolorBGMiniPlayer라는 변수에 원본 색상을 저장합니다:


애니메이션은 초당 5 분의 1로 매우 빠릅니다.

# 첫 번째 먼저 오리지널 색깔을 저장한다
originalColorBGMiniPlayer = Mini_Player_Background.backgroundColor.color

# … 그러고 나서 약간 더 어둡게 만든다
Mini_Player_Background.animate
     backgroundColor: "rgba(228,228,228,0.5)"
     options:
         time: 0.2
Tab 피드백

짧은 delay 후 애니메이션 시작

실제 전환은 1/3 초 후에 시작됩니다. 그래서 우리는 모든 애니메이션을 Utils.delay() 블록에 넣을 것입니다.

# 약간의 delay후에 애니메이션이 시작된다
Utils.delay 0.3, ->


그러나 애니메이션을 적용하기 전에 Mini_Player_Background에 다시 생각한 색상을 적용합니다.

# Mini Player’s color를 리셋한다
Mini_Player_Background.backgroundColor = originalColorBGMiniPlayer


... 그리고 우리는 이미 Now Playing 화면을 볼 수 있게 합니다 :

# fade in 할 필요가 없도록 전체 화면을 보여준다,
$.Now_Playing.opacity = 1

어차피 Mini Player는 밑에 있기 때문에, 슬라이드가 움직이는 동안 애니메이션을 적용하지 않아도 됩니다.



첫 번째 애니메이션 세트

자, 이제 애니메이션을 보도록 하겠습니다. 빠른 설정 (1/3 초)과 느린 설정 (0.5 초)이 있는데요. 먼저 빠른 설정을 설정하도록 하겠습니다 :

# - 애니메이션의 첫 번째 세트, 1/3 초 이상 - #
firstSetDuration = 0.3


이제 Mini Player를 숨기도록 하겠습니다...

# Mini Player가 사라진다
Mini_Player.animate
     opacity: 0
     options:
         time: firstSetDuration


... 그리고 같은 0.3 초 안에 Tab Bar를 밑으로 이동합니다 :

# Tab Bar를 밑으로 이동
$.Tabs.animate
     y: Screen.height
     options:
         time: firstSetDuration

눈이 잘 띄지 않는 작은  움직임이 들어간 애니메이션입니다 (Now Playing 스크린의 애니메이션과 비교해서)


여기 GIF로 어떻게 움직이는지 확인해 보겠습니다 (역시나 1/10의 스피드로)

브라우저에서 오픈  -  Framer에서 오픈


두 번째 애니메이션 세트

두 번째 세트 또한 첫 번째 애니메이션과 동시에 시작되지만이 애니메이션 자체는 더 느리게 실행됩니다: 0.5초로. 첫 번째 세트와 마찬가지로 기본 Bezier.ease을 사용합니다.

#두 번째 애니메이션 세트 : 0.5초
secondSetDuration = 0.5


가장 눈에 띄는 애니메이션인 Now Playing 화면이 다시 올라가는 순간입니다:

# Scroll Component 위쪽으로 애니메이션 적용
scroll_now_playing.animate
     y: 28
     borderRadius:
         topLeft: 8
         topRight: 8
     options:
         time: secondSetDuration

(상단 모서리의 radius도 복원합니다.)


동시에 앨범 커버를 큰 사이즈로 되돌리고 싶지만 음악이 재생되는지 확인해야 올바른 상태로 animate 할 수 있겠죠.


오디오 플레이어의 player 개체는 HTML5 audio요소에 대한 액세스 권한을 제공하므로이 요소의 properties를 확인할 수 있습니다. 그중 하나가 일시 중지되었으며 음악이 재생되지 않을 때 'true'가 됩니다.

if audio.player.paused
     $.Album_Cover.animate "paused",
         time: secondSetDuration
else
     $.Album_Cover.animate "playing",
         time: secondSetDuration
         curve: Bezier.ease

 이런 애니메이션을 제공함으로써 states을 만들 때 설정된 time을 오버라이드 하게 됩니다.


"playing"에 포함된 spring curve 효과를 원지 않기 때문에, Bezier.ease 커브로 오버라이드 합니다.


브라우저에서 오픈  -  Framer에서 오픈


이제 남은 것은 Now Playing 화면 밑에 있는 백그라운드에서 일어나는 일들입니다 :

투명 회색 오버레이가 다시 fade in 해야 합니다.

뒷면에 있는 화면도 카드가 되어야 합니다.

Status Bar가 다시 흰색이 되어야 합니다.


회색 오버레이 :

# 투명한 회색 오버레이 표시
overlay.animate
     opacity: 1
     options:
         time: secondSetDuration


Library와 For You 화면에 대해서는 :

# 뒤쪽의 화면 축소 및 이동
scroll_library.animate
     scaleX: 0.96
     y: 20
     borderRadius: 8
     options:
         time: secondSetDuration

scroll_for_you.animate
     scaleX: 0.96
     y: 20
     borderRadius: 8
     options:
         time: secondSetDuration

(다시 한번 말씀 드자면, 이 두 화면중 하나만 표시됩니다.)


Status Bar :

# Status Bar 하얗게 만들기
$.Status_Bar.animate
     invert: 100
     options:
         time: secondSetDuration


모든 설정이 끝났습니다. 이제 Now Playing 화면을 다시 스크롤할 수 있게 만듭니다.

scroll_now_playing.speedY = 1


그리고 미니 플레이어가 활성화되어 있지 않다는 것을 등록합니다.

miniPlayerActive = no
브라우저에서 오픈  -  Framer에서 오픈



Mini Player가 활성화되어있을 때 앨범 표지 애니메이션 방지하기

아마 여러분들은 지금까지 왜 miniPlayerActive 변수가 필요한지 궁금하셨을 것입니다.


자 한번 Mini Player에서 재생 버튼을 눌러보겠습니다.

Mini Player에 있을 때는 당연히 이러한 애니메이션이 발생하지 않아야겠죠.


# Audio player fold로 돌아가 보도록 하겠습니다


지금까지는  오디오 플레이어의 showPause() 및 showPlay() 함수는 다음과 같았습니다.

# When «Play» is tapped
audio.controls.showPause = ->
     @image = $.Button_Pause.image
 
     $.Album_Cover.animate "playing"
 
     Mini_Button_Play.visible = no
     Mini_Button_Pause.visible = yes

(showPlay() 함수에는 비슷한 코드가 포함됩니다.)


if 행을 사용하여 miniPlayerActive를 확인하고 활성 상태가 아닌 경우 (no)에만 $. Album_Cover의 상태를 변경하도록 합니다.

# When «Play» is tapped
audio.controls.showPause = ->
     @image = $.Button_Pause.image
 
     if miniPlayerActive is no
         $.Album_Cover.animate "playing"
 
     Mini_Button_Play.visible = no
     Mini_Button_Pause.visible = yes

(showPlay() 함수에도 같은 줄을 추가하세요.)


브라우저에서 오픈  -  Framer에서 오픈


완성되었습니다!


이 튜토리얼이 여러분께 도움이 되셨길 진심으로 바랍니다.


만약 도움이 되셨다면, 제가 쓴 Framer Book 도 확인해보세요. 비슷한 두 개의 앱에 관련된 튜토리얼이 방대한 양의 Framer 코드와 함께 책 안에 들어있습니다.

https://framerbook.com/

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari