นี่เป็นปัญหาที่เห็นได้ชัดว่าโปรแกรมเมอร์จำนวนมากมีและ Google ยังไม่ได้จัดหาโซลูชันที่น่าพอใจและได้รับการสนับสนุน
มีความตั้งใจและความเข้าใจผิดมากมายที่ลอยอยู่รอบ ๆ โพสต์ในหัวข้อนี้ดังนั้นโปรดอ่านคำตอบทั้งหมดนี้ก่อนตอบกลับ
ด้านล่างนี้ฉันมีการแฮ็กเวอร์ชันที่ "ละเอียด" และแสดงความคิดเห็นเป็นอย่างดีจากคำตอบอื่น ๆ ในหน้านี้รวมถึงแนวคิดจากคำถามที่เกี่ยวข้องอย่างละเอียด
เปลี่ยนสีพื้นหลังของเมนู Android
จะเปลี่ยนสีพื้นหลังของเมนูตัวเลือกได้อย่างไร?
Android: ปรับแต่งเมนูของแอปพลิเคชัน (เช่นสีพื้นหลัง)
http://www.macadamian.com/blog/post/android_-_theming_the_unthemable/
ปุ่มสลับเมนูรายการของ Android
เป็นไปได้ไหมที่จะทำให้พื้นหลังของเมนูตัวเลือก Android ไม่โปร่งแสง?
http://www.codeproject.com/KB/android/AndroidMenusMyWay.aspx
การตั้งค่าพื้นหลังของเมนูให้ทึบแสง
ฉันทดสอบแฮ็คนี้บน 2.1 (เครื่องจำลอง), 2.2 (อุปกรณ์จริง 2 เครื่อง) และ 2.3 (อุปกรณ์จริง 2 เครื่อง) ฉันยังไม่มีแท็บเล็ต 3.X ที่จะทดสอบ แต่จะโพสต์การเปลี่ยนแปลงที่จำเป็นที่นี่เมื่อ / ถ้าฉันทำ เนื่องจากแท็บเล็ต 3.X ใช้แถบการดำเนินการแทนเมนูตัวเลือกตามที่อธิบายไว้ที่นี่:
http://developer.android.com/guide/topics/ui/menus.html#options-menu
แฮ็คนี้แทบจะไม่ทำอะไรเลย (ไม่เป็นอันตรายและไม่ดี) บนแท็บเล็ต 3.X
ข้อความของปัญหา (อ่านสิ่งนี้ก่อนที่จะตอบกลับด้วยความคิดเห็นเชิงลบ):
เมนูตัวเลือกมีรูปแบบที่แตกต่างกันอย่างมากในอุปกรณ์ต่างๆ สีดำบริสุทธิ์พร้อมข้อความสีขาวในบางส่วนมีสีขาวบริสุทธิ์และมีข้อความสีดำอยู่ในบางส่วน ผมและนักพัฒนาอื่น ๆ อีกมากมายต้องการที่จะควบคุมสีพื้นหลังของตัวเลือกเมนูเซลล์เช่นเดียวกับสีของข้อความเมนูตัวเลือก
นักพัฒนาแอปบางรายต้องตั้งค่าสีพื้นหลังของเซลล์เท่านั้น (ไม่ใช่สีข้อความ) และสามารถทำได้อย่างสะอาดตายิ่งขึ้นโดยใช้สไตล์ android: panelFullBackground ที่อธิบายไว้ในคำตอบอื่น อย่างไรก็ตามขณะนี้ยังไม่มีวิธีควบคุมสีข้อความของเมนูตัวเลือกด้วยสไตล์ดังนั้นเราจึงสามารถใช้วิธีนี้เพื่อเปลี่ยนพื้นหลังเป็นสีอื่นที่จะไม่ทำให้ข้อความ "หายไป"
เราชอบที่จะทำสิ่งนี้ด้วยโซลูชันที่มีเอกสารและพิสูจน์ได้ในอนาคต แต่โซลูชันนี้ไม่สามารถใช้ได้กับ Android <= 2.3 ดังนั้นเราจึงต้องใช้โซลูชันที่ใช้งานได้ในเวอร์ชันปัจจุบันและได้รับการออกแบบมาเพื่อลดโอกาสที่จะเกิดปัญหา / เสียหายในเวอร์ชันต่อ ๆ ไป เราต้องการวิธีแก้ปัญหาที่ล้มเหลวอย่างสง่างามกลับสู่พฤติกรรมเริ่มต้นหากต้องล้มเหลว
มีเหตุผลที่ถูกต้องหลายประการที่อาจต้องควบคุมรูปลักษณ์ของเมนูตัวเลือก (โดยทั่วไปเพื่อให้ตรงกับลักษณะภาพสำหรับส่วนที่เหลือของแอป) ดังนั้นฉันจะไม่อยู่กับสิ่งนั้น
มีข้อบกพร่องของ Google Android ที่โพสต์เกี่ยวกับเรื่องนี้: โปรดเพิ่มการสนับสนุนของคุณด้วยการติดดาวข้อบกพร่องนี้ (โปรดทราบว่า Google ไม่สนับสนุนความคิดเห็น "ฉันด้วย" เพียงแค่ติดดาวก็เพียงพอแล้ว):
http://code.google.com/p/android/issues/detail?id=4441
สรุปวิธีแก้ปัญหาให้ไกล:
ผู้โพสต์หลายคนแนะนำการแฮ็กที่เกี่ยวข้องกับ LayoutInflater.Factory การแฮ็กที่แนะนำใช้งานได้กับ Android <= 2.2 และล้มเหลวสำหรับ Android 2.3 เนื่องจากการแฮ็กสร้างข้อสันนิษฐานที่ไม่มีเอกสารว่าสามารถเรียก LayoutInflater.getView () ได้โดยตรงโดยไม่ต้องอยู่ในการเรียก LayoutInflater.inflate () บนอินสแตนซ์ LayoutInflater เดียวกัน โค้ดใหม่ใน Android 2.3 ทำลายสมมติฐานนี้และนำไปสู่ NullPointerException
แฮ็คที่ได้รับการขัดเกลาเล็กน้อยของฉันด้านล่างไม่ได้อาศัยสมมติฐานนี้
นอกจากนี้แฮ็คยังอาศัยการใช้ชื่อคลาสภายในที่ไม่มีเอกสาร "com.android.internal.view.menu.IconMenuItemView" เป็นสตริง (ไม่ใช่ประเภท Java) ฉันไม่เห็นวิธีใดที่จะหลีกเลี่ยงปัญหานี้และยังคงบรรลุเป้าหมายที่ระบุไว้ อย่างไรก็ตามเป็นไปได้ที่จะทำการแฮ็คด้วยความระมัดระวังซึ่งจะถอยกลับหาก "com.android.internal.view.menu.IconMenuItemView" ไม่ปรากฏในระบบปัจจุบัน
โปรดเข้าใจอีกครั้งว่านี่เป็นการแฮ็กและฉันไม่ได้อ้างว่าสิ่งนี้ใช้ได้กับทุกแพลตฟอร์ม แต่พวกเรานักพัฒนาไม่ได้อยู่ในโลกวิชาการแฟนตาซีที่ทุกอย่างต้องเป็นไปตามหนังสือ: เรามีปัญหาที่ต้องแก้และเราต้องแก้ไขให้ดีที่สุดเท่าที่จะทำได้ ตัวอย่างเช่นดูเหมือนว่าไม่น่าเป็นไปได้ที่ "com.android.internal.view.menu.IconMenuItemView" จะมีอยู่ในแท็บเล็ต 3.X เนื่องจากใช้แถบการดำเนินการแทนเมนูตัวเลือก
ในที่สุดนักพัฒนาบางคนได้แก้ไขปัญหานี้โดยการระงับเมนูตัวเลือก Android ทั้งหมดและเขียนคลาสเมนูของตัวเอง (ดูลิงก์ด้านบน) ฉันยังไม่ได้ลอง แต่ถ้าคุณมีเวลาเขียนมุมมองของคุณเองและหาวิธีแทนที่มุมมองของ Android (ฉันแน่ใจว่าปีศาจอยู่ในรายละเอียดที่นี่) อาจเป็นทางออกที่ดีที่ไม่ต้องการอะไรเลย แฮ็กที่ไม่มีเอกสาร
สับ:
นี่คือรหัส
ในการใช้รหัสนี้ให้เรียก addOptionsMenuHackerInflaterFactory () ONCE จากกิจกรรมของคุณ onCreate () หรือกิจกรรมของคุณ onCreateOptionsMenu () ตั้งค่าโรงงานเริ่มต้นที่จะส่งผลต่อการสร้างเมนูตัวเลือกในภายหลัง ไม่มีผลต่อเมนูตัวเลือกที่สร้างไว้แล้ว (แฮ็กก่อนหน้านี้ใช้ชื่อฟังก์ชันของ setMenuBackground () ซึ่งทำให้เข้าใจผิดอย่างมากเนื่องจากฟังก์ชันไม่ได้ตั้งค่าคุณสมบัติเมนูใด ๆ ก่อนที่จะกลับมา)
@SuppressWarnings("rawtypes")
static Class IconMenuItemView_class = null;
@SuppressWarnings("rawtypes")
static Constructor IconMenuItemView_constructor = null;
@SuppressWarnings("rawtypes")
private static final Class[] standard_inflater_constructor_signature =
new Class[] { Context.class, AttributeSet.class };
protected void addOptionsMenuHackerInflaterFactory()
{
final LayoutInflater infl = getLayoutInflater();
infl.setFactory(new Factory()
{
public View onCreateView(final String name,
final Context context,
final AttributeSet attrs)
{
if (!name.equalsIgnoreCase("com.android.internal.view.menu.IconMenuItemView"))
return null;
View view = null;
if (IconMenuItemView_class == null)
{
try
{
IconMenuItemView_class = getClassLoader().loadClass(name);
}
catch (ClassNotFoundException e)
{
return null;
}
}
if (IconMenuItemView_class == null)
return null;
if (IconMenuItemView_constructor == null)
{
try
{
IconMenuItemView_constructor =
IconMenuItemView_class.getConstructor(standard_inflater_constructor_signature);
}
catch (SecurityException e)
{
return null;
}
catch (NoSuchMethodException e)
{
return null;
}
}
if (IconMenuItemView_constructor == null)
return null;
try
{
Object[] args = new Object[] { context, attrs };
view = (View)(IconMenuItemView_constructor.newInstance(args));
}
catch (IllegalArgumentException e)
{
return null;
}
catch (InstantiationException e)
{
return null;
}
catch (IllegalAccessException e)
{
return null;
}
catch (InvocationTargetException e)
{
return null;
}
if (null == view)
return null;
final View v = view;
new Handler().post(new Runnable()
{
public void run()
{
v.setBackgroundColor(Color.BLACK);
try
{
TextView tv = (TextView)v;
tv.setTextColor(Color.WHITE);
}
catch (ClassCastException e)
{
}
}
});
return view;
}
});
}
ขอบคุณที่อ่านและสนุก!