2013-10-17 51 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自包含而言,这实在是很小的代价。谢谢汤姆和加百列! –