2013-10-17 80 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

嘿Grabriel。這段代碼在技術上看起來很有前景。我很積極,我們可以糾正它。首先,你爲什麼要在'onSizeChanged'中創建一個位圖?使用'andorid.graphics'創建自定義視圖時,只需要直接繪製該視圖的畫布。你用這種方法做的事情非常昂貴而且沒有必要。您應該使用給定'onDraw'的畫布繪製圓。如果這還不足以解決您的問題,我會更詳細地發佈一些內容。 – Tom

+0

嗨,湯姆,我創建了位圖,因爲我認爲可以控制視圖的寬度和高度。所以,我修改了視圖以添加您的改進,刪除了位圖,但有些效果不佳。她是我的代碼https://gist.github.com/galaxyfeeder/7026090 –

+0

嗨,我明白了,我在構造函數中請求寬度和高度,但是onDraw是首先執行的,所以我要做的是請求'onDraw'中視圖的高度和寬度,這裏是我的實際代碼,效果很好:https://gist.github.com/galaxyfeeder/7026165 –

回答

18

我們應該將其遷移到答案框中。

OP基本上已經在這裏 - 實際上OP的修訂gist是輝煌的。

關於這個問題的第一次嘗試一些一般提示:

1)protected void onSizeChanged(int w, int h, int oldw, int oldh)

  • width = w;沒有理由爲什麼你不能叫getWidth()當你需要這個。建議的原因是View的內部寬度設置在onMeasure之後很晚。因此,onDraw可能是您想要最新版本的下一次,因此請在此處使用getter。
  • mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);。創建一個位圖是一個昂貴且佔用大量內存的操作。除非你想寫一個位圖到一個文件,或者把它發送到BitmapDrawableImageView什麼的,你不需要這樣做。尤其是使用android的graphics庫在UI上繪製的效果。
  • mCanvas = new Canvas(mBitmap);然後在新畫布上進行繪製操作。這是不需要的。然而,我在許多代碼庫和嘗試中都看到了它(不起作用)。我認爲這是一箇舊的堆棧溢出帖子的過錯,讓人們這樣做,以便他們可以在自定義視圖上轉換畫布而不影響畫布的其餘部分。順便說一句,如果你需要這個,請使用.restore().save()。如果您看到new Canvas可疑

2)onDraw(...)

  • ,你需要避免在onDraw做的事情,比如,創建對象,或任何重處理。 但是您還需要在onDraw中做些事情,您需要在onDraw
  • 所以在這裏你只需要撥打canvas.drawCircle(float cx, float cy, float radius, Paint paint)參數根據docs
  • 這對onDraw來說確實不算什麼罪。如果您擔心調用太多(如果您的整個按鈕在整個屏幕上進行動畫製作,可能會出現這種情況),您需要使用後面的API版本中提供的hardware acceleration,這將在名爲Optimizing the View的文章中詳述;如果您使用大量自定義繪製視圖,閱讀非常有幫助。

3)那討厭的徑向梯度。下一個問題是,你在init方法中正確創建了繪畫,以便創建對象。但是很正確的,它會有IllegalArgumentException ed(我認爲)在你身上,因爲在那個階段,視圖的getHeight()是0.你嘗試傳遞小像素值 - 除非你知道關於屏幕尺寸的一些魔術,否則它將不起作用。

這不像你設計模式的核心問題那樣令人討厭。修復雖然很簡單:只需在onMeasure調用設置畫筆過濾器之後使用視圖繪製過程的稍後部分即可。

也有一些問題,得到這個權利,即有時,煩人,onDraw得到你希望它在該點之前調用。結果將是你的油漆是空的,你不會得到所需的行爲。

我發現了一個更強大的解決方案,就是簡單地在onDraw中做一個厚臉皮和頑皮的小空檢查,然後一次只有在那裏構建繪畫對象。這並不是嚴格意義上的最佳解決方案,但考慮到Paint對象與Android的圖形原生層掛鉤的複雜方式,比在許多頻繁調用的位置跨越繪畫配置和構造更好。這使得代碼更清晰。

這看起來像(修改您的要點):

 @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); 
     } 

所以注意幾點changes-我想從你的描述你想要的兩種顏色在參數輪交換,也不要忘記中心您的視圖中的漸變中心:width/2height/2參數。

祝你好運!

+0

感謝大家,我認爲我通過這個問題學到了更多東西,並且你閱讀了所有關於繪圖和畫布的教程。 –

+1

哦,我不知道。我絕對犯了每一個錯誤,我只認爲至少其他人不應該要 – Tom

+1

非常好,讓我無需創建一堆不同的res drawables。雖然油漆的懶惰實例化可能會導致第一次繪製稍微慢一些,但對於onDraw自包含而言,這實在是很小的代價。謝謝湯姆和加百列! –