Multiple canvases on Live Wallpaper (one moving, one stable). How? - android

How can I draw multiple canvases on Live Wallpaper?
I want a live wallpaper having a background image (bitmap), and on the image there would be an object, which follows your finger. But I can't draw more than one canvas.
I've already went through Google, but I didn't find anythink helpful.
Is there any way to produce this?
Here's my (not working) code for this:
package i.need.some.help;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.service.wallpaper.WallpaperService;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
public class NewMyWallpaperService extends WallpaperService {
#Override
public Engine onCreateEngine() {
return new CubeEngine();
}
class CubeEngine extends Engine {
private final Paint mPaint = new Paint();
private final Paint myPaint = new Paint();
private float mTouchX = 0;
private float mTouchY = 0;
Bitmap movingObject = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
final SurfaceHolder holder = getSurfaceHolder();
int height = Resources.getSystem().getDisplayMetrics().heightPixels;
int width = Resources.getSystem().getDisplayMetrics().widthPixels;
Bitmap backroundIMG = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher_round);
CubeEngine() {
setBackground();
}
#Override
public void onCreate (SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
// Touch event handle alert
setTouchEventsEnabled(true);
}
#Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
}
#Override
public void onTouchEvent (MotionEvent event) {
super.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_UP) {
mTouchX = event.getX();
mTouchY = event.getY();
} else {
mTouchX = event.getX();
mTouchY = event.getY();
}
drawFrame();
}
void drawFrame() {
Canvas c = null;
try {
c = holder.lockCanvas();
if (c !=null) {
c.save();
c.drawBitmap(movingObject, mTouchX-(movingObject.getWidth()/2), mTouchY-(movingObject.getHeight()/2), mPaint);
c.restore();
}
} finally {
if (c != null) {
holder.unlockCanvasAndPost(c);
}
}
}
final void setBackground() {
Canvas ca = null;
try {
ca = holder.lockCanvas();
if (ca !=null) {
ca.save();
ca.drawColor(0xffa8a8a8);
ca.drawBitmap(backroundIMG, height/2, width/2, myPaint);
ca.restore();
}
} finally {
if (ca != null) {
holder.unlockCanvasAndPost(ca);
}
}
}
}
}

Related

Android app has stopped and attempt to invoke virtual method on a null object reference [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 2 years ago.
When I run my android app, it crashes and says that Android app has stopped. It also gives this error message:
java.lang.NullPointerException: Attempt to invoke virtual method 'com.esimerkki.doodl2.DoodleView com.esimerkki.doodl2.FirstFragment.getDoodleView()' on a null object reference
What is wrong with this? Is the reference really null? How could I make this work? I thought these original settings in doodleView have start values?
Here is the code of doodleView class:
package com.esimerkki.doodl2;
import android.content.Context;
import android.view.View;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.provider.MediaStore;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.widget.Toast;
import androidx.print.PrintHelper;
import java.util.HashMap;
import java.util.Map;
public class DoodleView extends View {
public DoodleView(Context context, Paint paintScreen, Paint paintLine) {
super( context );
this.paintScreen = paintScreen;
this.paintLine = paintLine;
}
private static final float TOUCH_TOLERANCE = 10;
private Bitmap bitmap; // drawing area
private Canvas bitmapCanvas; //
private final Paint paintScreen; //
private final Paint paintLine; //
private final Map<Integer, Path> pathMap = new HashMap<>();
private final Map<Integer, Point> previousPointMap = new HashMap<>();
public DoodleView(Context context, AttributeSet attrs) {
super(context, attrs); // kutsutaan yliluokanalustajaa
paintScreen = new Paint(); // bittikartan näyttämiseen ruudulla
paintLine = new Paint();
paintLine.setAntiAlias(true);
paintLine.setColor(Color.BLACK);
paintLine.setStyle(Paint.Style.STROKE);
paintLine.setStrokeWidth(5);
paintLine.setStrokeCap(Paint.Cap.ROUND);
#Override
public void onSizeChanged(int w, int h, int OldW, int oldH) {
bitmap = Bitmap.createBitmap(getWidth(), getHeight(),
Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas(bitmap);
bitmap.eraseColor(Color.WHITE);
}
public void clear() {
pathMap.clear();
previousPointMap.clear();
bitmap.eraseColor(Color.WHITE);
invalidate();
}
public void setDrawingColor(int color) {
paintLine.setColor(color);
}
public int getDrawingColor() {
return paintLine.getColor();
}
public void setLineWidth(int width) {
paintLine.setStrokeWidth(width);
}
public int getLineWidth() {
return (int) paintLine.getStrokeWidth();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(bitmap, 0, 0, paintScreen);
for (Integer key : pathMap.keySet())
canvas.drawPath(pathMap.get(key), paintLine); // piirretään viiva
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked(); // tapahtumatyyppi
int actionIndex = event.getActionIndex(); // osoitin
if (action == MotionEvent.ACTION_DOWN ||
action == MotionEvent.ACTION_POINTER_DOWN) {
touchStarted(event.getX(actionIndex), event.getY(actionIndex),
event.getPointerId(actionIndex));
}
else if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_POINTER_UP) {
touchEnded(event.getPointerId(actionIndex));
}
else {
touchMoved(event);
}
invalidate();
return true;
}
private void touchStarted(float x, float y, int lineID) {
Path path; // tallennetaan tietyn id:n polku
Point point; // tallennetaan polun viimeinen piste
if (pathMap.containsKey(lineID)) {
path = pathMap.get(lineID);
path.reset();
point = previousPointMap.get(lineID);
}
else {
path = new Path();
pathMap.put(lineID, path);
point = new Point();
previousPointMap.put(lineID, point);
}
path.moveTo(x, y);
point.x = (int) x;
point.y = (int) y;
}
private void touchMoved(MotionEvent event) {
for (int i = 0; i < event.getPointerCount(); i++) {
// luetaan pointtein id ja indeksi
int pointerID = event.getPointerId(i);
int pointerIndex = event.findPointerIndex(pointerID);
if (pathMap.containsKey(pointerID)) {
float newX = event.getX(pointerIndex);
float newY = event.getY(pointerIndex);
Path path = pathMap.get(pointerID);
Point point = previousPointMap.get(pointerID);
// lasketaan kuinka kauas liikuttu
float deltaX = Math.abs(newX - point.x);
float deltaY = Math.abs(newY - point.y);
if (deltaX >= TOUCH_TOLERANCE || deltaY >= TOUCH_TOLERANCE) {
path.quadTo(point.x, point.y, (newX + point.x) / 2,
(newY + point.y) / 2);
point.x = (int) newX;
point.y = (int) newY;
}
}
}
}
private void touchEnded(int lineID) {
Path path = pathMap.get(lineID);
bitmapCanvas.drawPath(path, paintLine);
path.reset(); // tyhjennetään polku
}
public void saveImage() {
final String name = "Doodlz" + System.currentTimeMillis() + ".jpg";
String location = MediaStore.Images.Media.insertImage(
getContext().getContentResolver(), bitmap, name,
"Doodlz Drawing"
);
if (location != null) {
Toast message = Toast.makeText(getContext(),
R.string.message_saved,
Toast.LENGTH_SHORT);
message.setGravity(Gravity.CENTER, message.getXOffset() / 2,
message.getYOffset() / 2);
message.show();
}
else {
Toast message = Toast.makeText(getContext(),
R.string.message_error_saving, Toast.LENGTH_SHORT);
message.setGravity(Gravity.CENTER, message.getXOffset() / 2,
message.getYOffset() / 2);
message.show();
}
}
public void printImage() {
if (PrintHelper.systemSupportsPrint()) {
PrintHelper printHelper = new PrintHelper(getContext());
printHelper.setScaleMode(printHelper.SCALE_MODE_FIT);
printHelper.printBitmap("Doodlz Imate", bitmap);
}
else {
Toast message = Toast.makeText(getContext(),
R.string.message_error_printing, Toast.LENGTH_SHORT);
message.setGravity(Gravity.CENTER, message.getXOffset() / 2,
message.getYOffset() / 2);
message.show();
}
}
}
And here is the code of a LineWidthFragment class:
package com.esimerkki.doodl2;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
//import android.support.v4.app.DialogFragment;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import androidx.fragment.app.DialogFragment;
public class LineWidthFragment extends DialogFragment {
private ImageView widthImageView;
#Override
public Dialog onCreateDialog(Bundle bundle) {
AlertDialog.Builder builder =
new AlertDialog.Builder(getActivity());
View lineWidthDialogView =
getActivity().getLayoutInflater().inflate(
R.layout.fragment_line_width, null);
builder.setView(lineWidthDialogView); // lisätään GUI dialogiin
builder.setTitle(R.string.title_line_width_dialog);
widthImageView = (ImageView) lineWidthDialogView.findViewById(
R.id.widthImageView);
final DoodleView doodleView = getDoodleFragment().getDoodleView();
final SeekBar widthSeekBar = (SeekBar)
lineWidthDialogView.findViewById(R.id.widthSeekBar);
widthSeekBar.setOnSeekBarChangeListener(lineWidthChanged);
widthSeekBar.setProgress(doodleView.getLineWidth());
builder.setPositiveButton(R.string.button_set_line_width,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
doodleView.setLineWidth(widthSeekBar.getProgress());
}
}
);
return builder.create();
}
private FirstFragment getDoodleFragment() {
return (FirstFragment) getChildFragmentManager().findFragmentById(
R.id.doodleFragment);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
FirstFragment fragment = getDoodleFragment();
if (fragment != null)
fragment.setDialogOnScreen(true);
}
#Override
public void onDetach() {
super.onDetach();
FirstFragment fragment = getDoodleFragment();
if (fragment != null)
fragment.setDialogOnScreen(false);
}
private final OnSeekBarChangeListener lineWidthChanged =
new OnSeekBarChangeListener() {
final Bitmap bitmap = Bitmap.createBitmap(
400, 100, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap); // piirtää bittikarttaan
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
Paint p = new Paint();
p.setColor(
getDoodleFragment().getDoodleView().getDrawingColor());
p.setStrokeCap(Paint.Cap.ROUND);
p.setStrokeWidth(progress);
bitmap.eraseColor(
getResources().getColor(android.R.color.transparent,
getContext().getTheme()));
canvas.drawLine(30, 50, 370, 50, p);
widthImageView.setImageBitmap(bitmap);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) { // tarvitaan
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) { // tarvitaan
}
};
}
Your error says the following:
null object reference
This means that 1 object gives the value 0.
Your code looks fine but if you rewrite the code once again you may solve the mistake.
It is caused by a pitty error in your code.
When rewriting it. You can find that error.
Even if this was a bug with some plugin or anything else.
Also after you rewrote it, if you get the same error then you need to look onto a reference.

Draw bitmap over already drawn background on the SurfaceView

In my SurfaceView when I click on the screen it creates black dots after that I connect them and it has a filled with color. After that I am ttrying to draw other bitmap and I want the current state be something like a background and when I touch the screen I want to draw a bitmap on this possition and when I am trying to draw a bitmap on touch location the canvas goes back to the previous state with the draws.
Here is my code:
package com.inveitix.android.clue.ui.views;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.inveitix.android.clue.R;
import com.inveitix.android.clue.cmn.Door;
import com.inveitix.android.clue.cmn.MapPoint;
import java.util.ArrayList;
import java.util.List;
public class DrawingView extends SurfaceView {
private static final String TAG = "DrawingView";
private static final float DOOR_SIZE = 30;
private Paint paint;
private Canvas canvas;
private int maxHeight;
private int maxWidth;
private SurfaceHolder surfaceHolder;
private List<MapPoint> shape;
private List<Door> doors;
private float ratio;
private boolean isFloorFinished;
private boolean isDoorSelected;
Path path;
public DrawingView(Context context) {
super(context);
init();
}
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DrawingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void setIsDoorSelected(boolean isDoorSelected) {
this.isDoorSelected = isDoorSelected;
}
public void setIsFloorFinished(boolean isFloorFinished) {
this.isFloorFinished = isFloorFinished;
}
private void init() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
isFloorFinished = false;
surfaceHolder = this.getHolder();
prepareCanvas();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
shape = new ArrayList<>();
doors = new ArrayList<>();
}
private void prepareCanvas() {
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void surfaceCreated(SurfaceHolder holder) {
canvas = holder.lockCanvas();
canvas.drawColor(Color.WHITE);
holder.unlockCanvasAndPost(canvas);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
});
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
int minh = getPaddingBottom() + getPaddingTop() + getSuggestedMinimumHeight();
this.maxWidth = resolveSizeAndState(minw, widthMeasureSpec, 1);
this.maxHeight = resolveSizeAndState(minh, heightMeasureSpec, 1);
if (ratio != 0) {
maxHeight = (int) (maxWidth / ratio);
}
Log.i(TAG, "onMeasure width:" + maxWidth);
Log.i(TAG, "onMeasure height:" + maxHeight);
setMeasuredDimension(maxWidth, maxHeight);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && !isFloorFinished) {
if (surfaceHolder.getSurface().isValid()) {
shape.add(new MapPoint(event.getX(), event.getY()));
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
for (MapPoint point : shape) {
canvas.drawCircle(point.getX(), point.getY(), 10, paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
} else if (event.getAction() == MotionEvent.ACTION_DOWN && isDoorSelected) {
if (surfaceHolder.getSurface().isValid()) {
Door door = new Door();
door.setConnectedTo("door1"); //this is for test
door.setX(event.getX());
door.setY(event.getY());
doors.add(door);
canvas = surfaceHolder.lockCanvas();
drawDoors(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
return false;
}
public void drawFloor() {
Bitmap bmpFloorPattern = BitmapFactory.decodeResource(getResources(), R.drawable.floor_pattern6);
BitmapShader patternBMPshader = new BitmapShader(bmpFloorPattern,
Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
canvas = surfaceHolder.lockCanvas();
path = new Path();
path.reset();
if (shape != null) {
path.moveTo(shape.get(0).getX(), shape.get(0).getY());
alignPoints(path);
canvas.drawColor(Color.WHITE);
for (int i = 0; i < shape.size(); i++) {
path.lineTo(shape.get(i).getX(), shape.get(i).getY());
}
}
paint.setShader(patternBMPshader);
path.close();
canvas.drawPath(path, paint);
paint.setShader(null);
surfaceHolder.unlockCanvasAndPost(canvas);
}
public void drawDoors(Canvas canvas) {
Bitmap bmpDoor = BitmapFactory.decodeResource(getResources(), R.drawable.door32);
paint.setFilterBitmap(true);
if (doors != null && doors.size() > 0) {
for (Door door : doors) {
canvas.drawBitmap(bmpDoor, door.getX() - DOOR_SIZE, door.getY() - DOOR_SIZE, null);
}
}
}
private void alignPoints(Path path) {
MapPoint previousPoint = null;
for (int i = 0; i < shape.size(); i++) {
float x = shape.get(i).getX();
float y = shape.get(i).getY();
if (previousPoint != null) {
float deltaX = Math.abs(x - previousPoint.getX());
float deltaY = Math.abs(y - previousPoint.getY());
if (Math.max(deltaX, deltaY) == deltaX) {
x = previousPoint.getX();
} else {
y = previousPoint.getY();
}
}
path.lineTo(x, y);
previousPoint = shape.get(i);
}
}
public void setWidthToHeightRatio(float ratio) {
this.ratio = ratio;
maxHeight = (int) (maxWidth / ratio);
invalidate();
requestLayout();
}
}
Any ideas how to draw over the drawn background ?
I found it I have to draw doors in the same time with the floor so I did this changes:
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && !isFloorFinished) {
if (surfaceHolder.getSurface().isValid()) {
shape.add(new MapPoint(event.getX(), event.getY()));
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
for (MapPoint point : shape) {
canvas.drawCircle(point.getX(), point.getY(), 10, paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
} else if (event.getAction() == MotionEvent.ACTION_DOWN && isDoorSelected) {
if (surfaceHolder.getSurface().isValid()) {
Door door = new Door();
door.setConnectedTo("door1"); //this is for test
door.setX(event.getX());
door.setY(event.getY());
doors.add(door);
drawFloor();
}
}
return false;
}
public void drawFloor() {
Bitmap bmpFloorPattern = BitmapFactory.decodeResource(getResources(), R.drawable.floor_pattern6);
BitmapShader patternBMPshader = new BitmapShader(bmpFloorPattern,
Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
canvas = surfaceHolder.lockCanvas();
path = new Path();
path.reset();
if (shape != null) {
path.moveTo(shape.get(0).getX(), shape.get(0).getY());
alignPoints(path);
canvas.drawColor(Color.WHITE);
for (int i = 0; i < shape.size(); i++) {
path.lineTo(shape.get(i).getX(), shape.get(i).getY());
}
}
paint.setShader(patternBMPshader);
path.close();
canvas.drawPath(path, paint);
paint.setShader(null);
if(doors.size() > 0) {
drawDoors();
}
surfaceHolder.unlockCanvasAndPost(canvas);
}

Changing path color without changing previous paths

I made straight lines with the canvas.drawPath command. But now I want that the color is selectable. So you click on a button and afterwards, the path is in this color, but the previous paths remain in their colors.. The thin with the button comes later, the colour is random at the moment...
I did it, i changed the code from here! Change path color without changing previous paths
Main Activity
package com.example.drawproject;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DrawArea da = new DrawArea(this);
setContentView(da);
}
}
Draw Activity
import android.content.Context;
import android.graphics.*;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class DrawArea extends View {
private List<Stroke> _allStrokes; //all strokes that need to be drawn
private SparseArray<Stroke> _activeStrokes; //use to retrieve the currently drawn strokes
private Random _rdmColor = new Random();
int count = 1;
public DrawArea(Context context) {
super(context);
_allStrokes = new ArrayList<Stroke>();
_activeStrokes = new SparseArray<Stroke>();
setFocusable(true);
setFocusableInTouchMode(true);
}
public void onDraw(Canvas canvas) {
if (_allStrokes != null) {
for (Stroke stroke: _allStrokes) {
if (stroke != null) {
Path path = stroke.getPath();
Paint painter = stroke.getPaint();
if ((path != null) && (painter != null)) {
if(count%2 != 0){
canvas.drawPath(path, painter);
}
}
}
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getActionMasked();
final int pointerCount = event.getPointerCount();
switch (action) {
case MotionEvent.ACTION_DOWN: {
count++;
if(count%2 != 1)
{pointDown((int)event.getX(), (int)event.getY(), event.getPointerId(0));
break;
}
if (count%2 != 0){
for (int pc = 0; pc < pointerCount; pc++) {
pointDown((int)event.getX(pc), (int)event.getY(pc), event.getPointerId(pc));
}
}
}
case MotionEvent.ACTION_MOVE: {
break;
}
case MotionEvent.ACTION_UP: {
break;
}
}
invalidate();
return true;
}
private void pointDown(int x, int y, int id) {
if(count%2 !=1){
//create a paint with random color
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10);
paint.setColor(_rdmColor.nextInt());
//create the Stroke
Point pt = new Point(x, y);
Stroke stroke = new Stroke(paint);
stroke.addPoint(pt);
_activeStrokes.put(id, stroke);
_allStrokes.add(stroke);
}
if (count%2 != 0){
//retrieve the stroke and add new point to its path
Stroke stroke = _activeStrokes.get(id);
if (stroke != null) {
Point pt = new Point(x, y);
stroke.addPoint(pt);
}
}
}
}
Lines
package com.example.drawproject;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
public class Stroke {
private Path _path;
private Paint _paint;
public Stroke (Paint paint) {
_paint = paint;
}
public Path getPath() {
return _path;
}
public Paint getPaint() {
return _paint;
}
public void addPoint(Point pt) {
if (_path == null) {
_path = new Path();
_path.moveTo(pt.x, pt.y);
} else {
_path.lineTo(pt.x, pt.y);
}
}
}
For each path declare separate paint object and change paint object of the path that you want to change.
canvas.drawPath(path1, paint1);
canvas.drawPath(path2, paint2);
canvas.drawPath(path3, paint3);
canvas.drawPath(path4, paint4);
The main idea:
public class temp extends View{
private Map<Path,Paint> MyMap = new HashMap<Path,Paint>();
public ViewFeld(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
private void init() {
for (int i = 0; i < number of pathes ; i++) {
Path path = new Path();
paint = new Paint();
paint.setColor(Color.MAGENTA);
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.FILL);
MyMap.put(path, paint);
}
}
protected void onDraw(Canvas canvas) {
for (Path p : MyMap.keySet()) {
canvas.drawPath(p, MyMap.get(p));
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Paint p = MyMap.get(path you want to change the color);
// change the color of p
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
// nothing to do
break;
default:
return false;
}
// Schedules a repaint.
invalidate();
return true;
}

SurfaceView lost initial drawing. Double buffer initialization?

I'm using SurfaceView for driving sprites.
For performance, I only redraw canvas partially, so I lock the Canvas with dirty rect. In general, it works good, but SurfaceView lost initial drawing in surfaceCreated method.
I suppose it's related to SurfaceView internal double buffering.
Any ideas how to correctly initialize SurfaceView?
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class TestView extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = TestView.class.getSimpleName();
SurfaceHolder holder;
public TestView(Context context) {
super(context);
holder = getHolder();
holder.addCallback(this);
setFocusable(true);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
drawBg();
drawPoint(100, 120);
}
private void drawBg() {
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
synchronized (holder) {
canvas.drawRGB(255, 128, 128);
Paint paint = new Paint();
paint.setColor(Color.GREEN);
canvas.drawCircle(100, 100, 10, paint);
}
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
private void drawPoint(int x, int y) {
int radius = 10;
Rect dirty = new Rect(x - radius, y - radius, x + radius, y + radius);
Canvas canvas = null;
try {
canvas = holder.lockCanvas(dirty);
synchronized (holder) {
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawCircle(x, y, radius, paint);
}
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
drawPoint((int) event.getX(), (int) event.getY());
}
return super.onTouchEvent(event);
}
}

paint canvas android

I'm developing in android, and I have to do a Paint for android.
I'm using the code below and, when I execute the code, the draw works, but, it seems that there are 2 surfaces to paint, and when you draw in one, the other one disappears.
I was looking for the exact error, but cannot find it.
Here is the code :
import java.util.Random;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RelativeLayout;
public class MainActivity extends Activity {
MySurfaceView mySurfaceView;
Button Cuadrado;
Button Circulo;
Button Color;
Button Linea;
private boolean Bcuadrado,Bcirculo,Bcolor=false;
private boolean Blinea=true;
Canvas canvas = new Canvas();
#TargetApi(11)
#SuppressLint("NewApi")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout mainLayout =(RelativeLayout)findViewById(R.id.main_layout_id );
View view =getLayoutInflater().inflate(R.layout.itemlayout, mainLayout,false);
mainLayout.addView(view);
mySurfaceView = new MySurfaceView(this);
Cuadrado=(Button)findViewById(R.id.button1);
Circulo=(Button)findViewById(R.id.button2);
Color=(Button)findViewById(R.id.button3 );
Linea=(Button)findViewById(R.id.button4 );
int w= view.getWidth();
int h= view.getHeight();
float x=view.getX();
float y= view.getY();
mySurfaceView.setY(100);
mainLayout.addView(mySurfaceView);
Cuadrado.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(Bcuadrado==false){
Bcuadrado=true;
Bcirculo=false;
Bcolor=false;
Blinea=false;
}
}
});
Circulo.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(!Bcirculo){
Bcuadrado=false;
Bcirculo=true;
Bcolor=false;
Blinea=false;
}
}
});
Color.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(!Bcolor){
Bcuadrado=false;
Bcirculo=false;
Bcolor=true;
Blinea=false;
}
}
});
Linea.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(!Blinea){
Bcuadrado=false;
Bcirculo=false;
Bcolor=false;
Blinea=true;
}
}
});
}
class MySurfaceView extends SurfaceView{
Path path;
SurfaceHolder surfaceHolder;
volatile boolean running = false;
private Paint paint = new Paint();
float x0=0;
float x1=0;
float y0=0;
float y1=0;
Random random = new Random();
public MySurfaceView(Context context) {
super(context);
surfaceHolder = getHolder();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(android.graphics.Color.WHITE);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(Blinea){
if(event.getAction() == MotionEvent.ACTION_DOWN){
path = new Path();
path.moveTo(event.getX(), event.getY());
}else if(event.getAction() == MotionEvent.ACTION_MOVE){
path.lineTo(event.getX(), event.getY());
}else if(event.getAction() == MotionEvent.ACTION_UP){
path.lineTo(event.getX(), event.getY());
}
if(path != null){
canvas = surfaceHolder.lockCanvas();
canvas.drawPath(path, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}else if(Bcuadrado){
if(event.getAction()==MotionEvent.ACTION_DOWN){
x0=event.getX();
y0=event.getY();
}
else if(event.getAction()==MotionEvent.ACTION_UP){
x1=event.getX();
y1=event.getY();
canvas = surfaceHolder.lockCanvas();
canvas.drawRect(x0, y0, x1, y1, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}else if(Bcirculo){
if(event.getAction()==MotionEvent.ACTION_DOWN){
x0=event.getX();
y0=event.getY();
}
else if(event.getAction()==MotionEvent.ACTION_UP){
x1=event.getX();
canvas=surfaceHolder.lockCanvas();
canvas.drawCircle(x0, y0,(x1-x0), paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}else if(Bcolor){
int r = random.nextInt(255);
int g = random.nextInt(255);
int b = random.nextInt(255);
canvas=surfaceHolder.lockCanvas();
paint.setColor(0xff000000 + (r << 16) + (g << 8) + b);
surfaceHolder.unlockCanvasAndPost(canvas);
}
return true;
}
}
}
it seems that there are 2 surfaces to paint, and when you draw in one, the other one disappears.
That is exactly how SurfaceView works - it's double buffered. You need to redraw whole frame each time.
From Android's doc: SurfaceHolder
The content of the Surface is never preserved between unlockCanvas() and lockCanvas(), for this reason, every pixel within the Surface area must be written. The only exception to this rule is when a dirty rectangle is specified, in which case, non-dirty pixels will be preserved.
The canvas does not save what you previously wrote to it. Every time you call unlock(), you must redraw everything all over again.

Categories

Resources