สรุป session "Build your own custom view with Canvas API in Android" จากงาน Android Bangkok 2020

Android Oct 8, 2021

Session ของ Android GDE หนึ่งเดียวในไทยในตอนนี้ ที่เราเองน้านก็ดองนานแสนนานกว่าจะสรุปเนี่ย

Canvas API จะช่วยเราสร้าง custom view ได้อย่างไรกันนะ? session น้ีจะมีความต่อเนื่องกับงาน Android Bangkok รอบก่อนหน้านี้ ที่พูดเรื่อง Bitmap ไป แปะลิ้งบล็อกไป น่าจะ session สุดท้ายของงานเลยนะ

เล่าเรื่องงาน Android Bangkok 2019 ในนาม speaker อีกปีหนึ่ง
ต้นปีนี้เป็นปีแห่งการเปลี่ยนแปลงของเรา สถานที่จัดงานก็เปลี่ยนแปลงไปด้วย

แล้ว Canvas คืออะไรหล่ะ? เราจะนึกถึงพื้นที่ในการวาดรูป จริงๆ Canvas เป็นเหมือน container ที่เก็บ operation ในการจะวาดภาพบนกระดาษ คือการเก็บคำสั่ง ที่จะวาดบนในกระดาษนั่นเอง

Component อะไร ที่เราวาดบนลง Android ได้บ้างนะ?

  • Bitmap เป็นเหมือนกระดาษจริงๆ อะไรที่เราวาดก็จะอยู่ตรงนั้น
  • Canvas บอกว่าจะใช้คำสั่งวาดอะไร เช่น วาดวงกลมลงในกระดาษให้หน่อยน้าา
  • Drawing Primitive ลักษณะรูปร่างในการวาดรูปพื้นฐาน เช่น เป็นสี่เหลี่ยม เป็นเส้น เป็นตัวหนังสือ เป็น Bitmap
  • Paint เปรียบเสมือนอุปกรณ์ที่เราใช้ในการวาด เช่น ใช้ดินสอ ใช้พู่กัน ใช้ปากกาตัดเส้น บลาๆ

ดังนั้น เส้นที่เราจะเขียนบน Canvas หรือ Bitmap นั้น จะขึ้นอยู่กับ Paint ที่เรากำหนดไว้นั่นเอง

Method พื้นฐานในการทำ CustomView ก็คือ onMeasure(), onLayout() และ onDraw()

โดย onDraw() คือสิ่งที่เราจะวาด ลงบนใน CustomView ตัวนั้น โดยจะส่งตัว canvas ออกมาให้ ดังนั้นเราจะวาดอะไรก็ได้ผ่าน canvas ตัวนี้ได้เลย เพื่อสร้าง Bitmap ของเราเอง เพราะว่าสร้าง Bitmap หรือ Canvas ให้เราเรียบร้อยแล้ว

เบื้องหลังการ render view ให้เราดูนั้น ดูจาก session ที่ชื่อว่า "How Android renders" หนึ่งใน session ของ Google I/O 2018 นั่นเอง

Canvas

วิธีการสร้าง Canvas อย่างง่าย ทำได้โดยสร้าง Bitmap ขึ้นมา และใส่ลงใน Canvas เราจะได้ Canvas เพื่อเอาไปใช้ในการวาดรูปของเรา

Drawing Primitivess

การวาดจุด ก็จะใช้คำสั่งพื้นฐาน drawPoint() กำหนดพิกัด x, y และ paint ในการวาดจุด

ถ้าอยากวาดเส้นหล่ะ? มีคำสั่ง drawLine() ให้พิกัดเริ่มต้น พอกัดสิ้นสุด เพื่อลากเส้นจากจุดเริ่มต้นไปยังจุดปลายทางให้

ใส่ความฮาไปหนึ่งซ็อต 555555555555 คนละไลน์ค่ะคุณพี่

ถ้าอยากวาดสี่เหลี่ยมหล่ะ? สร้างสี่เหลี่ยมขึ้นมาอันนึง ผ่าน drawRect() กำหนด left, top, right, bottom ของมัน หรือจะใช้ class RectF() ที่ใส่ค่าเป็น float ก็ได้นะ ส่วน Rect() ที่เราคุ้นเคยกันจะใส่ค่าเป็น Int นะเออ

วิธีการวาดสี่เหลี่ยม เราเข้าใจว่าน่าจะประมาณนี้นะ คือ เอาจุดซ้ายบน และขวาล่างมา เพื่อตีกรอบเพื่อวาดเป็นสี่เหลี่ยม

วาดได้สี่เหลี่ยมขอบมนก็ทำได้เช่นกันนะ โดยการสร้างสี่เหลี่ยมปกติขึ้นมาก่อน จากนั้นใช้ drawRoundRect() ในการทำขอบมน ซึ่ง redius สองตัวนี้เป็น redius แกน x และ redius แกน y นิยมใส่สองค่านี้เท่ากัน เพื่อความโค้งมนที่สวยงาม (หรือกันงงก็ไม่รู้เหมือนกันนะ)

แล้ววงกลมอ่ะ? กำหนดจุดศุนย์กลางของวงกลม ในพิกัดแกน x และ y พร้อมใส่รัศมีของวงกลมวงนั้น

และถ้า advance ขึ้นนิดนึงหล่ะ ถ้าเราจะวาด arc (ส่วนโค้งของวงกลม) หล่ะ? ตัวแปรจะเริ่มเยอะขึ้น เนื่องจาก เราไม่ได้กำหนดจุดศูนย์กลางของวงกลมเลย เราจะกำหนด left, top, right, bottom มันจะตีกรอบสี่เหลี่ยมให้เรา

แล้วรัศมีของวงกลมหล่ะ? มันจะเริ่มจากด้านขวามือก่อน เป็น 0 องศา แล้ววนตามเข็มนาฬิกาจนครบวง

วิธีการวาดเส้น จะให้วาดเริ่มที่ 150 องศา ให้เส้นยาวไป 180 องศา ทำให้เราได้เส้น arc ที่เราต้องการนั่นเอง

ของเราตอนนี้กลายเป็นวงกลมปิดเฉย ไม่ได้เป็นเส้น งงเหมือนกัน

useCenter เป็น true มันจะเชื่อมจุด start กับจุด end

กำหนดสีพื้นหลัง สามารถกำหนดเป็น drawColor ได้เลย ไม่ต้องวาดสี่เหลี่ยมเต็มหน้าจอเนอะ

อีกอันที่คุณเอกใช้บ่อยคือ path การวาดเส้น และเอาเส้น start กับเส้น end มาบรรจบกัน คล้ายๆกับ polygon ใน Google Maps เวลาจะวาด area

วิธีการวาด

  • moveTo(20f, 20f) เลื่อน cursor ไปพิกัด (20, 20) จะอยู่มุมบนซ้ายมือ
  • lineTo(40f, 20f) ลากเส้นจากมุมบนซ้ายมือไปที่ (40, 20)
  • arcTo() เขียนเส้น arc ขึ้นมา
  • lineTo(90f, 20f) ลากเส้นไปยังฝั่งมุมบนขวา
  • lineTo(90f, 90f) ลากเส้นจากมุมขวาบนลงมามุมขวาล่าง
  • lineTo(20f, 90f) ลากเส้นด้านล่าง จากมุมล่างขวา ไปมุมล่างซ้าย
  • close() มันจะวาดเส้นจากล่างซ้ายไปบนซ้ายที่เป็นจุดเริ่มต้น เป็นการจบการวาด

ต่อมาวาดข้อความ ให้ใส่ text พร้อมระบุพิกัดผ่าน drawText()

ถ้าจะเพิ่มรูป ให้โหลดไฟล์ภาพออกมาเป็น Bitmap และเอามาใส่ใน drawBitmap พร้อมด้วยตำแหน่งที่เราต้องการวาดลงไป ใส่แค่ left กับ top ก็พอ เดี๋ยวมันจะวาดทั้งหมดให้เรา

ถ้าอยากให้วาดขนาดครึ่งนึงของรูปหล่ะ drawBitmap จะคำนวณขนาดของ source และ destination ของ Bitmap ได้ เราสามารถ crop ภาพที่เป็น source ได้ด้วยนะ

Paint

เปรียบเสมือนอุปกรณ์ที่ใช้ในการวาด

สิ่งแรกที่เราจะกำหนดในการทำ Canvas ก็คือisAntiAlias = true กำหนดเพื่อเส้นทแยงแตกเป็น pixel มันจะเกลี่ยให้เส้นมันสวยงามดูนวลขึ้น

อีกค่านึงที่ใช้บ่อย คือ style มีทั้งหมด 3 แบบด้วยกัน

  • Paint.Style.FILL พื้นที่ที่ถมสีที่เรากำหนด
  • Paint.Style.STROKE ถมสีเฉพาะเส้นขอบ
  • Paint.Style.FILL_AND_STROKE ถมสีทั้งเส้นขอบและพื้นที่

กำหนดสีใช้ color กำหนดความโปร่งใส่ใช้ alpha

กำหนดขนาดตัวหนังสือใช้ textSize แต่มันเป็น pixel ดังนั้นถ้าใช้ sp อย่าลืม convert เป็น pixel ด้วย และกำหนด font ด้วย typeface ถามว่าไม่กำหนดได้ไหม ได้! แต่มันจะดึงจาก system มาให้ มันก็จะไม่ค่อยสวยหน่อย

ถ้าเราอยากรู้ว่ารูปตัวหนังสือที่เราจะวาด เกินหน้าจอไหม โดยยังไม่ต้อง render ให้ใช้ measureText เพื่อวัดได้ว่าถ้าใช้ textSize หรือ typeface นี้ จะใช้พื้นที่ในการวาดเท่าไหร่?

Paint จะมีสิ่งนึงที่เรียกว่า Mask Filter อยู่ ตัวนึงที่คุณเอกใช้บ่อยๆคือ BlurMaskFilter ทำวัตถุนั้นให้ blur

ถ้าจะลบทุกอย่างบน Canvas ทิ้งหล่ะ ใช้คำสั่ง drawColor โดยการใส่สีขาว เพิ่มเติมด้วยการใส่ PorterDuff.Mode.CLEAR

Compositing Mode

เป็นเทคนิคผสมผสานภาพทั้งสองภาพเข้าด้วยกันในเชิง Digital Image ถูกคิดค้นโดย Thomas Porter และ Tom Duff อันเป็นที่มาของ PorterDuff นั่นเอง เพราะว่าทีม Android อาจจะให้เกียรติแก่คนคิดค้นการทำงานเหล่านี้ขึ้นมา

ตัว class นี้มีให้เราใช้งานกันอยู่แล้ว ไม่ต้อง import อะไรมาเพิ่ม

Compositing Mode ทำงานอย่างไร? เราจะมี 2 ภาพ ด้วยกัน คือ Source ภาพที่ได้จากการที่เราใช้คำสั่ง draw ต่างๆ และ Destination คือสิ่งที่อยู่บน Bitmap อยู่แล้ว

แล้ว Compositing Mode มีอะไรบ้าง? อ่าาาา ตามรูปในสไลด์นี้เลยจ้า มีทั้งหมด 18 แบบ เช่น

  • ADD เราจะเห็น object ทั้งสองทับกัน
  • DST_IN เวาดเฉพาะ source แต่แสดงพื้นที่ที่ destination มีอยู่แล้ว
  • CLEAR ไม่มีอะไรเลย จึงใช้ในการลบภาพทุกอย่างใน Canvas นั่นเอง

จริงๆแล้วมันทำงานยังไงกันนะ? มาจากสมการเหล่านี้ คือ การคำนวณ alpha, การคำนวณ color เป็น RGB และตามมาด้วยสมการของ Compositing Mode นั้นๆ

ตัวอย่าง เรานำสีของทั้ง source และ destination เป็น ARGB แต่เราจะไม่คำนวณเป็น 255 นะ แปลงเป็น 1 เพราะ 255 เราจะใช้ในเชิง programming เท่านั้น

จากนั้นนำไปคำนวณในสมการ

เมื่อได้ผลลัพธ์แล้ว นำไปคูณ 255 กลับไป เพื่อเป็นเลขฐาน 16

ผลลัพธ์ที่ได้

Quiz Time

อันนี้คือ Compositing Mode ของอะไร?

ซึ่งคนที่อยู่ในงาน คนที่นั่งดูไลฟ์จากที่บ้าน ต่างก็ตอบผิดกันเป็นแถบ

เฉลยคือ SCREEN นั่นเอง กว่าจะถูกคือคนในงานตอบจนจะหมดตัวเลือกที่ตอบได้แล้วอ่ะ

ถ้า 18 แบบนี้เราไม่ถูกใจ เราทำเองได้ไหม? ไม่ได้! เพราะบน Android ไม่ให้เรา custom ตัวสมการเอง

ประโยชน์อย่างนึงของ Compositing Mode ก็คือ ใน Paint มี transfer mode xfermode เราสามารถสร้าง PorterDuff transfer mode ลงไปได้ ดังนั้นทุกคำสั่งที่เราวาด มันจะเป็น Compositing Mode โดยอัตโนมัตินั่นเอง

สิ่งที่ควรรู้เวลาจะวาดด้วย Canvas ลงบน Custom View

  • invalidate() เป็นคำสั่งให้ View วาดใหม่ทันที เป็น UI Thread
  • ถ้าต้องการเรียกผ่าน Worker Thread ให้ใช้ postInvalidate()
  • คำนวณเป็น px นะ
  • คำสั่งทุกอย่างที่จะวาดใน onDraw() ให้ใช้เวลาตํ่ากว่า 16 ms
  • อย่าไปสร้าง object ใหม่ๆด้วย onDraw เยอะ เพราะเวลา onDraw() ถ้าเราไป new instance บ่อยๆ มันจะส่งผลต่อ perfomance ด้วย
  • ดังนั้นจึงกำหนดเป็น global variable ในตัวที่เราใช้บ่อยๆใน onDraw() ให้กำหนดรอไว้เลย ดีกว่าไปกำหนดใหม่หลายๆครั้ง
  • ถ้าใช้เป็น ViewGroup ให้ใช้ setWillNotDraw(false) ได้เลย เพราะว่าปกติ ViewGroup จะไม่ draw ตัวเองในครั้งแรก เราใส่เพื่อบอกมันว่า ให้ draw ตัวเองด้วยนะ

ทำไมต้องทำคำสั่งใน onDraw() ภายใน 16 ms ด้วยหล่ะ?

เพราะมีโปรเจกชื่อว่า Butter มีสโลแกนว่า Smooth as Butter ลื่นเหมือนเนย

concept คืออยากเพิ่ม performance และ experience ของ user ให้รู้สึกว่า Android มันลื่น ก็เลยทำให้ตัว OS run อยู่ที่ 60fps

ถ้า 1 วินาทีรัน 60 เฟรม แล้ว 1 เฟรมจะต้องใช้เวลาเท่าไหร่? เท่ากับ 16 ms นั่นเอง

ดังนั้นเราจะต้องทำคำสั่งใดๆใน UI Thread ใช้เวลาตํ่ากว่า 16 ms เพื่อความลื่นนั่นเอง

มือถือรุ่นใหม่ๆ เช่น Pixel4 จะมี 90 fps ดังนั้นเราจะต้องให้ operation ต่างๆ ทำงานเร็วขึ้นกว่าเดิม

เราต้องทำถึง 120 fps ไหม? ไม่จำเป็น ทำถึง 60 fps เป็นมาตรฐานก็พอแล้ว

KTX Graphic

เราจะคุ้นเคยกับการใช้ ktx ต่างๆในโปรเจกของเรา ซึ่งในส่วนนี้ก็มีมาให้เราเหมือนกัน

และมีอะไรให้ใช้บ้างนะ?

เราสร้าง Bitmap ขึ้นมา เพื่อมาใส่ใน Cnavas ใน KTX เราสามารถใช้ applyCanvas ได้เลย ซึ่งมันจะทำการสร้าง Canvas ให้อยู่เบื้องหลัง และใน scope มันจะโยน Canvas มาให้เราเอาไปใช้ต่อได้เลย

แปลงสีจาก HEX color ที่เป็น string สามารถใช้ toColorInt() ได้เลย แต่ด้วยความที่มัน .toColorInt() มันค่อนข้างอันตราย แนะนำให้ใช้อย่างระมัดระวังนิดนึง

จากเดิมที่สร้าง PorterDuffXfermode() ขึ้นมา สามารถเรียกเป็น PorterDuff.Mode.OVERLAY.toXfermode() ได้เลย สั้นลงกว่าเดิมเยอะ

ตัวสี่เหลี่ยม ถ้าเราสร้างสี่เหลี่ยมที่ขนาดเท่ากัน ต่างกันเพียง Int และ Float สามารถใช้ toRectF() และ toRect() ในการ convert ได้ง่ายๆเลย

สามารถ get ค่า alpha, red, green, blue จากสีได้โดยตรงเลย

สามารถใช้ท่านี้ได้ สำหรับ API Level 26 ขึ้นไปเนอะ

Use Case : Coupon UI

ใช้ Canvas สร้าง Custom View คือ ตัว coupon ที่เป็น ViewGroup ที่สามารถใส่ content ข้างในได้

หน้าตาจะประมาณนี้ พอดีว่าเป็น background สีขาว แคปจอมายังไม่ค่อยเห็น แล้วจอที่งานน่าจะแยกออกยากนิดนุง มีเงา สามารถปรับความโค้งต่างๆได้ อยากให้มัน Flexible

เบื้องหลังจะแบ่งออกมาเป็น 3 layers คือ border, background และ shadow วาดทับกันจนเป็น coupon และมีขอบให้ด้วย

สิ่งที่ควรรู้ เราไม่สามารถวาดอะไรเกินขอบเขตที่เราวาดได้ ดังนั้นจะต้องมี padding เผื่อด้วยในการวาดเงา

จริงๆแล้ว มันเกิดจากการวาด canvas ง่ายๆ แต่ละ layer จะเป็น Paint เนอะ มี 3 ตัว และทั้ง 3 มี shape เหมือนกัน ดังนั้นสามารถใช้ Path ร่วมกันได้เลย เมื่อวาด Path แล้ว เราจะวาด Paint ทีละชั้น โดยเริ่มจากชั้นล่างสุดคือ shadowPaint ตามมาด้วย backgroundPaint และจบด้วย borderPaint

การสร้าง Path จะมีส่วนที่ยากคือขอบมน เพราะเราไม่สามารถสร้างสี่เหลี่ยมขอบมนได้เนื่องจากมีพื้นที่ครึ่งวงกลมที่ถูกตัดออกอยู่ ถามว่าใช้ได้ไหม? ได้! โดยใช้ Compositing Mode ในการสี่เกลี่ยมขอบมน แล้วใช้ Paint อีกตัวนึง เพื่อเอา Compositing Mode มาตัดส่วนเว้าครึ่งวงกลมออกได้

ในที่นี้จะใช้ Path วาดทีละเส้น

ส่วนของเงา ที่มองในสไลด์ไม่เห็น กำหนดเป็นสีดำที่มี alpha เป็น 40 (มีค่าระหว่าง 0 - 255) และใช้ BlurMaskFilter เพื่อทำให้เบลอตรงขอบ เบลอออกไปข้างนอก

ส่วนของพื้นหลัง ไม่มีอะไรมาก แค่เทสีเข้าไป

ขอบก็เช่นกัน เทสีไปที่ขอบ

ในส่วน usecase เจ้า coupon ถามว่าเรากำหนด flexible ได้แค่ไหน ก็จะประมาณนี้แหละ สามารถ custom attribute ของ View ได้ตามใจชอบ และรองรับ StateListDrawable ด้วย

อ่านเพิ่มเติม

Getting Started with Drawing on the Android Canvas 🖼
Learn how to use the Android Canvas class
https://medium.com/over-engineering/getting-started-with-drawing-on-the-android-canvas-621cf512f4c7

สำหรับโค้ดทางเราพยายามลองเล่นดู สามารถช่วยกัน contribute ได้เลย

GitHub - mikkipastel/drawing: Android drawing
Android drawing. Contribute to mikkipastel/drawing development by creating an account on GitHub.
https://github.com/mikkipastel/drawing

Glassmorphism

เป็นอะไรที่ทางเราไม่เก็ท ว่ามันเป็น trend ฝั่ง design ได้อย่างไร?

คุณเอกบอกว่าเป็น design ที่จะมาในปี 2021 ถามว่าสรุป session ตอนจะหมดปีแล้ว ถามว่ามีไหม ไม่ค่อยเจอนะ ถ้าเจอน่าจะใน Apeboard อ่ะ ตอนนี้ก็ไม่แน่ใจว่าเขาเอาออกยัง แต่เป็น website นะไม่ใช้แอพ

หน้าตาก็จะเป็นแบบนี้

.

มันคือ concept ในการ design เป็นรูปกระจกฝ้า อะไรที่อยู่ด้านหลังกระจกก็จะเบลอ ไม่ใช่เบลอพื้นหลังทั้งหมดเน้อ

ปกติจะเบลอเต็ม แต่ Glassmorphism มันเบลอเฉพาะส่วน

ถามว่าบน Android ทำได้ไหม? คุณเอกได้ทำการถามน้องเบน คำตอบคือ ได้!! โดยการใช้ 3D Engine แต่ถ้าใช้แบบนี้ เราก็ไม่ใช่ Native Developer หล่ะ เป็น Game Engine ไปแล้ว

ก่อนอื่นเรามาเข้าใจ behavior ของ native กันก่อนเลย คุณ native รู้จักกระจกไหม เขาไม่รู้จัก แล้วถ้ารู้จัก จะรู้จักจากอะไรหล่ะ? มี limitation คือ Canvas คือเบื้องหลังในการเกิด View ใน Android ดังนั้นเราจะทำด้วย native ยากมาก เพราะตัวมันไม่สามารถบอกได้ว่า สิ่งที่วาดลงไป ช่วยทำตัวเองเป็นกระจกนะ มันจะรู้จักตัวเองแค่พื้นผิวธรรมดา เงาก็คือใช้การเบลอ สรุปคือตัว native ไม่ support นั่นเอง

ดังนั้นในการทำการเบลอเฉพาะส่วน จะเป็นการร่วมพลังของ Bitmap API, Canvas API และ RenderScript API นั่นเอง

Fully Blur ก็จะมีพื้นหลัง ซึ่งไม่จำเป็นต้องชัดมาก ใช้ขนาดเล็กๆไปเลยยังได้ เพราะยังไงต้องถูกเบลออยู่ดี บวกกับ UI ที่ป็น content

Partially blur ประกอบด้วย 3 ส่วนด้วยกัน คือภาพพื้นหลัง ที่ไม่เบลอ, ภาพพื้นหลัง ที่ทำให้เบลอเฉพาะส่วน และ UI ที่เป็น content

มาดูพื้นหลังกระจกฝ้ากัน จริงๆคือสีขาวโปร่งใสน้อยมากจนดูเป็นสีเทา

ตรงนี้จะมี 3 layers ด้วยกัน มี Shadow, Surface และ Border

ตัว Border จะเป็นสีขาว มีความโปร่งใสมากกว่า layer อื่นๆ ส่วน Surface เป็นสีขาวเช่นกัน แต่มีความโปร่งใสน้อยกว่า layer อื่นๆ ทำให้ความรู้สึกเหมือนกระจก และ Shadow มีเงานิดหน่อย

แล้วเราจะเบลอเฉพาะส่วนได้อย่างไร?

เริ่มจากดึงภาพ Bitmap ที่ View ด้านหลัง ทำแบบนี้เพื่อเผื่อการใส่ View ต่างๆใน ViewGroup นี้ แล้วค่อยดึง Bitmap ออกมา

ทำการเบลอภาพที่ได้ ด้วยการใช้ RenderScript ช่วยในการทำเบลอ เพราะคำนวณด้วย GPU ทำให้ performance จะดีกว่าใช้ Canvas ในกรณีนี้ ทำให้ระยะเวลาการทำเบลอเร็วมากกว่า ประมาณ 1-3 ms

setRadius เราจะกำหนด radius ในการเบลอเท่าไหร่ก็ได้ ค่ายิ่งมาก ยิ่งเบลอมาก สูงสุดที่ 25 นะ ตํ่าสุดคือ 0 ก็คือไม่เบลอ ดังนั้นเราจะได้ Bitmap ที่มีความเบลอเป็นที่เรียบร้อย

แล้วเราต้อง capture content ด้วย โดยการ capture view เฉพาะที่เป็นกระจก มาใส่ใน Bitmap

จากนั้นลองใช้ Compositing Mode แต่ไม่มีสมการที่เราอยากได้ อยากได้ค่า alpha เป็น 1 เสมอ พอเอาไปทำแล้วได้ภาพที่จางมาก ดังนั้น dump pixel ออกมาจาก Bitmap และคำนวณหาพื้นที่ ที่เราจะถมเป็นสีขาว

เมื่อเราได้ Source และ Destination มาแล้ว เราจะกำหนด Paint ตัวใหม่ขึ้นมา และให้ xfermode เป็น SRC_IN

สรุป ทำได้จริง แต่ไม่ support native และการ overlap ลองทำแล้ว performance แย่มาก ถ้ามันซ้อนกัน ซึ่งจริงๆไม่ทำกันเพราะ UX ไม่ดีเท่าไหร่ ทาง design อาจจะต้องการแค่นี้

ไม่สามารถจบได้ใน View เดียว และพื้นหลังต้องไม่ขยับ ไม่งั้นแตกแน่นอน 60fps อาจจะเอาไม่อยู่

ส่วนโค้ดสามารถเข้าไปส่องได้ที่นี่

GitHub - akexorcist/Glassmorphism: [Android] Glassmorphism UI experiment project
[Android] Glassmorphism UI experiment project. Contribute to akexorcist/Glassmorphism development by creating an account on GitHub.
https://github.com/akexorcist/Glassmorphism

สามารถ support ค่ากาแฟเจ้าของบล็อกได้ที่ปุ่มแดงส้มสุดน่ารักที่มุมซ้ายล่าง หรือกดปุ่มตรงนี้ก็ได้จ้า

Buy Me a Coffee at ko-fi.com

กด follow Twitter เพื่อได้รับข่าวสารก่อนใคร เช่น สปอย content ใหม่ หรือสรุป content เร็วๆในนี้จ้า

ติดตามข่าวสารและบทความใหม่ๆได้ที่

อย่าลืมกด like กด share บทความกันด้วยนะคะ :)

Posted by MikkiPastel on Sunday, 10 December 2017

download แอพอ่านบล็อกใหม่ของเราได้ที่นี่

Tags

Minseo Chayabanjonglerd

I am a full-time Android Developer and part-time contributor with developer community and web3 world, who believe people have hard skills and soft skills to up-skill to da moon.