เปลี่ยนสีปุ่ม Material Design ดั่งใจ พร้อม Ripple หลากสี

Travis P
Black Lens
Published in
2 min readDec 27, 2016

ไม่ต้องสร้าง drawable ให้วุ่นวาย

บทความนี้มีในภาษาอังกฤษ

บทความนี้แปลมาจากภาษาอังกฤษ โดยได้รับอนุญาติจากเจ้าของแล้ว

ผมเชื่อว่าทุกคนคงชอบ AppCompat support library นะครับ เราได้ Material Design UI ส่งตรงจาก Google มาใช้กันฟรีๆ

แต่มีอย่างนึงที่ผมรู้สึกว่ามันยากเกินความจำเป็น และเบื่อหน่ายทุกครั้งที่ต้องทำ ใช่แล้วครับ มันคือการเปลี่ยนสีปุ่ม Button หรือ Ripple นั่นเอง ผมไม่เข้าใจเลยว่าเรื่องแค่นี้ทำไมต้องทำถึงขนาดไปสร้าง drawable แยกระหว่าง pre-API21 กับ post-API21 เฮ้ออออออ

ด้วยความเบื่อหน่าย ก็เลยตั้งใจศึกษาจากทั้ง docs ทั้ง stackoverflow ทั้ง blog สุดท้ายก็มาเจอวิธีง่ายๆจนได้

วิธีนี้ใช้ AppCompat version 25.1.0 ทดสอบบน emulator API25, API16 และเครื่อง Google Pixel

  1. เปลี่ยนสี background ด้วยandroid:backgroundTint
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/yellow"
android:text="Yellow Tint Button" />

การใช้ android:backgroundTint ทำให้ปุ่มเปลี่ยนสี พร้อมทั้ง ripple effect ที่ถูกต้อง ง่ายที่สุด แต่น่าเสียดายที่ใช้ได้เฉพาะ API21+ เท่านั้น

AppCompat version ก่อนหน้านี้ (จำไม่ได้อันไหน) เราสามารถใช้ app:backgroundTint ได้ทุก API level โดย เครื่องหลัง API21 ได้สีพร้อม ripple ส่วนก่อน API21 จะได้ StateListDrawable แต่ปัจจุบันถ้าเราพยายามใช้ app:backgroundTint เจ้า linter จะโวยวาย และใช้งานได้กับหลัง API21 เท่านั้น อันนี้ผมไม่มั่นใจว่าเป็นบักหรือเค้าจงใจ แต่ถ้า linter ขีดเส้นใต้สีแดงมา ผมก็ไม่อยากจะใช้แล้วครับ

2. เปลี่ยนสี background ด้วย android:theme

อีกวิธีคือใช้ theme เราสามารถประกาศ<item name=”colorButtonNormal”>@color/yellow</item> ใน AppTheme ทำให้ปุ่มทุกปุ่มในแอพกลายเป็นสีเดียวกันหมด API21+ จะได้ ripple effect สวยงาม ในขณะที่รุ่นก่อน API21 จะได้ StateListDrawable

<!-- styles.xml -->
<style name="AppTheme.YellowButton">
<item name="colorButtonNormal">@color/yellow</item>
</style>
<!-- layout.xml -->
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.YellowButton"
android:text="Yellow Tint Button" />

ทีนี้สิ่งที่เราต้องการคือเปลี่ยนสีเฉพาะปุ่ม สิ่งที่เราต้องทำคือสร้าง theme ใหม่ (สืบทอดมาจาก AppTheme ก็ดี) จากนั้นกำหนดให้ปุ่มนั้นใช้ theme ใหม่ที่สร้างขึ้น เพียงเท่านี้ก็ได้แล้ว วิธีนี้ใช้ได้กับทุก API level เลย

3. Ripple color

<!-- styles.xml -->
<style name="AppTheme.GreenRipple">
<item name="colorControlHighlight">@color/green</item>
</style>
<!-- layout.xml -->
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.GreenRipple"
android:text="Green Ripple Button" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?selectableItemBackground"
android:theme="@style/AppTheme.GreenRipple"
/>

อันนี้หลักการเหมือน colorButtonNormal แต่colorControlHighlight จะไปเปลี่ยนสี ripple แทน

สำหรับ View อื่นๆที่ไม่ใช่ Button เราสามารถใช้ theme พร้อมใส่android:background=”?selectableItemBackground” (หรือ android:foreground) เพื่อให้มี ripple effect ได้

สำหรับเครื่องก่อน API21 จะได้ StateListDrawable ที่มีสีสถานะกดเป็นcolorControlHighlight ที่เราใส่ไว้

หรือถ้าต้องการเปลี่ยนสีปุ่มและสี ripple ก็ใส่ทั้งcolorButtonNormal และ colorControlHighlight ใน theme นั้นไปเลย

4. ตัวพิมพ์เล็กบนปุ่ม

อันนี้ผมเจอบ่อย เวลาที่ designer มาบอกว่า “ชั้นไม่เอาตัวพิมพ์ใหญ่ทุกตัว”

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="textAllCaps=false"
android:textAllCaps="false" />

5. FloatingActionButton

<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
app:backgroundTint="@color/red"
app:rippleColor="@color/green"
app:srcCompat="@android:drawable/ic_dialog_email" />

สำหรับ FAB นี้ชีวิตง่ายสุด แค่เปลี่ยนapp:backgroundTintกับ app:rippleColor ก็ได้แล้ว (ขอขอบคุณ Wanchuda Sukarrom ที่เพิ่มเติมให้)

แต่สมมติวันนึงมันเกิดใช้ไม่ได้ขึ้นมา โค้ดด้านล่างนี้ก็ใช้แทนได้

<!-- styles.xml -->
<style name="AppTheme.RedFabGreenRipple">
<item name="colorAccent">@color/red</item>
<item name="colorControlHighlight">@color/green</item>
</style>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:theme="@style/AppTheme.RedFabGreenRipple"
app:srcCompat="@android:drawable/ic_dialog_email" />

วันนี้เท่านี้ก่อนละกันครับ ถ้าเพื่อนๆมีอะไรจะเพิ่มเติม จัดมาเลย
ถ้าบทความนี้ทำให้ชีวิตง่ายขึ้น กด 💚 recommend หรือจะแชร์ ช่วยกันเผยแผ่ครับ
ขอให้โค้ดกันอย่างเมามันครับทุกท่าน

--

--

Travis P
Black Lens

Android Developer, Kotlin & Flutter Enthusiast and Gamer