I am following this tutorial: http://danielnadeau.blogspot.ca/2012/01/android-canvas-beginners-tutorial.html
When I look at things in the "Graphical Layout" tab in Eclipse, I see the expected result (a red square in the center of the display), but when I actually run the app, I just get a large black rectangle, and I can't seem to figure out why. I've searched some posts, but have not found an answer that seems to apply to my situation.
MainActivity.java
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
activity_mail.xml
<RelativeLayout 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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.hintonworks.cantstop.CustomView
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="#+id/my_view" />
</RelativeLayout>
CustomView.java
package com.hintonworks.cantstop;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class CustomView extends SurfaceView implements SurfaceHolder.Callback {
public CustomView (Context context) {
super(context);
}
public CustomView (Context context, AttributeSet attrs) {
super(context);
}
#Override
public void onDraw (Canvas canvas) {
int dCenter = 40; //Distance from center in px, NOT in dp
int centerX = (int)(getWidth()/2);
int centerY = (int)(getHeight()/2);
Paint paint = new Paint();
paint.setColor(Color.RED); //The square will draw in the color blue now
Rect rect = new Rect(centerX-dCenter, centerY-dCenter, centerX+dCenter, centerY+dCenter);
canvas.drawRect(rect, paint);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
#Override
public void surfaceCreated(SurfaceHolder holder) {
setWillNotDraw(false); //Allows us to use invalidate() to call onDraw()
postInvalidate();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {}
}
Thanks for any insight. This is my stab at using the canvas, until now I have been using drawable resources.
Related
I'm trying to draw a rectangle over camera2 textureview, when i run the code I see the usual camera screen with moving square , and when I Click (touch) it, app crashes with the error in topic. I also not sure I implemented the custom view correctly, Here are all the relevant parts, Would love some help (I'm not sure I have a good layout xml, I added ViewGroup code under OnCrearte, not sure i even need to touch xml)
-------CameraActivity.java:
package com.example.android.camera2video;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.ViewGroup;
public class CameraActivity extends Activity {
private Context context;
CustomView customview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
customview = new CustomView(this);
final ViewGroup viewGroup = (ViewGroup) ((ViewGroup) this.findViewById(android.R.id.content)).getChildAt(0);
viewGroup.addView(new CustomView(this));
if (null == savedInstanceState) {
getFragmentManager().beginTransaction()
.replace(R.id.container, Camera2VideoFragment.newInstance())
.commit();
}
}
}
-------CustomView.java
package com.example.android.camera2video;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class CustomView extends SurfaceView {
private Paint paint;
private SurfaceHolder mHolder;
private Context context;
public CustomView(Context context) {
super(context);
mHolder = getHolder();
mHolder.setFormat(PixelFormat.TRANSPARENT);
this.context = context;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// real work here
}
private void doAdditionalConstructorWork() {
// init variables etc.
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
invalidate();
if (mHolder.getSurface().isValid()) {
final Canvas canvas = mHolder.lockCanvas();
Log.d("touch", "touchRecieved by camera");
System.err.println("EXIT 1");
if (canvas != null) {
Log.d("touch", "touchRecieved CANVAS STILL Not Null");
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
canvas.drawColor(Color.TRANSPARENT);
canvas.drawCircle(event.getX(), event.getY(), 100, paint);
mHolder.unlockCanvasAndPost(canvas);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Canvas canvas1 = mHolder.lockCanvas();
if(canvas1 !=null){
canvas1.drawColor(0, PorterDuff.Mode.CLEAR);
mHolder.unlockCanvasAndPost(canvas1);
}
}
}, 1000);
}
mHolder.unlockCanvasAndPost(canvas);
}
}
return false;
}
}
-----fragment_camera2_video.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.android.camera2video.AutoFitTextureView
android:id="#+id/texture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_below="#id/texture"
android:background="#4285f4">
<Button
android:id="#+id/video"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/record" />
<ImageButton
android:id="#+id/info"
android:contentDescription="#string/description_info"
style="#android:style/Widget.Material.Light.Button.Borderless"
android:layout_width="4dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|right"
android:padding="20dp"
android:src="#drawable/ic_action_info" />
</FrameLayout>
</RelativeLayout>
Only one thing can be drawing to a View at a time; once the SurfaceView is connected to the camera, you're not able to lock it for drawing yourself.
Your crash is probably because you're calling mHolder.unlockCanvasAndPost(canvas); outside of the null check.
If you want to draw over the cameara preview, you need a second View positioned on top of the SurfaceView.
I want to put Circle class into my layout. I tried it but app got stopped on creating. I think the problem is in xml code in the first line which is under. Kindly guide me.
<com.package.Circle
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/circle"
android:layout_width="300dp"
android:layout_height="300dp" />
XML file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.example.zohaib.animatedcircle.MainActivity"
tools:showIn="#layout/activity_main">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<com.package.Circle
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/circle"
android:layout_width="300dp"
android:layout_height="300dp" />
</RelativeLayout>
Circle.java
package com.example.zohaib.animatedcircle;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class Circle extends View {
private static final int START_ANGLE_POINT = 90;
private final Paint paint;
private final RectF rect;
private float angle;
public Circle(Context context, AttributeSet attrs) {
super(context, attrs);
final int strokeWidth = 40;
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(strokeWidth);
//Circle color
paint.setColor(Color.RED);
//size 200x200 example
rect = new RectF(strokeWidth, strokeWidth, 200 + strokeWidth, 200 + strokeWidth);
//Initial Angle (optional, it can be zero)
angle = 120;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint);
}
public float getAngle() {
return angle;
}
public void setAngle(float angle) {
this.angle = angle;
}
}
MainActivity.java
package com.example.zohaib.animatedcircle;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Circle circle = (Circle) findViewById(R.id.circle);
CircleAngleAnimation animation = new CircleAngleAnimation(circle, 240);
animation.setDuration(1000);
circle.startAnimation(animation);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
The XML element name needs to be the fully qualified class name of your custom View class. In this case, it would be com.example.zohaib.animatedcircle.Circle, instead of com.package.Circle.
<com.example.zohaib.animatedcircle.Circle
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/circle"
android:layout_width="300dp"
android:layout_height="300dp" />
I'm very new to Android development and trying to implement my own custom view which will allow me to use draw operations on a canvas. My custom view should draw a rectangle onto the screen in the onDraw() function, however it doesn't seem to work, no rectangle is drawn.
The very basic main activity that I'm trying to use the custom view with:
package com.example.testcanvas;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
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 ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
XML files for the activity, which I have tried to add the custom view to:
fragment main.xml
<RelativeLayout 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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.testcanvas.MainActivity$PlaceholderFragment" >
</RelativeLayout>
activity main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.testcanvas.MainActivity"
tools:ignore="MergeRootFrame" >
<com.example.testcanvas.CustomView
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="#+id/custom_view" />
</RelativeLayout>
and finally, my custom view class:
package com.example.testcanvas;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
public class CustomView extends SurfaceView implements SurfaceHolder.Callback {
public CustomView (Context context) {
super(context);
}
public CustomView (Context context, AttributeSet attrs) {
super(context);
}
#Override
public void onDraw (Canvas canvas) {
int dCenter = 40; //Distance from center in px, NOT in dp
int centerX = (int)(getWidth()/2);
int centerY = (int)(getHeight()/2);
Paint paint = new Paint();
paint.setColor(Color.BLUE); //The square will draw in the color blue now
Rect rect = new Rect(centerX-dCenter, centerY-dCenter, centerX+dCenter, centerY+dCenter);
canvas.drawRect(rect, paint);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
#Override
public void surfaceCreated(SurfaceHolder holder) {
setWillNotDraw(false); //Allows us to use invalidate() to call onDraw()
postInvalidate();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {}
}
Could anybody possibly point out where I've gone wrong? Thanks.
I have two ImageViews one of them located on top of another and both inside a frameLayout. As far as I know whatever we add in frameLayout will sit on the left top part of screen and we can set their position by setting a padding for them, So I've set paddings for both of ImageViews.
upperImage = (ImageView) findViewById(R.id.imageView1);
upperImage.setPadding(250,250, 250, 0);
lowerImage = (ImageView) findViewById(R.id.imageView2);
lowerImage.setPadding(250, 361, 250, 0); //250+Height of Image
I want to rotate my ImageViews and I'm almost done with that. the only thing I still haven't done is the location of pivot.
I want to set the pivot point on the center bottom of my ImageViews. I've tried many numbers but I didn't get the answer and didn't even find out how that method works. I mean I don't know what's the number it gets as an argument. Is that pixels or what?(I call the method for animations in onCreate method so I can't use getWidth() and getHeight() methods so I enter the numbers that these methods return myself.)
I have even tried different places to set pivot point in java and even XML layout. But that didn't make any changes.
All I want to know is how to set the pivot point at center bottom of my ImageView using setPivot methods?(They don't seem to be working methods) Can it be the problem with setting the point in onCreate method? If yes how can I make it work in onCreate?
Remember to put the actual graphic in the res folders for your bitmap and change the name in the constructor or whatever when it loads the bitmap
PivotView.java
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class PivotView extends View{
public Bitmap arm;
public Bitmap hand;
public int armrotation = 0;
public int handrotation = 0;
public PivotView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
arm = BitmapFactory.decodeResource(getResources(),R.drawable.arm );
hand = BitmapFactory.decodeResource(getResources(),R.drawable.hand );
}
#Override
protected void onDraw (Canvas canvas){
canvas.rotate((float)armrotation, 0, (float)canvas.getHeight());
canvas.drawBitmap(arm, new Rect(0,0,arm.getWidth(),arm.getHeight()), new Rect(0,
canvas.getHeight()*1/3,canvas.getWidth()*1/5,canvas.getHeight()), null);
Matrix matrix = new Matrix();
matrix.setRectToRect(new RectF(0,0,(float)hand.getWidth(),(float)hand.getHeight()), new RectF(0,
(float)canvas.getHeight()*1/4,(float)canvas.getWidth()*1/5,(float)canvas.getHeight()*4/10), Matrix.ScaleToFit.FILL);
matrix.preRotate((float)handrotation,(float)hand.getWidth()/2,(float)hand.getHeight());
canvas.drawBitmap(hand, matrix, null);
}
public void rotatArm(int rotate){
Log.d("arm", String.valueOf(rotate));
armrotation = rotate;
}
public void rotateHand(int rotate){
Log.d("hand", String.valueOf(rotate));
handrotation = rotate;
}
}
MainActivity.java
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
public class MainActivity extends Activity implements SeekBar.OnSeekBarChangeListener{
public SeekBar hand;
public SeekBar arm;
public PivotView robot;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
hand = (SeekBar)findViewById(R.id.seekhand);
hand.setMax(360);
arm = (SeekBar)findViewById(R.id.seekarm);
arm.setMax(90);
robot = (PivotView)findViewById(R.id.pivot);
hand.setOnSeekBarChangeListener(this);
arm.setOnSeekBarChangeListener(this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
switch(seekBar.getId()){
case R.id.seekarm:
rotatethearm(progress);
//robot.invalidate();
break;
case R.id.seekhand:
rotatethehand(progress);
//robot.invalidate();
break;
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
public void rotatethearm(int progress){
robot.rotatArm(progress);
robot.invalidate();
}
public void rotatethehand(int progress){
robot.rotateHand(progress);
robot.invalidate();
}
}
Make your layout like so with custom view, remember to use your package name in place where it says com.example.pivotview in the layout for the custom view
<RelativeLayout 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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.example.pivotview.PivotView
android:id="#+id/pivot"
android:layout_width="match_parent"
android:layout_height="match_parent"></com.example.pivotview.PivotView>
<SeekBar
android:id="#+id/seekarm"
android:layout_alignParentBottom = "true"
android:layout_width = "match_parent"
android:layout_height="wrap_content"/>
<SeekBar
android:id="#+id/seekhand"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/seekarm"
/>
</RelativeLayout>
I am trying to develop a simple map application, which will display a map in the screen.
When the user moves the cursor on screen, I want to display 2 perpendicular lines over my map. I had tried many examples to get an idea for that, but unfortunately, didn't succeed.
How can I make this?
And as one previous questionhere I had tried. but didn't get the answer. Can anyone guide me?
My main.xml is as following:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView android:id="#+id/main_imagemap"
android:src="#drawable/worldmap"
android:clickable="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
And my activity file(i had just started it..)
import android.app.Activity;
import android.os.Bundle;
import android.widget.ImageView;
public class LineMapActivity extends Activity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView map_image = (ImageView)findViewById(R.id.main_imagemap);
}
}
And as in that link, i had also added MyImageView.
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.widget.ImageView;
public class MyImageView extends ImageView
{
public MyImageView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
canvas.drawLine(0, 0, 20, 20, p);
super.onDraw(canvas);
}
}
Now how can i add this MyImageView to my app?
Finally I figured out a solution. It's a simple program which draws a line over an Image.
Here is my main.xml file (com.ImageDraw.MyImageView is my custom view, code below):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.ImageDraw.MyImageView android:id="#+id/main_imagemap"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
And here is the main activity:
import android.app.Activity;
import android.os.Bundle;
public class MyActivity extends Activity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
and this is my custom image view (MyImageView):
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MyImageView extends SurfaceView implements SurfaceHolder.Callback
{
private CanvasThread canvasthread;
public MyImageView(Context context) {
super(context);
getHolder().addCallback(this);
canvasthread = new CanvasThread(getHolder(), this);
setFocusable(true);
}
public MyImageView(Context context, AttributeSet attrs)
{
super(context,attrs);
getHolder().addCallback(this);
canvasthread = new CanvasThread(getHolder(), this);
setFocusable(true);
}
protected void onDraw(Canvas canvas) {
Log.d("ondraw", "ondraw");
Paint p = new Paint();
Bitmap mapImg = BitmapFactory.decodeResource(getResources(), R.drawable.mybitmap);
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(mapImg, 0, 0, null);
p.setColor(Color.RED);
canvas.drawLine(0, 0, 100, 100, p);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
canvasthread.setRunning(true);
canvasthread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
canvasthread.setRunning(false);
while (retry)
{
try
{
canvasthread.join();
retry = false;
}
catch (InterruptedException e) {
// TODO: handle exception
}
}
}
}
And finally here is my CanvasThread:
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class CanvasThread extends Thread
{
private SurfaceHolder surfaceHolder;
private MyImageView myImageView;
private boolean run = false;
public CanvasThread(SurfaceHolder s, MyImageView m)
{
surfaceHolder = s;
myImageView = m;
}
public void setRunning(boolean r)
{
run = r;
}
public void run()
{
Canvas c;
while(run)
{
c=null;
try
{
c= surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
myImageView.onDraw(c);
}
}
finally
{
if(c!=null)
{
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
You can find more details in this tutorial
Error you are getting because you are trying to casting ImageView object to MyImageView object.
Just fix the xml to include your object instead of an imageview like so (note that com.your.package.MyImageView should be the full package name of the package containing your class and then the class name)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.your.package.MyImageView android:id="#+id/main_imagemap"
android:src="#drawable/worldmap"
android:clickable="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>