Reputation: 125
The default is SolidLine, I can start drawing, switch to Airbrush, and everything looks fine. If I switch back to SolidLine, the Airbrush draws disappear, but the previous SolidLine draws remain. If I then switch back to Airbrush, the previous Airbrush draw reappear, and the previous SolidLine draws remain. In the function touch_up(event), in (line_type == SOLID_LINE), if I comment out
//mCanvas.drawPath(mPath, mPaint);
then When I select Airbrush the SolidLine draws disappear, and reapear when I select back to SolidLine, while as usual Airbrush draw disappear. So it seems clear to me that I need to get my Airbrush draws onto the onDraw Canvas, but I've not been able to get that to work, trying a variety of things focussing on trying to draw the Bitmap mSourceBM used to initialize mCanvas, onto the onDraw Canvas canvas.
Any ideas would be greatly appreciated!
My onDraw function
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(line_type == SOLID_LINE){
for (Pair<Path, Paint> p : paths) {
canvas.drawPath(p.first, p.second);
}
canvas.drawPath(mPath, mPaint);
}else if(line_type == AIRBRUSH){
Log.d(DTAG, "onDraw: AIRBRUSH: no call");
canvas.drawBitmap(mSourceBM, 0,0, null);
}
}
My init function, for context
private void init(AttributeSet attrs, int defStyle) {
if(line_type == SOLID_LINE){
setSolidLine(); // various paint settings
}else if(line_type == AIRBRUSH){
setAirbrush(); // other paint settings
}
}
Here's the drawSpalsh function that is fired multiple times in touch_move, and once in touch up. It draws a paint with a radial gradient, and a radius of have half the Paint Stroke width at point (x,y). invalidate() is called in onTouchEvent after each touch_move(x,y), touch_start(x,y), and touch_up(event) call.
private void drawSplash(int x, int y)
{
mBrush.setBounds(x - strokeRadius, y - strokeRadius, x + strokeRadius, y + strokeRadius);
mBrush.draw(mCanvas);
//mPaint = mBrush.getPaint();
//mCanvas.drawBitmap(mSourceBM, x, y, mPaint);
//mCanvas.drawPaint(mPaint);
}
touch_start, called from onTouchEvent
private void touch_start(float x, float y) {
if(line_type == SOLID_LINE){
undonePaths.clear();// we clear the undonePaths because we are drawing
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}else if(line_type == AIRBRUSH){
mPreviousX = x;
mPreviousY = y;
Log.d(DTAG, "touch_start");
}
}
touch_move called from onTouchEvent
private void touch_move(float x, float y) {
if(line_type == SOLID_LINE){
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
// displayMemoryUsage("touch_move SOLID");
}else if(line_type == AIRBRUSH){
float mX = x;
float mY = y;
// get vector from previous to current position
float xdist = mX - mPreviousX;
float ydist = mY - mPreviousY;
// get the length
float segmentLength = (float) Math.sqrt(xdist * xdist + ydist * ydist);
// derive a suitable step size from stroke width
float stepSize = Math.max(strokeRadius / 10, 1f);
// calculate the number of steps we need to take
// NOTE: this draws a bunch of evenly spaced splashes from the start point
// to JUST BEFORE the end point.
int steps = Math.max(Math.round(segmentLength / stepSize), 2);
for(int i = 0; i < steps; ++i)
{
int currentX = (int) (mPreviousX + xdist * i / steps);
int currentY = (int) (mPreviousY + ydist * i / steps);
drawSplash(currentX, currentY);
}
//Log.d(DTAG, "touch_move: AIRBRUSH xdist, ydist: "+xdist+" "+ydist);
// update the previous position
mPreviousX = mX;
mPreviousY = mY;
//displayMemoryUsage("touch_move AIR");
//Log.d(DTAG, "touch_move AIR: previous x y "+mX+" "+mY);
}
}
touch_up called from onTouchEvent
private void touch_up(MotionEvent event) {
if(line_type == SOLID_LINE){
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
Paint newPaint = new Paint(mPaint);
paths.add(new Pair<Path, Paint>(mPath, newPaint));
mPath = new Path();
}else if(line_type == AIRBRUSH){
drawSplash((int) event.getX(), (int)event.getY());
}
}
the Activity sets the Bitmap. Actually I don't use the BitmapDrawable. Just the Bitmap to initialize the Airbrush canvas mCanvas.
/**
* Sets the Canvas Bitmap we intend to modify
*/
public boolean setCanvasBitmapDrawable(BitmapDrawable bitmapdrawable, Bitmap sourceBM, int left_bound, int top_bound) {
// supply bounds as parameters
mSourceBM = sourceBM;
// mSourceBM = convertToMutable(this, mSourceBM);
bmDrawable = bitmapdrawable;
mCanvas = new Canvas(mSourceBM);
//bmDrawable.setBounds(left_bound, top_bound, bitmapdrawable.getIntrinsicWidth()+left_bound, bitmapdrawable.getIntrinsicHeight()+top_bound);
invalidate();
return true;
}
Upvotes: 0
Views: 292
Reputation: 1712
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (Pair<Path, Paint> p : paths) {
canvas.drawPath(p.first, p.second);
}
canvas.drawPath(mPath, mPaint);
Log.d(DTAG, "onDraw: AIRBRUSH: no call");
canvas.drawBitmap(mSourceBM, 0,0, null);
}
the ifs in the above statement make it draw only one or the other. take them out of ondraw, the if statements in your ontouch will suffice to show which type your using, and it should work fine
Upvotes: 0