I want to be able to edit photos, allowing a user to put annotations on a photo they have captured. I am fine with Portrait photos, but Landscape photos are causing me major problems. The problem is that the drawing area ends up being the entire layout and I just want the photo boundaries to be editable (drawable). How do I do this? Portrait is ok since it fills up the layout.
Here is what it looks like:
And here is the code XML def:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical"
tools:context=".MainActivity" >
<!-- Top Buttons -->
<LinearLayout
android:id="#+id/drawToolbar"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="center"
android:orientation="horizontal" >
<ImageButton
android:id="#+id/new_btn"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="#drawable/new_pic" />
<!--
<ImageButton
android:id="#+id/existing_btn"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="#drawable/new_pic" />
-->
<ImageButton
android:id="#+id/draw_btn"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="#drawable/brush" />
<ImageButton
android:id="#+id/erase_btn"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="#drawable/eraser" />
</LinearLayout>
<!-- Custom View -->
<RelativeLayout
android:id="#+id/imgStack"
android:layout_weight="1"
android:layout_width="fill_parent"
android:layout_height="0dp">
<ImageView
android:id="#+id/imgBackground"
android:layout_alignParentTop="true"
android:layout_marginBottom="3dp"
android:layout_height="fill_parent"
android:layout_width="fill_parent"/>
<com.invocore.fastfield.views.DrawingView
android:id="#+id/drawing"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="3dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="3dp"
android:background="#android:color/transparent" />
</RelativeLayout>
<!-- Color Palette -->
... removed buttons to save space...
</LinearLayout>
The Activity code looks like this (have removed stuff to save space):
public class PhotoCaptureEditActivity extends Activity implements OnClickListener {
//custom drawing view
private DrawingView drawView;
private ImageView imgBackground;
private RelativeLayout imgStack;
// toolbars
private LinearLayout drawToolbar, drawColors;
//buttons
private ImageButton currPaint, drawBtn, eraseBtn, newBtn; //, saveBtn, existingBtn;
//sizes
private float smallBrush, mediumBrush, largeBrush;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photo_capture_edit);
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
// reset all pending values
GlobalState.getInstance().pendingFieldKey = null;
GlobalState.getInstance().pendingFieldValue = null;
//get drawing view
drawView = (DrawingView)findViewById(R.id.drawing);
drawView.setVisibility(View.VISIBLE);
imgBackground = (ImageView)findViewById(R.id.imgBackground);
imgStack = (RelativeLayout)findViewById(R.id.imgStack);
// toolbars
drawToolbar = (LinearLayout)findViewById(R.id.drawToolbar);
drawColors = (LinearLayout)findViewById(R.id.drawColors);
//get the palette and first color button
LinearLayout paintLayout = (LinearLayout)findViewById(R.id.paint_colors);
currPaint = (ImageButton)paintLayout.getChildAt(0);
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
[removed button and other code to save space]
enableDrawing();
// Must be a PNG for editing
Bitmap image = Utilities.loadImageByPath(filename);
if (image != null) {
imgBackground.setImageBitmap(image);
}
}
//user clicked paint
public void paintClicked(View view){
//use chosen color
setModeText("Draw Mode");
//set erase false
drawView.setErase(false);
drawView.setBrushSize(drawView.getLastBrushSize());
if(view!=currPaint){
ImageButton imgView = (ImageButton)view;
String color = view.getTag().toString();
drawView.setColor(color);
//update ui
imgView.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint));
currPaint=(ImageButton)view;
}
}
[Lots of other code...]
}
And the DrawingView class:
public class DrawingView extends View {
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
//brush sizes
private float brushSize, lastBrushSize;
//erase flag
private boolean erase=false;
public DrawingView(Context context, AttributeSet attrs){
super(context, attrs);
setupDrawing();
}
//setup drawing
private void setupDrawing(){
//prepare for drawing and setup paint stroke properties
brushSize = getResources().getInteger(mycompany.R.integer.medium_size);
lastBrushSize = brushSize;
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(brushSize);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
//size assigned to view
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if(canvasBitmap == null) {
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
}
drawCanvas = new Canvas(canvasBitmap);
drawCanvas.drawColor(Color.TRANSPARENT);
}
//draw the view - will be called after touch event
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
//register user touches as drawing action
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
//respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
if(erase == true) {
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
drawPath.moveTo(touchX, touchY);
}
else {
drawPath.lineTo(touchX, touchY);
}
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
//redraw
invalidate();
return true;
}
//update color
public void setColor(String newColor){
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
// set into draw mode if color was clicked
setBrushSize(getLastBrushSize());
setErase(false);
}
//set brush size
public void setBrushSize(float newSize){
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize=pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
//get and set last brush size
public void setLastBrushSize(float lastSize){
lastBrushSize=lastSize;
}
public float getLastBrushSize(){
return lastBrushSize;
}
//set erase true or false
public void setErase(boolean isErase){
erase=isErase;
if(erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
else drawPaint.setXfermode(null);
}
public void startExisting(String path) {
File file = new File(path);
if(file.exists() == true) {
Bitmap captured = BitmapFactory.decodeFile(file.toString());
canvasBitmap = captured.copy(Bitmap.Config.ARGB_8888, true);
drawCanvas = new Canvas(canvasBitmap);
drawCanvas.drawColor(Color.TRANSPARENT);
invalidate();
}
}
public void startNew() {
if(drawCanvas != null) {
drawCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
invalidate();
}
// setting a solid background color
//drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
//drawCanvas.drawColor(Color.GREEN, PorterDuff.Mode.CLEAR);
}
public Bitmap getImage() {
return canvasBitmap;
}
}
Thanks!
Uri currImageURI = intent.getData();
String s= getRealPathFromURI(currImageURI);
File file = new File(s);
if (file.exists()) {
Drawable drawImg = Drawable.createFromPath(file.getAbsolutePath());
drawView.setBackground(drawImg);
}
else {
// file does not exist
}
Related
In my project, users can view PDF documents and I want them to have the option to annotate each page in the document via onDraw and Paint. I would like the document to open for viewing first with the option to turn the drawing/painting function on and off via a button like the WhatsApp paint function.
I have a PaintView class extending my PDFView but when I open a PDF, the onDraw is called straight away, allowing me to draw over the PDF but not being able to then turn off this function and swipe between pages. When I move initDraw to a button I get a null pointer in my PaintView class.
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int)' on a null object reference
at com.example.dissertation814.pdfViewer.PaintView.onDraw(PaintView.java:60)
My viewer activity:
public class PdfViewerActivity extends AppCompatActivity {
private boolean isDrawInit = false;
private PaintView paintView;
//firebase auth
private FirebaseAuth mAuth;
//variables
public String currentUserAccount;
public String teacherAccountNav = "Teacher";
PDFView pdfView;
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pdf_viewer);
//PDFView to display PDFs
pdfView = findViewById(R.id.pdfView);
//use best quality
pdfView.useBestQuality(true);
//get data from intent
Intent i = this.getIntent();
Uri uri = i.getParcelableExtra("FILE_PATH_URI");
//Get the pdf file
assert uri != null;
File file = new File(Objects.requireNonNull(uri.getPath()));
if(file.canRead()){
//load pdf file
pdfView.fromFile(file)
.defaultPage(0)
.enableSwipe(true)
.swipeHorizontal(true)
.pageSnap(true)
.onDrawAll(new OnDrawListener() {
#Override
public void onLayerDrawn(Canvas canvas, float pageWidth, float pageHeight, int displayedPage) {
Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
canvas.drawBitmap(bitmap, 0,0, paint);
}
})
.onLoad(new OnLoadCompleteListener() {
#Override
public void loadComplete(int nbPages) {
Toast.makeText(PdfViewerActivity.this, "No. of pages: " + nbPages, Toast.LENGTH_SHORT).show();
}
}).load();
}
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
public void onInitDrawClick(View view){
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
#Override
protected void onResume() {
super.onResume();
if(!isDrawInit){
initDraw();
isDrawInit = true;
}
}
//initialise paint view
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
private void initDraw(){
paintView = findViewById(R.id.paintView);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
paintView.init(metrics);
}
//user finger path from paint view class
static class FingerPath{
int colour;
int strokeWidth;
Path path;
FingerPath(int colour, int strokeWidth, Path path){
this.colour = colour;
this.strokeWidth = strokeWidth;
this.path = path;
}
}
My PaintView class:
public class PaintView extends PDFView {
private Paint mPaint;
private Canvas mCanvas;
private Bitmap mBitmap;
private ArrayList<PdfViewerActivity.FingerPath> paths = new ArrayList<>();
private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
private static final float TOUCH_TOLERANCE = 4;
private Path mPath;
private float mX;
private float mY;
public int brushColour = Color.BLACK;
public int brushSize = 10;
public PaintView(Context context, AttributeSet set) {
super(context, set);
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.setXfermode(null);
mPaint.setAlpha(0xff);
}
public void init (DisplayMetrics metrics){
int height = (int) (metrics.heightPixels);
int width = metrics.widthPixels;
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
mCanvas.drawColor(Color.TRANSPARENT);
for(PdfViewerActivity.FingerPath fp : paths){
mPaint.setColor(fp.colour);
mPaint.setStrokeWidth(fp.strokeWidth);
mPaint.setMaskFilter(null);
mCanvas.drawPath(fp.path, mPaint);
}
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.restore();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
touchStart(x,y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touchMove(x,y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touchUp();
break;
}
return true;
}
private void touchUp(){
mPath.lineTo(mX,mY);
}
private void touchMove(float x, float y){
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;
}
}
private void touchStart(float x, float y){
mPath = new Path();
PdfViewerActivity.FingerPath fp = new PdfViewerActivity.FingerPath(brushColour, brushSize, mPath);
paths.add(fp);
mPath.reset();
mPath.moveTo(x,y);
mX = x;
mY = y;
}
public void clear(){
paths.clear();
invalidate();
}
My XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/black"
tools:context=".pdfViewer.PdfViewerActivity">
<Button
android:id="#+id/initDraw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="init"
app:layout_constraintBottom_toTopOf="#+id/relativeLayout"
app:layout_constraintEnd_toStartOf="#+id/homeButton"
app:layout_constraintStart_toEndOf="#+id/backButton"
app:layout_constraintTop_toTopOf="parent"
android:onClick="onInitDrawClick"/>
<ImageButton
android:id="#+id/backButton"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#color/black"
android:contentDescription="#string/back_button"
android:onClick="onBackClicked"
android:src="#drawable/backward_arrow"
app:layout_constraintBottom_toTopOf="#+id/relativeLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.112"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.8" />
<ImageButton
android:id="#+id/homeButton"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginEnd="64dp"
android:layout_marginRight="64dp"
android:background="#color/black"
android:onClick="onHomeClicked"
android:src="#drawable/ic_home_black_24dp"
app:layout_constraintBottom_toTopOf="#+id/relativeLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="#+id/backButton"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.8" />
<RelativeLayout
android:id="#+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="800dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.919"
android:paddingLeft="16dp"
android:paddingRight="16dp">
<com.github.barteksc.pdfviewer.PDFView
android:id="#+id/pdfView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.example.dissertation814.pdfViewer.PaintView
android:id="#+id/paintView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/transparent"/>
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
onDraw is a method, thus it's not something you initialize. I don't think you should try to disable the method either. Although you can override it, which puts you in control of what is drawn.
Consider another solution to you problem. Instead of enabling or disabling the onDraw method, you control which view gets to process the user input.
Solution:
When returning true in the method onTouchEvent, you state that no views above this one -- in the view hierarcy -- needs to process this input.
What you instead should do is to check whether or not the drawing feature should be on. If the drawing feature is disabled, you return false. Else if the drawing feature is enabled, you process the input, then return true.
Example:
#Override
public boolean onTouchEvent(MotionEvent event) {
// Check whether or not the drawing feature is disabled
if (drawingIsEnabled == false) {
// Let parent views process this input
return false;
}
float x = event.getX();
float y = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
touchStart(x,y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touchMove(x,y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touchUp();
break;
}
// Prevent parent views from processing this input
return true;
}
When returning false, the input is passed further up the view hierarchy so that the parent view will get the chance to process the input. (This will allow you to swipe pages)
If you however return true, you are preventing parent views from processing the input. (This will prevent the parent view from swiping pages while you're drawing, which would be quite annoying)
Hope this helps!
EDIT:
I initialized canvasBitmap = Bitmap.createBitmap(500,300, Bitmap.Config.RGB_565); drawCanvas = new Canvas(canvasBitmap); app does not crash but also does not draw anything.. i test it with canvas.drawcolor(Color.RED) inside the HOVER MOVE case. Now,learning from the crash I KNOW it is recognizing my hover movement.. so why nothing happens now? any idea?
I have an android 5.1 development board with a usb mouse connected. I need to perform some drawing operation when mouse is moved inside view window.
I am aware that the android studio emulator does not work with hover so all of my testing is on the development board itself
I added a hover listener to my OnCreate method. I basically have a transparent view sitting on top of the camera2 video (textureview). Trying to listen to it.
As soon as I move the mouse inside app, it crashes. so it IS detecting the hover. need some help with the reason for the crash. here are all relevant code: Activit containing the Oncreate, my CustomView, and my XML
public class CameraActivity extends Activity {
private Canvas drawCanvas;
private Bitmap canvasBitmap;
private Paint canvasPaint;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
if (null == savedInstanceState) {
getFragmentManager().beginTransaction()
.replace(R.id.container, Camera2BasicFragment.newInstance())
.commit();
}
View container = findViewById(R.id.container);
canvasPaint = new Paint(Paint.DITHER_FLAG);
container.setOnHoverListener(new View.OnHoverListener() {
#Override
public boolean onHover(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_HOVER_ENTER:
break;
case MotionEvent.ACTION_HOVER_MOVE:
drawCanvas.drawCircle(50,50,100,canvasPaint);
break;
case MotionEvent.ACTION_HOVER_EXIT:
break;
}
return false;
}
});
}
}
customview:
public class CustomView extends View{
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xff00ff00;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
//constructor
public CustomView(Context context){
super(context);
setupDrawing();
}
public CustomView(Context context, AttributeSet attrs){
super(context, attrs);
setupDrawing();
}
//prepare drawing
private void setupDrawing(){
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(10);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
//view assigned size
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
//draw view
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
//respond to touch interaction
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
//respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
new Timer().schedule(new TimerTask() {
#Override
public void run() {
// this code will be executed after 2 seconds
drawCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
}
}, 2000);
drawPath.reset();
break;
default:
return false;
}
//redraw
invalidate();
return true;
}
}
xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.android.camera2basic.AutoFitTextureView
android:id="#+id/texture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<com.example.android.camera2basic.CustomView
android:id="#+id/texture2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<FrameLayout
android:id="#+id/control"
android:layout_width="match_parent"
android:layout_height="112dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:background="#color/control_background">
<Button
android:id="#+id/picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/picture" />
<ImageButton
android:id="#+id/info"
android:contentDescription="#string/description_info"
style="#android:style/Widget.Material.Light.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|right"
android:padding="20dp"
android:src="#drawable/ic_action_info" />
</FrameLayout>
</RelativeLayout>
I have the following xml setup:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/content"
android:orientation="vertical">
</LinearLayout>
<ListView
android:id="#+id/navList"
android:layout_width="250dp"
android:layout_height="match_parent"
android:layout_gravity="left|start"
android:background="#cccccc"/>
</android.support.v4.widget.DrawerLayout>
I now would like to draw a canvas in that linear layout, therefore I do that:
Radar radar = new Radar(this, this.width);
content.addView(radar);
and here is the radar class:
private int width;
public Radar(Context context, int width){
super(context);
this.width = width;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint circlePaint = new Paint();
circlePaint.setColor(0xFF00FF00);
circlePaint.setStyle(Paint.Style.FILL);
Rect rect = new Rect();
rect.set(0, 0, canvas.getWidth(), canvas.getHeight() / 2);
canvas.drawRect(rect, circlePaint);
//canvas.drawCircle(0, 0, this.width, circlePaint);
}
The problem I encounter is that the canvas doesn't show up
How can I fix that?
I found the answer by adding setWillNotDraw(false);
It worked below code for me. you can also try similarly.
1) Add layout
<com.example.canvas.DrawingArea
android:id="#+id/drawing"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_marginBottom="3dp"
android:layout_weight="1"
android:background="#FFFFFFFF" />
2) Code
public class DrawingArea extends View {
private Path drawPath;
private Paint drawPaint, canvasPaint;
private int paintColor = 0xFF660000;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
private boolean erase = false;
public DrawingArea(Context context) {
super(context);
setupDrawing();
}
public DrawingArea(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
public void setupDrawing() {
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(20);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
public void setColor(String newColor) {
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(eventX, eventY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
// Makes our view repaint and call onDraw
invalidate();
return true;
}
public void setErase() {
canvasBitmap.eraseColor(Color.TRANSPARENT);
drawPath.reset();
invalidate();
}
public void startNew() {
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
}
3) create drawing object
DrawingArea mDrawView = (DrawingArea) findViewById(R.id.drawing);
I have created my own custom edittext class so that i can draw in it and also add text...
Everything is working fine regarding the drawing part but when i type no text is visible,,,,,,
How can i fix this
my customview
public class MyCustomView extends View
{
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
private float brushSize ;
private boolean erase=false;
public MyCustomView(Context c, AttributeSet attr){
super(c,attr);
setupdraw();
}
public MyEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void setupdraw()
{
drawPath = new Path();
drawPaint = new Paint();
brushSize = 15;
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(brushSize);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//view given size
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
//draw view
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//detect user touch
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
invalidate();
return true;
}
public void setColor(String newColor){
//set color
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
}
public void setBrushSize(float newSize){
//update size
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize=pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
}
}
my main activity
public class MainActivity extends Activity
{
private MyCustomView myView;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MyCustomView myView = (MyCustomView) findViewById(R.id.myCustomView);
}
}
main.xml
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:padding="10dp"
android:background="#D06C65">
<com.mycompany.myapp.MyCustomView
android:id="#+id/myCustomView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#EAEAEA"/>
<Button
android:layout_height="wrap_content"
android:text="T"
android:layout_width="wrap_content"
android:layout_gravity="bottom|center"/>
</FrameLayout>
You should call super.onDraw(canvas) after drawing your background stuff. The TextView drawing methods will subsequently handle all the drawing text features (you don't want to recode that).
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
super.onDraw(canvas);
}
I'm creating an app where the user draws a letter on canvas and it gets validated if the draw is an actual letter. I'm using a GestureOverlayView with a canvas inside to capture both the gesture and the path, the problem is that the canvas is not drawing the whole path/gesture i do with my hands. I need help to find the solution. I need the path/gesture to be fully drawn.
XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<android.gesture.GestureOverlayView
android:id="#+id/gestures"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:eventsInterceptionEnabled="true"
android:gestureStrokeType="multiple"
android:layout_alignParentRight="true"
android:fadeOffset="500"
android:background="#000000">
<cohen.projetoTEA.com.DrawLetter
android:id="#+id/drawing"
android:layout_width="wrap_content"
android:layout_alignParentRight="true"
android:layout_height="wrap_content"
android:background="#FFFFFF"
/>
</android.gesture.GestureOverlayView>
</RelativeLayout>
Activity
public class Reconhecimento extends Activity implements OnGesturePerformedListener {
GestureLibrary mLibrary;
private final File mStoreFile = new File(Environment.getExternalStorageDirectory(), "gestures");
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reconhecimento);
//mLibrary = GestureLibraries.fromRawResource(this, R.raw.gestures);
mLibrary = GestureLibraries.fromFile(mStoreFile);
if (!mLibrary.load()) {
finish();
}
GestureOverlayView gestures = (GestureOverlayView) findViewById(R.id.gestures);
gestures.addOnGesturePerformedListener(this);
gestures.setGestureVisible(false);
}
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
ArrayList<Prediction> predictions = mLibrary.recognize(gesture);
if (predictions.size() > 0 && predictions.get(0).score > 1.0) {
String result = predictions.get(0).name;
Toast.makeText(this, result, Toast.LENGTH_LONG).show();
if ("open".equalsIgnoreCase(result)) {
Toast.makeText(this, "Opening the document", Toast.LENGTH_LONG).show();
} else if ("save".equalsIgnoreCase(result)) {
Toast.makeText(this, "Saving the document", Toast.LENGTH_LONG).show();
}
}
}
}
DrawLetter app
public class DrawLetter extends View {
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
private boolean erase=false;
public DrawLetter(Context context, AttributeSet attrs){
super(context, attrs);
setupDrawing();
}
private void setupDrawing(){
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(5);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
public void setErase(boolean isErase){
erase=isErase;
if(erase){
drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
drawPaint.setStrokeWidth(10);
}
else{
drawPaint.setXfermode(null);
drawPaint.setStrokeWidth(5);
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//view given size
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
//draw view
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//detect user touch
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
invalidate();
return true;
}
public boolean getErase(){ return erase; }
}
You can do it in another way.
Like this
<android.gesture.GestureOverlayView
android:id="#+id/g1"
android:layout_width="fill_parent"
android:layout_height="200dp"
android:background="#ffffff"
android:fadeOffset="999999"
android:gestureColor="#0000FF"
android:gestureStrokeType="multiple"
android:gestureStrokeWidth="5" >
<android.gesture.GestureOverlayView
android:id="#+id/g2"
android:layout_width="fill_parent"
android:layout_height="200dp"
android:gestureStrokeType="multiple"
android:fadeOffset="001"
android:gestureColor="#000"
android:gestureStrokeAngleThreshold="0.0"
android:gestureStrokeLengthThreshold="0.0"
android:gestureStrokeSquarenessThreshold="0.0"
>
</android.gesture.GestureOverlayView>
</android.gesture.GestureOverlayView>
Here GestureOverlayView g2 is within g1.
g2 is used to recognize letters and it fades once the letter is written.
But g1 does not fades.
If you don't want the letter you can clear the GestureOverlayView.