2013-10-17 5 views
11

मैंने एक सर्कल बटन बनाया जो एक फ़ंक्शन कॉल करते समय उसका रंग बदल सकता है। मैं जो चाहता हूं वह एक और बनाना है, जो एक ही सर्कल बटन बनाता है लेकिन एक रेडियल ग्रेडियेंट के साथ जो रंग में चयनित रंग के साथ शुरू होता है और जब आप सर्कल से बाहर जाते हैं तो पारदर्शी हो जाता है।कैनवास में रेडियल ढाल के साथ एक सर्कल कैसे आकर्षित करें?

मैंने How to set gradient style to paint object? पर पोस्ट किए गए एक का उपयोग कर एक समान कोड बनाया लेकिन काम नहीं किया।

कोड है कि मैं करने की कोशिश की इस porpuse लिए है:

mPaint.setShader(new RadialGradient(0, 0, height/3, Color.BLACK, Color.TRANSPARENT, Shader.TileMode.MIRROR)); 

निम्नलिखित वर्ग एक है कि मैं एक सर्किल बटन के लिए बनाई गई है।

public class ColorGradientCircleButton extends View{ 

private Paint mPaint; 
private Paint mBitmapPaint; 
private Bitmap mBitmap; 
private Canvas mCanvas; 
private int width, height; 

public ColorGradientCircleButton(Context context) { 
    super(context); 
    init(); 
} 
public ColorGradientCircleButton(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    init(); 
} 
public ColorGradientCircleButton(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    init(); 
} 
private void init() { 
    mPaint = new Paint(); 
    mPaint.setColor(Color.BLACK); 
    mPaint.setStrokeWidth(1); 
    mPaint.setStyle(Paint.Style.FILL_AND_STROKE); 
    mBitmapPaint = new Paint(Paint.DITHER_FLAG); 
} 
@Override 
protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
    super.onSizeChanged(w, h, oldw, oldh); 
    width = w; 
    height = h; 
    mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
    mCanvas = new Canvas(mBitmap); 
    mCanvas.drawCircle(w/2, h/2, h/3, mPaint); 
} 
@Override 
protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); 
} 
public void changeColor(int color){ 
    mPaint.setColor(color); 
    mCanvas.drawCircle(width/2, height/2, height/3, mPaint); 
    invalidate(); 
} 
} 
+1

अरे ग्रेब्रियल। यह कोड तकनीकी रूप से बहुत ही आशाजनक दिखता है। मैं सकारात्मक हूं कि हम इसे सही कर सकते हैं। सबसे पहले, आप 'ऑनसाइज चेंज' में बिटमैप क्यों बना रहे हैं? 'Andorid.graphics' के साथ कस्टम व्यू बनाते समय, उस दृश्य के कैनवास पर सीधे आकर्षित करने की आवश्यकता होनी चाहिए। आप उस विधि में क्या करते हैं वह अविश्वसनीय रूप से महंगा है और आवश्यक नहीं है। आपको 'ऑनड्रा' दिए गए कैनवास का उपयोग करके सर्कल खींचना चाहिए। यदि यह आपकी समस्या को हल करने के लिए पर्याप्त नहीं है, तो मैं कुछ और विस्तार से पोस्ट करूंगा। – Tom

+0

हाय टॉम, मैंने बिटमैप बनाया क्योंकि मुझे लगता है कि इसके साथ मैं दृश्य की चौड़ाई और ऊंचाई को नियंत्रित कर सकता हूं। इसलिए, मैंने बिटमैप को हटाने, अपने सुधार जोड़ने के लिए दृश्य को संशोधित किया लेकिन कुछ अच्छी तरह से काम नहीं करता है। वह मेरा कोड है https://gist.github.com/galaxyfeeder/7026090 –

+0

हाय फिर से, मुझे मिल गया, मैं कन्स्ट्रक्टर में चौड़ाई और ऊंचाई का अनुरोध कर रहा था, लेकिन ऑन ड्रा को पहले निष्पादित किया गया है, इसलिए मैं अनुरोध करता हूं कि मैं क्या करूँ 'ऑनड्रा' में दृश्य की ऊंचाई और चौड़ाई, यहां मेरा वास्तविक कोड है जो अच्छी तरह से काम करता है: https://gist.github.com/galaxyfeeder/7026165 –

उत्तर

18

हमें इसे उत्तर बॉक्स में माइग्रेट करना चाहिए।

ओपी मूल रूप से इसे यहां मिला है- और वास्तव में ओपी का संशोधित gist शानदार है। सवाल में पहले ही प्रयास के बारे में

कुछ सामान्य टिप्स:

1) protected void onSizeChanged(int w, int h, int oldw, int oldh) में:

  • width = w; कोई कारण नहीं क्यों आप getWidth() फोन नहीं कर सकते हैं जब आप इस आवश्यकता होती है। इसका कारण यह है कि View की आंतरिक चौड़ाई onMeasure के बाद काफी देर हो चुकी है। नतीजतन, onDraw अगली बार जब आप सबसे अद्यतित संस्करण चाहते हैं, तो वहां गेटर का उपयोग करें।
  • mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);। बिटमैप बनाना एक महंगा और स्मृति गहन ऑपरेशन है। जब तक आप किसी फ़ाइल में बिटमैप लिखना नहीं चाहते हैं, या इसे पर ImageView या कुछ के लिए भेजना चाहते हैं, तो आपको ऐसा करने की आवश्यकता नहीं है। विशेष रूप से एंड्रॉइड के graphics लाइब्रेरी के साथ UI पर खींचे गए प्रभावों के साथ।
  • mCanvas = new Canvas(mBitmap); नए कैनवास पर ड्रॉ ऑपरेशन के बाद। इसकी कभी आवश्यकता नहीं है। और फिर भी मैंने इसे कई कोड अड्डों और प्रयासों में देखा है (काम नहीं)। I सोचें यह पुरानी स्टैक ओवरफ़्लो पोस्ट की गलती है जिसने लोगों को ऐसा करने के लिए किया है ताकि वे कैनवास के बाकी हिस्सों पर ड्राइंग को प्रभावित किए बिना कस्टम दृश्य पर कैनवास को बदल सकें। संयोग से, अगर आपको इसकी आवश्यकता है, तो इसके बजाय .restore() और .save() का उपयोग करें। यदि आप new Canvas देखते हैं, संदिग्ध देखें।

2) onDraw(...):

  • हाँ, आप की तरह onDraw में बातें कर रही है, से बचने के लिए, वस्तुओं बनाने या किसी भारी प्रसंस्करण की जरूरत है,। लेकिन आपको अभी भी onDraw में चीजों को करने की आवश्यकता है, आपको onDraw में करना होगा!
  • तो यहां आपको के अनुसार तर्कों के साथ: canvas.drawCircle(float cx, float cy, float radius, Paint paint) पर कॉल करने की आवश्यकता है।
  • यह वास्तव में onDraw के लिए पापपूर्ण नहीं है।यदि आप इसे बहुत अधिक पर कॉल करने के बारे में चिंतित हैं, तो यदि आपका पूरा बटन स्क्रीन पर एनिमेट हो रहा है, तो आपको hardware acceleration का उपयोग बाद के एपीआई संस्करणों में उपलब्ध करना होगा, जैसा कि Optimizing the View नामक आलेख में विस्तृत किया जाएगा; यदि आप बहुत सारे कस्टम खींचे गए विचारों का उपयोग कर रहे हैं तो बहुत उपयोगी पढ़ना।

3) वह उग्र रेडियल ढाल। आपके पास अगला मुद्दा यह है कि आपने अपने पेंट को init विधि में सही तरीके से बनाया है ताकि ऑब्जेक्ट निर्माण ड्रॉ से बाहर हो। लेकिन फिर सही है कि इसमें IllegalArgumentException एड (मुझे लगता है) आपके लिए होगा क्योंकि उस चरण में getHeight() दृश्य था 0. आपने छोटे पिक्सेल मानों में गुजरने की कोशिश की- यह तब तक काम नहीं करेगा जब तक आप स्क्रीन आकारों के बारे में कुछ जादू नहीं जानते।

यह एंड्रॉइड के डिजाइन पैटर्न के दिल में कष्टप्रद दृश्य चक्र जितना अधिक मुद्दा नहीं है। हालांकि फिक्स काफी आसान है: पेंट फ़िल्टर सेट करने के लिए onMeasure कॉल के बाद बस दृश्य की ड्राइंग प्रक्रिया के बाद के हिस्से का उपयोग करें।

लेकिन वहाँ यह सही है, अर्थात् है कि कभी कभी, annoyingly, onDraw बिंदु है जिस पर आप इसकी अपेक्षा से पहले कहा जाता हो जाता है हो रही है के साथ कुछ मुद्दों कर रहे हैं। परिणाम आपका पेंट शून्य होगा और आपको वांछित व्यवहार नहीं मिलेगा।

मैं एक और अधिक मजबूत समाधान पाया है onDraw में एक मुखर और शरारती थोड़ा अशक्त जांच करने के लिए और फिर एक बार केवल वहाँ रंग वस्तु का निर्माण बस है। यह सख्ती से इष्टतम बात नहीं कर रहा है, लेकिन जटिल तरीके से दिया गया है जिसमें Paint ऑब्जेक्ट्स एंड्रॉइड के ग्राफिक्स देशी परत के साथ कई बार बुलाए गए स्थानों में पेंट कॉन्फ़िगरेशन और निर्माण को स्ट्रैडल करने की कोशिश करने से बेहतर हैं। और यह स्पष्ट स्पष्ट कोड बनाता है।

इस तरह (अपने सार में संशोधन) दिखेगा:

 @Override 
     protected void onDraw(final Canvas canvas) { 
      super.onDraw(canvas); 
      if (mPaint == null) { 
       mPaint = new Paint(); 
       mPaint.setColor(Color.BLACK); 
       mPaint.setStrokeWidth(1); 
       mPaint.setStyle(Paint.Style.FILL_AND_STROKE); 
       mPaint.setShader(new RadialGradient(getWidth()/2, getHeight()/2, 
         getHeight()/3, Color.TRANSPARENT, Color.BLACK, TileMode.MIRROR)); 
      } 
      width = getWidth(); 
      height = getHeight(); 
      canvas.drawCircle(width/2, height/2, height/3, mPaint); 
     } 

तो कुछ बदलाव मैं अपने विवरण से लगता है ध्यान दें कि आप दो रंगों बहस में दौर बदली चाहते हैं, भी केंद्र के लिए मत भूलना आपके दृश्य में आपके ढाल का केंद्र: width/2 और height/2 तर्क।

शुभकामनाएँ!

+0

सभी के लिए धन्यवाद, मुझे लगता है कि मैंने इस प्रश्न के साथ और अधिक सीखा है और आप सभी ट्यूटोरियल्स के साथ जो मैंने ड्राइंग और कैनवास के बारे में पढ़ा या देखा है। –

+1

ओह मुझे नहीं पता। मैंने पूरी तरह से हर गलती की है, मुझे लगता है कि कम से कम हर किसी को – Tom

+1

नहीं होना चाहिए, बहुत अच्छा, मुझे अलग-अलग res drawables का एक गुच्छा बनाने से बचाया। और जब पेंट की आलसी तात्कालिकता पहले ड्रॉ को थोड़ा धीमा कर सकती है, तो यह वास्तव में एक छोटी सी कीमत है जो स्वयं को निहित करने के लिए भुगतान करती है। धन्यवाद टॉम और गेब्रियल! –

संबंधित मुद्दे