DrawingView with share image in Sketchware Pro
1. This example shows how to create a DrawingView in Sketchware.
2. Create a new project in Sketchware.
3. Switch On AppCompat and design.
4. In View manager, deselect toolbar for main.xml.
5. In java/Kotlin manager:
a. Add a file DrawingView.java and put following codes in it.
package com.sanju.drawingview;
import android.view.View;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Canvas;
import android.content.Context;
import android.util.AttributeSet;
import android.graphics.Color;
import android.view.MotionEvent;
import android.graphics.PorterDuff;
import java.util.ArrayList;
public class DrawingView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Paint mBitmapPaint;
private Paint mPaint;
private Paint circlePaint;
private Path circlePath;
private Path mPath;
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private ArrayList<PathPaint> all_paths = new ArrayList<>();
public DrawingView(Context context) {
super(context);
init();
}
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6f);
circlePath = new Path();
circlePaint = new Paint();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeWidth(1f);
}
@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) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
canvas.drawPath(circlePath, circlePaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
invalidate();
break;
case MotionEvent.ACTION_MOVE:
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;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
}
invalidate();
break;
case MotionEvent.ACTION_UP:
mPath.lineTo(mX, mY);
circlePath.reset();
Path p = new Path(mPath);
Paint pnt = new Paint(mPaint);
all_paths.add(new PathPaint(p, pnt));
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
invalidate();
break;
}
return true;
}
public void undo() {
if (all_paths.size() > 0) {
all_paths.remove(all_paths.size() - 1);
}
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (PathPaint pp : all_paths) {
mCanvas.drawPath(pp.getPath(), pp.getPaint());
}
invalidate();
}
// Clear all drawings
public void clear() {
all_paths.clear();
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
invalidate();
}
// Set stroke width
public void setStrokeWidth(float width) {
mPaint.setStrokeWidth(width);
}
// Set stroke color
public void setStrokeColor(int color) {
mPaint.setColor(color);
}
}
b. Add another file PathPaint.java and put following codes in it.
package com.sanju.drawingview;
import android.graphics.Paint;
import android.graphics.Path;
public class PathPaint {
private Path path;
private Paint paint;
public PathPaint(Path path, Paint paint) {
this.path = path;
this.paint = paint;
}
public Path getPath() {
return path;
}
public Paint getPaint() {
return paint;
}
}
c. Add another file SaveUtils.java and put following codes in it.
package com.sanju.drawingview;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.view.View;
import android.widget.Toast;
import androidx.core.content.FileProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public final class SaveUtils {
private SaveUtils() {
// Utility class
}
/**
* Converts a View into a Bitmap
*/
public static Bitmap viewToBitmap(View view) {
Bitmap bitmap = Bitmap.createBitmap(
view.getWidth(),
view.getHeight(),
Bitmap.Config.ARGB_8888
);
Canvas canvas = new Canvas(bitmap);
Drawable background = view.getBackground();
if (background != null) {
background.draw(canvas);
} else {
canvas.drawColor(Color.WHITE);
}
view.draw(canvas);
return bitmap;
}
/**
* Saves bitmap to internal storage
*/
public static File saveBitmap(Context context, Bitmap bitmap) {
if (context == null || bitmap == null) return null;
File imageFile = new File(context.getFilesDir(), "temp_drawing.png");
try (FileOutputStream fos = new FileOutputStream(imageFile)) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
return imageFile;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
if (!bitmap.isRecycled()) {
bitmap.recycle();
}
}
}
/**
* Shares image using FileProvider
*/
public static void shareImage(Context context, File imageFile) {
if (context == null || imageFile == null || !imageFile.exists()) return;
try {
Uri imageUri = FileProvider.getUriForFile(
context,
context.getPackageName() + ".provider",
imageFile
);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("image/*");
shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(
Intent.createChooser(shareIntent, "Share image via")
);
} catch (IllegalArgumentException e) {
Toast.makeText(context,
"FileProvider error: " + e.getMessage(),
Toast.LENGTH_SHORT).show();
} catch (ActivityNotFoundException e) {
Toast.makeText(context,
"No app available to share image",
Toast.LENGTH_SHORT).show();
}
}
}
6. In main.xml, add a Linear Horizontal containing 6 ImageViews image_strokecolor, image_strokewidth, image_background, image_undo, image_delete, image_download.
Below this, add a Linear Vertical with width and height match_parent. Convert it to com.sanju.drawingview.DrawingView (Replace com.sanju.drawingview with your package name). Also change its ID to drawingView.
7. In AndroidManifest manager, in App Components, put following codes:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
8. In Resource manager, create a folder xml and inside this create a file file_paths.xml. Put following codes in it.
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="internal_files"
path="." />
</paths>
9. Create a more block, showStrokeWidthDialog and put following codes in it.
String[] sizes = {"4", "8", "12", "16", "20"};
new AlertDialog.Builder(this)
.setTitle("Select Stroke Width")
.setItems(sizes, (d, i) ->
binding.drawingView.setStrokeWidth(Float.parseFloat(sizes[i])))
.show();
10. In event image_strokewidth onClick, use the more block showStrokeWidthDialog.
11. Create another more block showStrokeColorDialog and put following codes in it.
int[] colors = {
Color.BLACK, Color.RED, Color.BLUE,
Color.GREEN, Color.YELLOW
};
String[] names = {"Black", "Red", "Blue", "Green", "Yellow"};
new AlertDialog.Builder(this)
.setTitle("Select Stroke Color")
.setItems(names, (d, i) ->
binding.drawingView.setStrokeColor(colors[i]))
.show();
12. In event image_strokecolor onClick, use the more block showStrokeColorDialog.
13. Create a more block, showBackgroundColorDialog and put following codes in it.
int[] colors = {
Color.WHITE, Color.LTGRAY,
Color.YELLOW, Color.CYAN
};
String[] names = {"White", "Gray", "Yellow", "Cyan"};
new AlertDialog.Builder(this)
.setTitle("Select Background Color")
.setItems(names, (d, i) ->
binding.drawingView.setBackgroundColor(colors[i]))
.show();
14. In event image_background onClick, use the more block showBackgroundColorDialog.
15. In the event image_undo onClick, use following codes.
binding.drawingView.undo();
16. In the event image_delete onClick, use following codes.
binding.drawingView.clear();
17. In the event image_download onClick, use following codes.
Bitmap bitmap = SaveUtils.viewToBitmap(binding.drawingView);
File savedImage = SaveUtils.saveBitmap(getApplicationContext(), bitmap);
SaveUtils.shareImage(MainActivity.this, savedImage);
18. In Build Settings, select D8 and java version 1.8 and save.
19. Run the project.



Comments
Post a Comment