Hello, TouchBar — ลองเขียนแอพฯ ที่มี Touch Bar กัน

Jirat Ki.
3 min readOct 30, 2016

--

วันก่อนเขียนวิธีเปิดใช้ Touch Bar Simulator เพื่อที่จะได้ลองเล่นสัมผัสแห่งอัจฉริยะ

หลังจากวันนั้นก็ใช้เวลาทั้งในงมอยู่กับ Touch Bar API และ Sample Code ที่แอปเปิลปล่อยมาให้ — ตอนแรกผมตั้งใจว่าจะเขียนแบบถึงทำพวกกดปุ่มเล่นเสียง มี Controller สวยงามบลาๆ แต่เหมือนจะมีปัญหากับตัว Touch Bar API หรือ Simulator อันไหนสักอย่าง ที่ทำให้ Code ที่เขียนเหมือนกัน ดันรันออกมาไม่เคยจะเหมือนกัน รันครั้งนึงได้ Item โผล่มา กด Undo, Redo ไปมาแล้วมันก็หายไป ปิด Restart เครื่องแล้วก็โผล่มาอีก ให้ความรู้สึกเหมือนแบบ “เหี้ย มันทำงานได้ไงวะ” กับ “เหี้ย ทำไมทำงานไม่ได้วะ” ในเวลาเดียวกัน

เพราะงั้นหลังจากที่ผมโดนธาติไฟเข้าแทรกเป็นที่เรียบร้อยแล้ว บทความนี้ผมจะพาเขียนแค่ “Hello, World” เพื่อป้องกันทุกคนจากด้านมืดที่มาจาก Bug ของ Touch Bar SDK :P

เริ่มจาก Touch Bar API 101

เริ่มแรกต้องอ่านเอกสารของแอปเปิลให้หมดทุกตัวอักษรเพื่อความเข้าใจนะครับ :D

แต่ถ้าขี้เกียจผมสรุปแบบมั่วๆ ให้ คือ Touch Bar จะประกอบด้วย Touch Bar และ Touch Bar Item สร้างสองอันนี้ก็ได้ Touch Bar ของเราเองแล้ว แต่…

แล้วเราจะไปให้สร้างตอนไหน และสร้างให้ใคร… ในเอกสารบอกว่า ถ้าต้องการสร้าง TouchBar ให้แอพของเรา จะมีเงื่อนไข 3 อย่างนี้

To provide a bar in your app, define it in an object that meets three requirements. The object that defines the bar must:- Be a responder (an instance of an NSResponder subclass) that is present within a responder chain at runtime- Conform to the NSTouchBarProvider protocol- Implement the makeTouchBar() method within that protocol

1. ต้องสืบทอดมาจาก NSResponder

คือจะบอกว่าสารพัดของที่เราใช้กันอยู่เนี่ย ไม่ว่าจะเป็น ViewController, View, Button, Textfield บลาๆ เกือบทั้งหมด Inherit มาจาก NSResponder อยู่แล้ว (ยกเว้นบางคนที่มีแนวทางเป็นของตัวเองสร้างของแปลกมาใช้เองก็อีกเรื่องนึง) เพราะงั้นเราสร้าง TouchBar ให้ได้เกือบกับทุกสิ่งในแอพ

2. ต้องเป็น NSTouchBarProvider

อันนี้ยากขึ้นมาหน่อย แต่ถ้าดูจาก

จะเห็นว่าเกือบทุกอย่างมันก็เป็น NSTouchBarProvider เหมือนกัน ยกเว้นทะลึ่งอยากทำเองก็อาจต้องไปปวดหัวกับพวก KVO สักหน่อย

3. เขียนฟังก์ชั่น makeTouchBar()

โอเคอันนี้ตรงไปตรงมาก็เขียนฟังก์ชั่น makeTouchBar() ซะ…

(จริงๆ เราสามารถลาก TouchBar ใน Interface Builder ยัดใส่ใน ViewController เลยก็ได้นะ ได้เหมือนกัน แต่ผมเจอบัคแล้วขอปล่อยมันไว้ตรงนั้นแหละ เขียนในโค็ดแล้วดูสบายใจกว่า อย่างน้อยไม่โค็ดกูผิดมึงก็ผิด

ร่ายมายาวมาลองเขียนกันดีกว่า

เริ่มโปรเจค — Hello, Touch Bar

เริ่มจากสร้าง Xcode Project ขึ้นมาใหม่เป็น macOS Application (อย่าสร้าง iOS นะ มันไม่มี TouchBar) แล้วก็ตั้งชื่อแล้วแต่สะดวก ผมตั้ง CounterTouchBar เพราะต่อจะจะทำ Counter ไว้กดบวกเลขเล่นด้วย

ปล. ผมตั้ง Deployment Target เป็น 10.12.1 นะครับ ถ้าไม่ได้ตั้ง Xcode จะขึ้นเตือนแล้วใส่ Code ตรวจสอบเวอร์ชั่นให้

จากนั้นเราสร้าง TouchBar ที่ไหน? ใน AppDelegate เลยได้มั้ย? จริงๆ ก็ได้นะแต่ในเอกสารบอกว่า

“Associate the bar with your app object instead of with the app delegate, or with a window controller object instead of with the window itself…”
- https://developer.apple.com/reference/appkit/nstouchbar

เพราะงั้นผมเอาไปไว้ที่ WindowController แทนที่จะเป็น AppDelegate (จริงๆ ลอกมาจากโค้ดตัวอย่างอีกที) — งั้นจงสร้าง WindowController ขึ้นโดยสืบทอดจาก NSWindowController

ไม่ต้องสร้าง XIB นะเพราะใน Main Storyboard มี Window Controller อยู่แล้ว

จากนั้นเปิด Main.storyboard แล้วเปลี่ยน Window ให้เป็น WindowController ที่เราสร้างซะ

คลิก Window Controller แล้วเปลี่ยนขวาบนตรง Class (ผมลืมลากเส้นให้)

กลับมาที่ WindowController.swift — เริ่มจาก TouchBar ตัวละตัวต้องมี ID เป็นของตัวเองและ TouchBarItem แต่ละตัวก็ต้องมี ID ของตัวเองเช่นกัน เพราะงั้นผมจะเริ่มสร้าง Identifier สำหรับ TouchBar และ TouchBarItem ก่อน โดยใส่ไว้เป็น extension ของ NSTouchBarCustomizationIdentifier, NSTouchBarItemIdentifier เลย (ทำตาม Sample Code นั้นแหละ)

  • windowbar เป็น Identifier ของ TouchBar แต่ละตัวครับ เนื่องจากในระบบมีหลาย TouchBar และในแอพฯ ก็อาจหลาย TouchBar ด้วย
  • label ในที่นี้เป็น Identifier ที่จะไว้แสดง Hello, TouchBar นั้นเอง

จากนั้นก็มาเขียนฟังก์ชั่นสำหรับสร้าง TouchBar

  • customizationIdentifier — TouchBar Identifier ที่เราสร้างก่อนหน้านี้
  • defaultItemIdentifier — เป็น Array ของ NSItemTouchBarIdentifier เพื่อบอกว่า TouchBar นี้มี Item อะไรบ้าง ตอนนี้ใส่ไว้แค่อันเดียวคือ .label

สังเกตว่าเราใส่ Identifier ของ Item เข้าไป ไม่ได้ใส่ตัว TouchBarItem จริงๆ เข้าไป เพราะการสร้าง TouchBarItem นั้นจะเป็นหน้าที่ของ Delegate ของ TouchBar

เนื่องจากผมใส่ self ให้เป็น delegate เลยต้องเขียนฟังก์ชั่นตาม Protocol ของ NSTouchBarDelegate ดังนี้

อย่างที่บอกหน้าที่การสร้าง TouchBarItem เป็นหน้าที่ของ Deleaget เพราะงั้นจากโค็ดด้านบนจะเป็นการสร้าง TouchBarItem สำหรับ .label (ซึ่งมีอันเดียวเพราะเราใส่ไว้อันเดียวตอนสร้าง TouchBar)

จริงๆ แล้ว TouchBar API มี NSTouchBar Subclasses มาให้ใช้หลายอัน แต่ปัญหาคือมันไม่มีอันไหนที่ไว้สำหรับสร้าง Label ง่ายๆ เลย ต้องสร้าง Custom Item แล้วใส่ Label ไปเป็น View ของมันแทน (ถ้าทำใน Interface Builder มีให้นะ เป็น Custom ใส่ Label เหมือนกัน)

สำหรับ TouchBarItem แบบต่างๆ ที่แอปเปิลมีให้ดูได้ในเอกสารตรงหัวข้อ NSTouchBarItem Subclasses

ถึงตรงนี้สั่งรันแอพของเราแล้วเปิด TouchBar Simulator ขึ้นมาก็จะได้ Hello, TouchBar สีเขียวๆ ขึ้นมาแล้ว TADA!!

— วิธีเปิด TouchBar Simulator คือ cmd+shift+5

เย้ ในที่สุดเราก็ได้ Hello, TouchBar สีเขียว สวยงาม ทำไมมันถึงง่ายดายขนาดนี้นะ :)

แต่อยากที่บอกจริงๆ ผมตั้งใจเขียนไปไกลกว่านี้แต่ติดบัค ซึ่งไม่รู้ว่าบัคหรือผมทำอะไรผิด แต่นี้มันเป็นแค่ Hello, World ในโลกของความเป็นจริงมันจะมีของใน TouchBar มากมาย แล้วของใน TouchBar ก็จะเปลี่ยนไปตามบริบทต่างๆ (Context) ในแอพของเราด้วย

ดังนั้นตอนต่อไปจะเริ่มทำ Nested & Composed Touchbar กัน โดยให้ ViewController มี TouchBar เป็นของตัวเองด้วย (ไอ้นี้แหละที่งมด่ามันอยู่ทั้งวันเพราะมันได้บ้างไม่ได้บ้าง) โดยสิ่งที่เราจะทำคือเพิ่ม Counter :|

โค็ดสามารถดูได้ใน Github ด้านล่าง

--

--