Android Paint: how to get “airbrush” effect?

后端 未结 3 1519
梦如初夏
梦如初夏 2021-02-04 09:56

I am following the \"FingerPaint\" demo in the API Demos.

I would need to get an \"airbrush\" effect, in the sense that when I draw over the same spot it gets darker and

3条回答
  •  谎友^
    谎友^ (楼主)
    2021-02-04 10:26

    This approach is more of a simulation the way something like Photoshop would do it: Integrate along the path and draw individual paint splashes with an adjustable spacing inbetween.

    enter image description here

    public class DrawView extends View {
    public Paint mPaint;
    
    private Bitmap mBitmap;
    private Canvas mCanvas;
    
    private int strokeRadius;
    private ShapeDrawable mBrush;
    private Paint mBitmapPaint;
    
    private float mPreviousX, mPreviousY;
    
    public DrawView(Context context, AttributeSet attrs) {
        super( context,  attrs);
    
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
    
        int strokeWidth = 20;
    
        strokeRadius = strokeWidth/2;
    
        Shape brushShape = new OvalShape();
    
        mBrush = new ShapeDrawable(brushShape);
    
        Paint paint = mBrush.getPaint();
    
        // radial gradient shader with a transparency falloff, if you don't want this,
        // just set a color on the paint and remove the setShader call
        Shader shader = new RadialGradient(strokeRadius, strokeRadius, strokeRadius,
                Color.argb(255, 0, 0, 0), Color.argb(0, 0, 0, 0), Shader.TileMode.CLAMP);
    
        paint.setShader(shader);
        paint.setAlpha(0x10);
    }
    
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(0xFF00B8F5);
    
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    }
    
    private void touch_start(float x, float y) {
        mPreviousX = x;
        mPreviousY = y;
    }
    
    private void touch_move(MotionEvent event)
    {
        float x = event.getX();
        float y = event.getY();
    
        // get vector from previous to current position
        float xdist = x - mPreviousX;
        float ydist = y - 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. The end point will be drawn by the start point of the
        // next stroke, or by the touch_up method. If we drew both the start and
        // end point there it would be doubled up
        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);
        }
    
        // update the previous position
        mPreviousX = x;
        mPreviousY = y;
    }
    
    private void touch_up(MotionEvent event) {
        drawSplash((int) event.getX(), (int)event.getY());
    }
    
    /**
     * draws the brush to the canvas, centered around x and y
     * @param x
     * @param y
     */
    private void drawSplash(int x, int y)
    {
        mBrush.setBounds(x - strokeRadius, y - strokeRadius, x + strokeRadius, y + strokeRadius);
    
        mBrush.draw(mCanvas);
    
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
    
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touch_start(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            touch_move(event);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            touch_up(event);
            invalidate();
            break;
        }
        return true;
    }
    }
    

    Edit: snap shot (Raghunandan). Result Testing with White Background and Black Color paint.

    enter image description here

提交回复
热议问题