26 April 2015

[Android Code] รู้จักกับ Palette API ลูกเล่นใหม่เพื่อเพิ่มสีสันให้กับแอปของคุณ



        Palette นั้นเป็น API ที่ทาง Google ได้ปล่อยออกมาเพื่อรองรับกับ Material Design ใน Android 5.0 Lollipop และได้ทำเป็น Support Library เพื่อให้สามารถใช้งานกับแอนดรอยด์เวอร์ชันเก่าๆได้ด้วย จึงขอหยิบมาพูดถึงซักหน่อย

       
        โดยเจ้า Palette เนี่ย จะทำการแยกสีของภาพนั้นๆออกมาเพื่อบอกว่าภาพนั้นๆมีสีเป็นโทนอะไรบ้าง เพื่อให้ผู้ที่หลงเข้ามาอ่านสามารถนำสีดังกล่าวไปใช้กับ UI ในส่วนอื่นๆเพื่อให้เหมาะสมกับภาพนั้นๆ


        จากภาพข้างบนนี้จะเห็นว่าในแต่ละเพลงนั้นจะมีปกเพลงแตกต่างกันไป และรายละเอียดเกี่ยวกับเพลงนั้นๆก็จะมีสีพื้นหลังที่แตกต่างกันไปตามสีบนปกเพลงด้วย

        การทำแบบนี้ได้ก็มาจากการคำนวนค่าสีที่อยู่บนภาพนั่นแหละ ซึ่ง Palette API ก็เกิดมาเพื่องานนี้นี่เอง

       โดย Palette API จะดึงสีจากภาพอยู่ 2 แบบด้วยกันคือ Vibrant (สีสด) และ Muted (สีหม่น) แถมยังแยกตามความสว่างของสีแต่ละแบบให้อีกด้วย โดยแบ่งเป็น Light, Normal และ Dark

        อะไรนะ ไม่ค่อยเข้าใจ? ถ้างั้นดูภาพตัวอย่างข้างล่างนี้เลยดีกว่า


        จากภาพข้างบนนี้ เจ้าของบล็อกยกตัวอย่างภาพขึ้นมา แล้วลองใช้ Palette API ในการดึงค่าสี แล้วนำมาแสดงผลเพื่อให้เห็นว่าสีแต่ละโทนแต่ละแบบจะแตกต่างกันยังไง ซึ่งจะได้ออกมาทั้งหมด 6 โทนสี คือ

        • Light Vibrant : สีสดออกสว่าง
        • Vibrant : สีสดปานกลาง
        • Dark Vibrant : สีสดออกมืด
        • Light Muted : สีหม่นออกสว่าง
        • Muted : สีหม่นปานกลาง
        • Dark Muted : สีหมดออกมืด

        และในกรณีที่หาค่าสีในบางช่วงไม่เจอ ก็สามารถกำหนดสี Default ได้ว่าจะให้เป็นสีอะไรแทนที่ ยกตัวอย่างเช่น สีขาว เป็นต้น


การเรียกใช้งาน Palette API

       เพิ่ม Dependency เข้ามาในโปรเจคดังนี้

implementation 'androidx.palette.palette:1.0.0'

        เวลาต้องการเรียกใช้งาน จะต้องเรียกผ่านคลาสที่ชื่อว่า Palette ด้วยคำสั่ง from(...) โดยจะต้องกำหนด Bitmap ที่ต้องการลงไปด้วย

val bitmap: Bitmap = ...

// Synchronous
val palette: Palette = Palette.from(bitmap).generate()

// Asynchronous
Palette.from(bitmap).generate { palette: Palette? ->
    ...
}

       โดยค่าสีจาก Bitmap นั้นๆจะส่งออกมาได้ 2 แบบ คือ Synchronous และ Asynchronous ซึ่งเจ้าของบล็อกแนะนำว่าให้ใช้แบบ Asynchronous ดีกว่า เพราะว่าระยะเวลาในการดึงค่าสีของ Palette API นั้นขึ้นอยู่กับขนาดภาพ ดังนั้นถ้าภาพมีขนาดใหญ่ก็จะใช้เวลานานและทำให้ไปบล็อก UI Thread ดังนั้นการใช้แบบ Asynchronous จึงปลอดภัยกว่า

         ค่าสีที่ได้นั้นจะส่งออกมาเป็นคลาส Palette นั่นแหละ ซึ่งในนั้นก็จะมีค่าสีต่างๆตามที่เจ้าของบล็อกอธิบายไว้ในตอนแรก สามารถดึงค่ามาใช้งานได้เลย

val defaultColor: Int = Color.WHITE
val palette: Palette = ...

val lightVibrantColor: Int = palette.getLightVibrantColor(defaultColor)
val vibrantColor: Int = palette.getVibrantColor(defaultColor)
val darkVibrantColor: Int = palette.getDarkVibrantColor(defaultColor)
val lightMutedColor: Int = palette.getLightMutedColor(defaultColor)
val mutedColor: Int = palette.getMutedColor(defaultColor)
val darkMutedColor: Int = palette.getDarkMutedColor(defaultColor)

       และนอกจากจะดึงค่าสีแต่ละแบบใน Palette แล้ว ยังสามารถดึงสิ่งที่เรียกว่า Swatch ของแต่ละสีออกมาใช้งานได้ด้วย

val palette: Palette = ...

val lightVibrantSwatch: Swatch? = palette.getLightVibrantSwatch()
val vibrantSwatch: Swatch? = palette.getVibrantSwatch()
val darkVibrantSwatch: Swatch? = palette.getDarkVibrantSwatch()
val lightMutedSwatch: Swatch? = palette.getLightMutedSwatch()
val mutedSwatch: Swatch? = palette.getMutedSwatch()
val darkMutedSwatch: Swatch? = palette.getDarkMutedSwatch()

        ซึ่ง Swatch คือชุดสีที่เอาไว้ใช้งานในแต่ละบริบท โดยจะแบ่ง 2 ส่วนคือสีของ Swatch นั้นๆ และสีสำหรับตัวหนังสือเพื่อแสดงบนสีของ Swatch

val palette: Palette = ...
val swatch: Palette.Swatch? = palette.getVibrantSwatch()

swatch?.let {
    val hsl: FloatArray = swatch.getHsl()
    val rgb: Int = swatch.getRgb()
    val bodyTextColor: Int = swatch.getBodyTextColor()
    val titleTextColor: Int = swatch.getTitleTextColor()
    val population = swatch.getPopulation()
}

        โดยสีของ Swatch สามารถเลือกได้ว่าจะดึงค่าออกมาเป็นแบบ RGB หรือว่า HSL และมีการบอกค่า Population ให้ด้วย ซึ่งหมายถึงจำนวน Pixel ที่มีค่าสีตรงกับสีนั้นๆ

        ส่วนสีตัวหนังสือจะแบ่งเป็น Title และ Body ซึ่งทั้ง 2 จะเป็นสีที่แตกต่างกันโดยขึ้นอยู่กับสีของ Swatch นั้นๆ


        จากภาพตัวอย่างข้างบนจะเห็นว่าสีของตัวหนังสือทั้ง Title และ Body จะตัดกับสีของ Swatch เพื่อให้สามารถอ่านได้ง่าย แต่ไม่ได้ Constrast มากเกินไปจนปวดตา

สรุป

        Palette API ถือว่าเป็นเครื่องมือดีๆที่จะช่วยให้นักพัฒนาสามารถเพิ่มลูกเล่นเกี่ยวกับสีใน UI ได้มากขึ้นโดยที่ไม่ต้องเขียนเองให้ยุ่งยาก ไม่ต้องปวดหัวกับการดึงสีจากภาพ และไม่ต้องกังวลว่าสีของตัวหนังสือจะกลืนไปกับสีพื้นหลังเลย เพราะทุกอย่างถูกจัดการไว้เรียบร้อยแล้วใน Palette API นั่นเอง

        เอาล่ะ มาเพิ่มสีสันให้กับแอปกันเถอะ!!