Android: फ़िल्टर के साथ एक StateListDrawable बनाने के लिए एक ड्रॉबल क्लोनिंग


90

मैं एक सामान्य फ्रेमवर्क फंक्शन बनाने की कोशिश कर रहा हूं, जो किसी भी ड्रॉबल को प्रेस / फोकस / सिलेक्टेड / इत्यादि होने पर हाइलाइट किया जाता है

मेरा कार्य एक ड्रॉबल लेता है और एक स्टेटलिस्टड्राइव को लौटाता है, जहां डिफ़ॉल्ट स्थिति ड्रॉबल ही है, और इसके लिए राज्य android.R.attr.state_pressedएक ही ड्रॉबल है, बस एक फ़िल्टर का उपयोग करके लागू किया जाता है setColorFilter

मेरी समस्या यह है कि मैं ड्रॉबल को क्लोन नहीं कर सकता और लागू किए गए फिल्टर के साथ इसका एक अलग उदाहरण बना सकता हूं। यहाँ मैं प्राप्त करने की कोशिश कर रहा हूँ:

StateListDrawable makeHighlightable(Drawable drawable)
{
    StateListDrawable res = new StateListDrawable();

    Drawable clone = drawable.clone(); // how do I do this??

    clone.setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);
    res.addState(new int[] {android.R.attr.state_pressed}, clone);
    res.addState(new int[] { }, drawable);
    return res;
}

यदि मैं क्लोन नहीं करता हूं, तो फ़िल्टर स्पष्ट रूप से दोनों राज्यों पर लागू होता है। मैं के साथ खेलने की कोशिश की, mutate()लेकिन यह मदद नहीं करता है ..

कोई विचार?

अपडेट करें:

स्वीकृत उत्तर वास्तव में एक ड्रॉबल क्लोन करता है। हालांकि इससे मुझे मदद नहीं मिली क्योंकि मेरा सामान्य कार्य एक अलग समस्या पर विफल है। ऐसा लगता है कि जब आप एक स्टेटलिस्ट में एक जोड़ने योग्य जोड़ते हैं, तो यह अपने सभी फिल्टर खो देता है।


नमस्ते, क्या आपको ड्रॉइंग फिल्टर को आकर्षित करने के लिए एक समाधान मिला? मैंने एक ही मुद्दे में भाग लिया है :( मैंने बिटमैप को क्लोन करके और फिल्टर पिक्सेल-बाय-पिक्सेल को लागू करके स्रोत छवि से अन्य छवि तैयार की है। हां, यह अक्षम है, लेकिन मेरे पास एक बार संसाधित छोटी छवियों का एक गुच्छा है।
port443

मैं इसे StateListDrawable के साथ हल नहीं कर सका, लेकिन यदि आप StateListDrawable का उपयोग नहीं कर रहे हैं और अभी भी अपने फ़िल्टर खो रहे हैं, तो सुनिश्चित करें कि आपके बिटमैप परस्पर हैं। संबंधित अच्छे प्रश्न हैं: stackoverflow.com/questions/5499637/… , मैंने यह भी पता लगाया है कि लाइटकॉर्नरफिल्टर उन जगहों पर काम करता है जहां पोर्टरडफ विफल रहता है .. इस एंड्रॉइड को
लॉरिन करें

इस लिंक पर एक शानदार जवाब stackoverflow.com/questions/10889415/…
एलन

इससे एक समान दुष्प्रभाव उत्पन्न होता है ImageView.setImageDrawable, जिसे मैं स्वीकृत उत्तर के लिए धन्यवाद के आसपास काम करने में सक्षम था।
Giulio Piancastelli

मैं एक ही काम करने की कोशिश कर रहा हूं और यह किसी भी तरह से उम्मीद के मुताबिक काम करता है, ColorFilter खो नहीं गया ... अंतर यह है कि मैंने ड्रॉबल को म्यूट किया।
हेनरी

जवाबों:


162

निम्नलिखित प्रयास करें:

Drawable clone = drawable.getConstantState().newDrawable();

1
धन्यवाद! यह विधि एक ड्रॉबल को सफलतापूर्वक क्लोन करने में लगती है। जिस फ़ंक्शन को मैं लिखने की कोशिश कर रहा था, वह काम नहीं करता है .. ऐसा लगता है कि जब एक ड्रॉबल को स्टेटलिस्ट में डाला जाता है तो वह अपने फिल्टर खो देता है :(
talkol

3
+1 ने मुझे मैप व्यू में एक बहुत ही अजीब त्रुटि को ठीक करने में मदद करने के लिए जहां एक अलर्ट में आइटम ItemizedOverlay से फिर से उपयोग करने पर ट्रिगर किया, जब ItemizedOverlay कदम बनाया। ड्रॉबल का एक नया उदाहरण बनाने से समस्या ठीक हो गई।
kskjon

9
सही ढंग से काम करने के लिए, अगर हम setAlpha विधि का उपयोग करने की कोशिश करते हैं। इस मामले में, दोनों ड्रा करने योग्य परिवर्तन बिटमैप। फिर मुझे पहले ड्रा करने योग्य मिलता है जैसे: getResources ()। GetDrawable (), दूसरा as: getResources ()। GetDrawable ()। Mutate ()।
यूरा शिनकरेव

बहुत बहुत धन्यवाद, यह उस समस्या को ठीक करता है जब मैंने एपीआई मैपफोर्ज से एक बाउंडिंग फ़ंक्शन लागू किया था। अब मैं हर जगह ड्रॉ का उपयोग कर सकता हूँ!
xarlymg89

17
@ फेलियो - मैंने इसे एक कलर फिल्टर के साथ आज़माया, लेकिन इसने मेरे ड्रॉबल के सभी उदाहरणों को रंगीन कर दिया! यह पता चला है कि ऐसा लगता है कि आपको उपयोग करना होगा .mutate()(मेरा उत्तर देखें)।
पीटर Ajtai

104

यदि आप एक फिल्टर / आदि के साथ बनाए गए एक ड्रॉबल पर लागू करते हैं, getConstantState().newDrawable()तो ड्रॉबल के सभी उदाहरणों को भी बदल दिया जाएगा, क्योंकि ड्रॉइबल्स constantStateकैश के रूप में उपयोग करते हैं !

इसलिए यदि आप कलर फिल्टर और ए का उपयोग करके एक सर्कल को रंग देते हैं, तो आप सभी सर्कल का रंग newDrawable()बदल देंगे।

यदि आप इस आकर्षित करने योग्य अद्यतन को अन्य उदाहरणों को प्रभावित किए बिना बनाना चाहते हैं, तो आपको उस मौजूदा स्थिर स्थिति को बदलना होगा।

// To make a drawable use a separate constant state
drawable.mutate()

एक अच्छी व्याख्या के लिए देखें:

http://www.curious-creature.org/2009/05/02/drawable-mutations/

http://developer.android.com/reference/android/graphics/drawable/Drawable.html#mutate ()


वास्तव में म्यूटेट () उसी सटीक उदाहरण को वापस करता है, लेकिन इसकी आंतरिक स्थिति को बदल दिया जाता है इसलिए रंग फ़िल्टर लागू करने से अन्य उदाहरण प्रभावित नहीं होंगे। क्या आप अपने जवाब की समीक्षा कर सकते हैं?
10

1
यदि आप रंग परिवर्तन के सभी उदाहरणों का उपयोग नहीं करते हैं, तो @ Clemp6r - आपको केवल क्लोन का रंग बदलने के लिए म्यूट को कॉल करने की आवश्यकता है
पीटर अज़ताई

2
API रेफरी की जाँच करें ("यह ड्रॉबल म्यूटेबल बनाएं। - यह ड्रॉबल लौटाता है") और सोर्स कोड ("इसे वापस करें")। कॉलिंग म्यूट () की आवश्यकता है, लेकिन लौटा हुआ उदाहरण समान है। यह एक क्लोन नहीं बनाता है, यह केवल ड्रा करने योग्य उदाहरण की आंतरिक स्थिति को बदलता है, जिससे एक ही ड्रॉबल के अन्य उदाहरणों को प्रभावित किए बिना इसे संशोधित करने की अनुमति मिलती है।
9

वैसे मैं इस सवाल के बारे में नहीं जानता, लेकिन यह जवाब मुझे ठीक वही चाहिए जो मुझे चाहिए ... tU
एवरेन ओज़टर्क

1
वे सबसे अच्छे लिंक हैं, जिन्हें आपने संदर्भ के लिए दिया है
अशोक वर्मा

15

मेरे लिए यही काम करता है।

Drawable clone = drawable.getConstantState().newDrawable().mutate();

हाँ, मैं नहीं जानता कि यह केवल क्यों है, लेकिन यह संयोजन नयाड्राएबल () और म्यूटेट () मेरे लिए किसी अन्य एकल म्यूटेट () या एकल न्यूडेबल () के लिए काम करता है, जो मेरे लिए सही ढंग से काम नहीं करता है
माइकेल ज़ियोब्रो

12

यह मेरा समाधान है, इस एसओ प्रश्न पर आधारित है ।

विचार यह है कि ImageViewजब उपयोगकर्ता इसे छूता है तो रंग फ़िल्टर हो जाता है, और उपयोगकर्ता द्वारा इसे छूने से रोकने पर रंग फ़िल्टर हटा दिया जाता है। केवल 1 ड्रॉएबल / बिटमैप मेमोरी में है, इसलिए इसे बेकार करने की आवश्यकता नहीं है। यह उसी तरह काम करता है, जैसा उसे करना चाहिए।

class PressedEffectStateListDrawable extends StateListDrawable {

    private int selectionColor;

    public PressedEffectStateListDrawable(Drawable drawable, int selectionColor) {
        super();
        this.selectionColor = selectionColor;
        addState(new int[] { android.R.attr.state_pressed }, drawable);
        addState(new int[] {}, drawable);
    }

    @Override
    protected boolean onStateChange(int[] states) {
        boolean isStatePressedInArray = false;
        for (int state : states) {
            if (state == android.R.attr.state_pressed) {
                isStatePressedInArray = true;
            }
        }
        if (isStatePressedInArray) {
            super.setColorFilter(selectionColor, PorterDuff.Mode.MULTIPLY);
        } else {
            super.clearColorFilter();
        }
        return super.onStateChange(states);
    }

    @Override
    public boolean isStateful() {
        return true;
    }
}

उपयोग:

Drawable drawable = new FastBitmapDrawable(bm);
imageView.setImageDrawable(new PressedEffectStateListDrawable(drawable, 0xFF33b5e5));

मेरे लिए भी काम करता है! Thats एक दिलचस्प समाधान, धन्यवाद!) PS android बेकार है, ठीक से काम नहीं कर रहे खराब एपीआई :(
एंटोन Kizema

मुझे लगता है कि यह (StateListDrawable + BitmapDrawable) बग को हल करने के लिए अब तक का सबसे अच्छा समाधान है!
ज़ेवियर।

1

मैंने संबंधित प्रश्न का उत्तर यहां दिया

मूल रूप से ऐसा लगता है कि StateListDrawables वास्तव में अपने फ़िल्टर खो देते हैं। मैंने बिटमैप की एक बदली हुई कॉपी से एक नया BitmapDrawale बनाया, जिसे मैं मूल रूप से उपयोग करना चाहता था।



0

क्लोन का उपयोग करने योग्य प्राप्त करें, newDrawable()लेकिन यह सुनिश्चित करें कि यह परिवर्तनशील है अन्यथा आपका क्लोन प्रभाव चला गया है, मैंने कोड की इन कुछ पंक्तियों का उपयोग किया है और यह अपेक्षित रूप से काम कर रहा है। getConstantState()एनोटेशन द्वारा सुझाए गए अनुसार अशक्त हो सकते हैं, इसलिए जब आप ड्रॉबल क्लोनिंग करते हैं तो इस रनटाइम एक्सेप्शन को संभाल लें।

Drawable.ConstantState state = d.mutate().getConstantState();
if (state != null) {
    Drawable drawable = state.newDrawable().mutate();
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.