यह स्पष्ट रूप से एक समस्या है जो बहुत सारे प्रोग्रामर के पास है और जिसके लिए Google को अभी तक एक संतोषजनक, समर्थित समाधान प्रदान करना है।
इस विषय पर पोस्ट के आसपास बहुत सारे अभिप्रेरित इरादे और गलतफहमी हैं, इसलिए जवाब देने से पहले कृपया इस पूरे उत्तर को पढ़ें।
नीचे मैं इस पृष्ठ पर अन्य उत्तरों से हैक के एक अधिक "परिष्कृत" और अच्छी तरह से टिप्पणी किए गए संस्करण को शामिल करता हूं, इन बहुत ही निकट से संबंधित प्रश्नों से विचारों को भी शामिल करता है:
एंड्रॉइड मेनू का पृष्ठभूमि रंग बदलें
विकल्प मेनू की पृष्ठभूमि का रंग कैसे बदलें?
Android: अनुप्रयोग के मेनू (जैसे पृष्ठभूमि रंग) को अनुकूलित करें
http://www.macadamian.com/blog/post/android_-_theming_the_unthemable/
Android MenuItem टॉगल बटन
क्या 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 टैबलेट पर कुछ भी नहीं (कोई नुकसान नहीं और अच्छा नहीं) करेगा।
समस्या का विवरण (इसे नकारात्मक टिप्पणी के साथ ट्रिगर-उत्तर देने से पहले पढ़ें):
विकल्प मेनू में विभिन्न उपकरणों पर अलग-अलग शैली है। कुछ पर सफेद पाठ के साथ शुद्ध काला, कुछ पर काले पाठ के साथ शुद्ध सफेद। मैं और कई अन्य डेवलपर्स विकल्प मेनू कोशिकाओं के पृष्ठभूमि रंग के साथ-साथ विकल्प मेनू पाठ के रंग को नियंत्रित करना चाहते हैं ।
कुछ ऐप डेवलपर्स को केवल सेल बैकग्राउंड कलर (टेक्स्ट कलर नहीं) सेट करने की आवश्यकता होती है, और वे इसे एंड्रॉइड का उपयोग करके एक क्लीनर तरीके से कर सकते हैं: एक अन्य उत्तर में वर्णित पैनलफ्लेकबैकग्राउंड स्टाइल। हालाँकि, वर्तमान में शैलियों के साथ विकल्प मेनू पाठ रंग को नियंत्रित करने का कोई तरीका नहीं है, और इसलिए केवल पृष्ठभूमि को दूसरे रंग में बदलने के लिए इस पद्धति का उपयोग कर सकते हैं जो पाठ को "गायब" नहीं करेगा।
हम इसे एक प्रलेखित, भविष्य-प्रूफ समाधान के साथ करना पसंद करेंगे, लेकिन एक बस एंड्रॉइड <= 2.3 के रूप में उपलब्ध नहीं है। इसलिए हमें एक समाधान का उपयोग करना होगा जो वर्तमान संस्करणों में काम करता है और भविष्य के संस्करणों में दुर्घटनाग्रस्त होने / टूटने की संभावना को कम करने के लिए बनाया गया है। हम ऐसा समाधान चाहते हैं जो विफल होने पर गल्ती से डिफ़ॉल्ट व्यवहार में वापस आ जाए।
ऐसे कई वैध कारण हैं कि किसी को विकल्प मेनू के लुक को नियंत्रित करने की आवश्यकता हो सकती है (आमतौर पर बाकी ऐप के लिए एक दृश्य शैली से मेल खाने के लिए) इसलिए मैं उस पर ध्यान केंद्रित नहीं करूंगा।
इस बारे में एक Google Android बग पोस्ट किया गया है: कृपया इस बग को अभिनीत करके अपना समर्थन जोड़ें (ध्यान दें कि Google ने मुझे "टिप्पणी": बस एक सितारा पर्याप्त है):
http://code.google.com/p/android/issues/detail?id=4441
समाधान का सारांश:
कई पोस्टरों में LayoutInflater.Factory से जुड़े एक हैक का सुझाव दिया गया है। सुझाए गए हैक ने एंड्रॉइड <= 2.2 के लिए काम किया और एंड्रॉइड 2.3 के लिए विफल हो गया क्योंकि हैक ने एक अनिर्धारित धारणा बनाई: कि कोई व्यक्ति लेआउटइनफ्लाटर.फ्लैट () को सीधे उसी लेआउट लेआउट इनफ्लिटर उदाहरण पर कॉल किए बिना LayoutInflater.getView () को कॉल कर सकता है। एंड्रॉइड 2.3 में नए कोड ने इस धारणा को तोड़ दिया और NullPointerException का नेतृत्व किया।
नीचे मेरी थोड़ी परिष्कृत हैक इस धारणा पर भरोसा नहीं करता है।
इसके अलावा, हैक भी एक स्ट्रिंग के रूप में (जावा प्रकार के रूप में नहीं) एक आंतरिक, अनिर्दिष्ट श्रेणी नाम "com.android.internal.view.menu.IconMenuItemView" का उपयोग करने पर भरोसा करते हैं। मुझे इससे बचने का कोई रास्ता नहीं दिख रहा है और फिर भी बताए गए लक्ष्य को पूरा नहीं कर पा रहा हूं। हालांकि, हैक को सावधानीपूर्वक तरीके से करना संभव है जो "com.android.internal.view.menu.IconMenuItemView" वर्तमान सिस्टम पर प्रकट नहीं होता है।
फिर से, समझ लें कि यह एक हैक है और किसी भी तरह से मैं यह दावा नहीं कर रहा हूं कि यह सभी प्लेटफार्मों पर काम करेगा। लेकिन हम डेवलपर्स एक फंतासी अकादमिक दुनिया में नहीं रह रहे हैं, जहां सब कुछ पुस्तक द्वारा होना है: हमें हल करने के लिए एक समस्या है और हमें इसे सबसे अच्छा हल करना होगा जो हम कर सकते हैं। उदाहरण के लिए, यह संभव नहीं लगता है कि "com.android.internal.view.menu.IconMenuItemView" 3.X गोलियों पर मौजूद होगा क्योंकि वे विकल्प मेनू के बजाय एक्शन बार्स का उपयोग करते हैं।
अंत में, कुछ डेवलपर्स ने एंड्रॉइड ऑप्शन्स मेनू को पूरी तरह से दबाकर और अपनी स्वयं की मेनू क्लास (ऊपर कुछ लिंक देखें) लिखकर इस समस्या को हल किया है। मैंने यह कोशिश नहीं की है, लेकिन यदि आपके पास अपना स्वयं का दृश्य लिखने का समय है और यह पता लगाने का तरीका है कि एंड्रॉइड के दृश्य को कैसे बदला जाए (मुझे यकीन है कि शैतान का विवरण यहां है) तो यह एक अच्छा समाधान हो सकता है जिसमें किसी की आवश्यकता नहीं है अघोषित हैक।
हैक:
यहाँ कोड है।
इस कोड का उपयोग करने के लिए, AddOptionsMenuHackerInflaterFactory () ONCE को आपकी गतिविधि से ONCreate () या आपकी गतिविधि onCreateOptionsMenu () पर कॉल करें। यह एक डिफ़ॉल्ट कारखाना सेट करता है जो किसी भी विकल्प मेनू के बाद के निर्माण को प्रभावित करेगा। यह उन विकल्प मेनू को प्रभावित नहीं करता है जो पहले ही बनाए जा चुके हैं (पिछली हैक्स ने सेटमेन्यूबैकग्राउंड () का एक फ़ंक्शन नाम का उपयोग किया था, जो कि बहुत ही भ्रामक है क्योंकि फ़ंक्शन किसी भी मेनू गुणों को वापस करने से पहले सेट नहीं करता है)।
@SuppressWarnings("rawtypes")
static Class IconMenuItemView_class = null;
@SuppressWarnings("rawtypes")
static Constructor IconMenuItemView_constructor = null;
// standard signature of constructor expected by inflater of all View classes
@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; // use normal inflater
View view = null;
// "com.android.internal.view.menu.IconMenuItemView"
// - is the name of an internal Java class
// - that exists in Android <= 3.2 and possibly beyond
// - that may or may not exist in other Android revs
// - is the class whose instance we want to modify to set background etc.
// - is the class we want to instantiate with the standard constructor:
// IconMenuItemView(context, attrs)
// - this is what the LayoutInflater does if we return null
// - unfortunately we cannot just call:
// infl.createView(name, null, attrs);
// here because on Android 3.2 (and possibly later):
// 1. createView() can only be called inside inflate(),
// because inflate() sets the context parameter ultimately
// passed to the IconMenuItemView constructor's first arg,
// storing it in a LayoutInflater instance variable.
// 2. we are inside inflate(),
// 3. BUT from a different instance of LayoutInflater (not infl)
// 4. there is no way to get access to the actual instance being used
// - so we must do what createView() would have done for us
//
if (IconMenuItemView_class == null)
{
try
{
IconMenuItemView_class = getClassLoader().loadClass(name);
}
catch (ClassNotFoundException e)
{
// this OS does not have IconMenuItemView - fail gracefully
return null; // hack failed: use normal inflater
}
}
if (IconMenuItemView_class == null)
return null; // hack failed: use normal inflater
if (IconMenuItemView_constructor == null)
{
try
{
IconMenuItemView_constructor =
IconMenuItemView_class.getConstructor(standard_inflater_constructor_signature);
}
catch (SecurityException e)
{
return null; // hack failed: use normal inflater
}
catch (NoSuchMethodException e)
{
return null; // hack failed: use normal inflater
}
}
if (IconMenuItemView_constructor == null)
return null; // hack failed: use normal inflater
try
{
Object[] args = new Object[] { context, attrs };
view = (View)(IconMenuItemView_constructor.newInstance(args));
}
catch (IllegalArgumentException e)
{
return null; // hack failed: use normal inflater
}
catch (InstantiationException e)
{
return null; // hack failed: use normal inflater
}
catch (IllegalAccessException e)
{
return null; // hack failed: use normal inflater
}
catch (InvocationTargetException e)
{
return null; // hack failed: use normal inflater
}
if (null == view) // in theory handled above, but be safe...
return null; // hack failed: use normal inflater
// apply our own View settings after we get back to runloop
// - android will overwrite almost any setting we make now
final View v = view;
new Handler().post(new Runnable()
{
public void run()
{
v.setBackgroundColor(Color.BLACK);
try
{
// in Android <= 3.2, IconMenuItemView implemented with TextView
// guard against possible future change in implementation
TextView tv = (TextView)v;
tv.setTextColor(Color.WHITE);
}
catch (ClassCastException e)
{
// hack failed: do not set TextView attributes
}
}
});
return view;
}
});
}
पढ़ने के लिए धन्यवाद, मजा करें!