สร้าง Counter บน Touch Bar

หลังจากวุ่นวายกับ TouchBar มาเกือบสัปดาห์ รวมถึงนั่งหงุดหงิดกับ Bug ที่ไม่รู้ว่าใครผิดระหว่าง SDK หรือตัวผมเอง เลยตั้งใจว่าจะเขียนเรื่องเกี่ยวกับ TouchBar อีกแค่สองอย่างคือบทความนี้ และอีกอันที่จะดึงข้อมูลจาก Dribbble มาแสดงใน Scrubber หลังจากนั้นผมจะไปหนีไปเขียนเรื่อง React Fiber แทนละ

จากครั้งก่อนผมลองเขียน Hello, TouchBar ที่เป็นแอพฯ ง่ายเอาข้อความไปแสดงบน TouchBar รอบนี้ผมจะใส่พวกปุ่มลงไปหน่อย และทำ Nested TouchBarโดยให้ Controller อีกตัวเป็นคนจัดการ TouchBar ของตัวเองด้วย

สำหรับครั้งที่แล้วไปตามอ่านได้

Counter Touch Bar

อย่างที่บอกไปครั้งที่แล้วผมสร้างโปรเจคชื่อ CounterTouchBar เพราะตั้งใจจะลองทำ Counter แบบง่ายๆ เลย งั้นเรามาดูหน้าตาคร่าวๆ ของแอพฯ เราก่อน

  1. Window — คือของที่เราทำไว้ครั้งที่แล้ว จะแสดงคำว่า Hello, TouchBar… แต่ที่เพิ่มว่าคือ Other Item
  2. View Controller ซึ่งเป็น Content View Controller ของ Window จะมี TouchBar อีกอันเป็นของตัวเอง ซึ่งจะมีปุ่ม 2 ปุ่มกับ Label 1 อัน เพื่อทำเป็น Counter

Other Items — ตัว TouchBar เองนั้นออกแบบมาให้สามารถ Nested หรือ Composed TouchBar ตัวอื่นได้ โดยใช้ NSTouchBarItem ที่เรียกว่า otherItemsProxy ถ้าหากมี otherItemsProxy อยู่ใน TouchBar ตัวระบบจะมองหาว่าใน Respond Chain ถัดไปนั้นมีถัดไปนั้นมี TouchBar อยู่มั้ย ถ้ามีจะเอามาใส่ตรงนั้นให้ แต่ถ้าไม่มีระบบจะเอา TouchBar ตัวต่อไปมาใส่แทนเลย

(พูดง่ายๆ คือถ้าไม่ใส่ otherItemsProxy ตัว Hello, TouchBar ของ Window จะโดน Replace ด้วย TouchBar ของ View Controller เลยนั้นเอง)

รายละเอียดเพิ่มเติมอ่านได้จากลิ้งค์ได้ล่าง

เริ่มแก้โค็ดอันเก่าของเราโดยการเพิ่ม .otherItemProxy ไปใน WindowController.swift

จากนั้นไปที่ ViewController.swift ซึ่งผมตั้งให้ตัวนี้เป็นตัวดูแล CounterTouchBar

1 — สร้าง NSTouchBarCustomizationIdentifier และ NSTouchBarItemIdentifier

อย่างที่บอกไปครั้งที่แล้ว TouchBar แต่ละตัวต้องมี Identifier เป็นของตัวเอง เช่นเดียวกับ TouchBar Item แต่ละตัวก็ต้องมีเป็นของตัวเองเช่นกัน

2 — Override makeTouchBar()

จำครั้งที่แล้วได้มั้ยครับ ถ้าจะเพิ่ม TouchBar มีเงื่อนไข 3 อย่างคือ NSResponder, NSTouchBarProvider, makeTouchBar() ซึ่ง ViewController เข้าเงื่อนไข 2 อย่างแรกแล้ว เราเลยทำอย่างที่ 3 คือเขียน makeTouchBar()

  • TouchBar ที่ผมสร้างมี Item อยู่ 3 อย่างคือปุ่ม เพิ่ม, ตัวแสดงตัวเลข, ปุ่มลบ
  • ผมใส่ TouchBar Delegate เป็น self เพราะงั้นต้องเขียนฟังก์ชั่นใน Protocol ของ NSTouchBarProvider เพื่อให้สามารถทำงานได้

3 — เขียนฟังก์ชั่นใน NSTouchBarProvider

หน้าในการสร้าง TouchBarItem เป็นของ Delegate เราจึงจำเป็นต้องเขียนฟังก์ชั่นในการสร้าง TouchBarItem ตาม NSTouchBarProvider

แต่ก่อนอื่น เนื่องจากผมได้ คิด วิเคราะห์ แยกแยะ ผมเลยจะเขียนฟังก์ชั่นและตัวแปรเพื่อใช้สำหรับ Counter ทำงานได้ก่อน

  1. currentCounter สำหรับเก็บค่า Counter , เพิ่ม dynamic เพื่อให้สามารถ binding ได้
  2. Handler ฟังก์ชั่นไว้สำหรับเพิ่มลดจำนวน Counter

หลังจากได้ฟังก์ชั่นเพิ่ม-ลดแล้ว ก็มาสร้าง TouchBarItem ต่อ

สังเกตบรรทัดที่ 29 ผมได้ทำการ bind stringValue ของ Label เข้ากับ currentCounter ที่ผมสร้างไว้ก่อนหน้านี้ ทำให้เมื่อค่า currentCounter มีการเปลี่ยนแปลงค่า Label ก็จะเปลี่ยนแปลงไปด้วย เมื่อรันโปรแกรมแล้วเปิด TouchBar Simulator ดูจะได้ผลลัพธ์ประมาณนี้

ถ้าใครทำทุกอย่างถูกต้องแล้ว แต่ Counter ไม่ขึ้นให้ลงไปดูล่างสุด

4. ใส่ Counter ให้กับ View ใน ViewController

แค่ลดๆ เพิ่มๆ ใน TouchBar ยังไม่พอ ผมจะใส่ตัวเลขเข้าไปในแอพฯ เพิ่มด้วย เวลากดในตัวเลขในแอพฯ จะได้เปลี่ยนไปด้วย

จริงๆ ก็ง่ายนิดเดียวนะ ใส่ Label เข้าไปใน View ของ ViewController ใน IB แล้วก็ bind มันซะก็จบละ

ลองรันดูก็จะได้

จบแล้ว… สำหรับ Source code ดูได้ใน Github ใน branch counter

รอบหน้าผมจะลองเรียกรูปจาก Dribbble API แล้วเอามาโชว์ใน NSScrubber

TouchBar ไม่ขึ้น, ลาก Label มาใส่แล้ว TouchBar ของ ViewController หายไป

ถ้าเกิด TouchBar ของ ViewController ที่เราสร้างไม่แสดง ซึ่งผมก็เจอปัญหานี้เหมือนกัน โดยกรณีที่ผมเจอคือ

  • makeTouchBar แล้วใช้ได้
  • ลาก Label มาใส่ View ใน IB แล้ว TouchBar หายไป
  • ลบ Label ออก TouchBar มันไม่กลับมา

หรือบางครั้งเขียนถูกหมดแล้ว TouchBar ที่สร้างก็ไม่โผล่หัวมาให้เห็นเลย ซึ่งผมก็ไม่รู้ว่ากูเองที่เขียนผิดหรือมันเป็น Bug

วิธีที่ผมแก้คือผมลาก TableView มาใส่ใน View แล้วตอนเปิดแอพฯ ให้ไปกดโฟกัสที่ TableView ทีนึง มันก็จะใช้งานได้ แล้วค่อย Hidden TableView ทิ้งไป 
(อย่าลบ ถ้าลบ TouchBar แม่งก็หายไปอีก) ตามรูป