I am trying to draw a single line in Android using canvas
My class :
public class LineDrawer extends View {
public LineDrawer(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setStrokeWidth(10);
float left = 20;
float top = 20;
float right = 50;
float bottom = 100;
canvas.drawLine(left, top, right, bottom, paint);
}
}
My Main Activity :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LineDrawer lineDrawer = new LineDrawer(this);
setContentView(R.layout.activity_Main);
}
}
I cannot find where is the problem , I try all the solutions in the internet but nothing happen , still a blank activity..
Should I import some code ?
lineDrawer is created but not added anywhere. Just creating a view is not enough, you need to add it to the current displayed views to be taken into account and drawn. You have two options:
Add it to your XML layout. You will have to add the following constructor to your custom view.
public LineDrawer(Context context, AttributeSet attrs) {
super(context, attrs);
}
Use addView(). Anyway, given how simple is your example, I'll use first (common) method.
As an additional comment, the Paint paint object should be created on view initialization, as is a costly operation. See in the original documentation for more information about this.
Related
I wrote the following code and it works well. But I have other purpose. I want to click only on a view to doing the operations.First, Please see the following image:
MY CODE IS AS FOLLOWS:
public class MainActivity extends Activity {
RelativeLayout relativeLayout;
#Override
protected void onCreate(Bundle bundle)
{ super.onCreate(bundle);
relativeLayout = new RelativeLayout(getApplicationContext());
setContentView(relativeLayout);
A a = new A(this);
relativeLayout.addView(a);
a.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
B b = new B(getApplicationContext());
relativeLayout.addView(b);
}
});
}
}
class A extends View {
Paint paint;
A(Context context) {
super(context);
paint = new Paint();
}
#Override
protected void onDraw(Canvas canvas) {
paint.setAntiAlias(true);
paint.setColor(Color.RED);
canvas.drawRect(20,60,100,150,paint);
}
}
class B extends View {
Paint paint;
B(Context context){
super(context);
paint = new Paint();
}
#Override
protected void onDraw(Canvas canvas){
paint.setAntiAlias(true);
paint.setColor(Color.GREEN);
canvas.drawRect(100,150,200,250,paint);
}
}
when I run the above code I can see the green rectangle after press on the red rectangle. But the problem is that when I press another places on the screen I can do this operations also. I want that only I can see the green rectangle to press on the red rectangle and not in the another places on the screen to doing this operations.
Use onTouch event
a.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getX(0)>=20 && event.getY(0)>=60 && event.getX(0)<=160 && event.getY(0)<=150) {
B b = new B(getApplicationContext());
relativeLayout.addView(b);
}
return true;
}
});
You are defining the red square's parameters but not the parameters of the canvas in which you are drawing. You are creating the view (A) without defining the width and height of it, so it is set to match_parent by default, which means it will take the whole size of your RelativeLayout (the whole screen). So, when you click "outside" the red square you are actually clicking the view (A).
Try to define an specific height and width for the view in which you are drawing, like this.
A a = new A(this);
a.setLayoutParams(new RelativeLayout.LayoutParams(300,300));
Remember that LayoutParams takes pixels as parameters, so you should really convert the dps to px as specified here
Also, setting some background colors to your views (relativeLayout, A) will help you visualize what you are doing.
# nukeforum, your guess helped me very much. I thank all of you. My problem was exactly from the canvas and its size. I added the following operation in my code and solved my problem.
relativeLayout.addView(a,70,70);
For A class, I changed as follows:
canvas.drawRect(10,20,30,40,paint);
I want to develop my application with a simple animation. I have used a lot of source from: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/Arcs.html
My code:
public class Animation extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
private static class AnimView extends View {
private Paint myPaint;
private Paint myFramePaint;
private RectF bigOval;
private float myStart;
private float mySweep;
private static final float SWEEP_INC = 1;
public AnimView(Context context) {
super(context);
init();
}
public AnimView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
myPaint = new Paint();
myPaint.setAntiAlias(true);
myPaint.setStyle(Paint.Style.FILL);
myPaint.setColor(Color.RED);
bigOval = new RectF(40, 10, 280, 250);
myFramePaint = new Paint();
myFramePaint.setAntiAlias(true);
myFramePaint.setColor(Color.BLACK);
}
private void drawArcs(Canvas canvas, RectF oval, boolean useCenter, Paint paint) {
canvas.drawRect(oval, myFramePaint);
canvas.drawArc(oval, myStart, mySweep, useCenter, paint);
}
#Override
protected void onDraw(Canvas canvas) {
drawArcs(canvas, bigOval, true, myPaint);
myStart = -90;
mySweep -= SWEEP_INC;
invalidate();
}
}}
I'm using my view in this way in my xml file:
<view
class="go.android.Animation$AnimView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
It works properly. I know that it isn't custom animation. But is this possible to set speed of this animation (in ms or seconds)? Or to stop this animation (for example in the OnClick or OnTouch Listener), and get to know when this animation has finished?
I also want to get first whole circle, and on the end of animation - lack of circle. Simply to change direction of this animation. Is this possible?
I don't want to use frame-by-frame animation. I want to get continuous animation. Is there any possibilities to get similar animation (with setting speed, etc...)
I also want to animate not only a color but rather a round drawable.
Thank you in advance. Sorry for my English skill.
There might be better and more precise ways to control your animation than this (you could look into using OpenGL), but you can change the speed and direction of the animation relatively easily given your existing code.
The speed is controlled by the SWEEP_INC field (which stands for Sweep Increment I would guess). Every time the onDraw() method is called, it increases the size of the wedge by 1 degree. If you want the animation to go 5 times as fast, set SWEEP_INC to 5 instead of 1. If you want the animation to go half as fast, set SWEEP_INC to 0.5.
You can also just set a flag to reverse the animation each time it finishes. I've modified your code to reverse each time it reaches the end, using the addToCircle boolean.
public class Animation extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
private static class AnimView extends View {
private Paint myPaint;
private Paint myFramePaint;
private RectF bigOval;
private float myStart;
private float mySweep;
private float SWEEP_INC = 1;
//Use this flag to control the direction of the arc's movement
private boolean addToCircle = true;
public AnimView(Context context) {
super(context);
init();
}
public AnimView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
myPaint = new Paint();
myPaint.setAntiAlias(true);
myPaint.setStyle(Paint.Style.FILL);
myPaint.setColor(Color.RED);
bigOval = new RectF(40, 10, 280, 250);
myFramePaint = new Paint();
myFramePaint.setAntiAlias(true);
myFramePaint.setColor(Color.BLACK);
}
private void drawArcs(Canvas canvas, RectF oval, boolean useCenter, Paint paint) {
canvas.drawRect(oval, myFramePaint);
canvas.drawArc(oval, myStart, mySweep, useCenter, paint);
}
public void setIncrement(float newIncrement)
{
SWEEP_INC = newIncrement;
}
#Override
protected void onDraw(Canvas canvas) {
drawArcs(canvas, bigOval, true, myPaint);
myStart = -90;
//If the arc is currently getting bigger, decrease the value of mySweep
if(addToCircle)
{
mySweep -= SWEEP_INC;
}
//If the arc is currently getting smaller, increase the value of mySweep
else
{
mySweep += SWEEP_INC;
}
//If the animation has reached the end, reverse it
if(mySweep%360 == 0)
{
addToCircle = !addToCircle;
}
invalidate();
}
}
}
EDIT
If you remove the final and static modifiers from SWEEP_INC you can change the speed of the animation at runtime using the setIncrement(float newIncrement) function I've added.
You can stop the animation by calling setIncrement(0).
However, I don't think there is a constant rate at which onDraw is called. So I don't know of any way to assign a duration in seconds to this animation. For that you may want to look into more sophisticated methods of animation.
I need your experience.
Problem : I need to be able to draw thing (rect, circ,etc) on one part of a FlipperView....
My main.xml has a main linearLayout. In this LinearLayout I have a ViewFlipper with 2 linearlayouts in it. The first linearlayout has soms buttons, inputfiels,etc... the second one should have a special view in wich I can draw the things I choose in the first part.
So I have created a new view wich extends the View class so I can play with the ondraw methode. But I can not get it to work.
This is what I have so far...
MAIN.XML
<LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="#+id/layout_main" xmlns:android="http://schemas.android.com/apk/res/android">
<ViewFlipper android:id="#+id/details" android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:orientation="vertical" android:layout_height="match_parent">
//BUTTONS TEXTFIELDS ETC
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:orientation="vertical" android:layout_height="match_parent">
//an instance of my new ViewClass
<Vierbergen.Tim.ViewClass
android:id="#+id/draw" android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</ViewFlipper>
</LinearLayout>
The VIEWCLASS.java
public class ViewClass extends View {
Paint paint = new Paint();
public DrawView(Context context) {
super(context);
paint.setColor(Color.WHITE);
}
#Override
public void onDraw(Canvas canvas) {
//depending on some params....
draw this, draw that...
}
}
and then my main activity
DRAWER.JAVA
public class SmsDraw extends Activity implements OnTouchListener{
ViewClass vClass;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
vClass = (ViewClass) findViewById(R.id.draw);
}
// with somewhere a draw function excecuted by a button
private void start() {
//where can I get a canvas ? Canvas c = new Canvas();
blablalba
vClass.onDraw(c);
}
So I need to be able to draw on the thing VIEWCLASS with id = draw in my main.xml...
How can I do this ? please help me with an explanation and solution and not just a solution :-)
Thanks VeeTee
Your onDraw method will be called by the framework if your View is attached to the view hierarchy. You don't need to call it yourself.
If you're unsure about your onDraw code, try using the code from a sample like DrawPoints in API Demos.
You don't call onDraw yourself, as Matthew has said. Here's a very simple addition to your ViewClass that would allow you to draw rectangles or circles. It hasn't been tested, so proceed carefully.
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class DrawView extends View {
private boolean drawRect;
private boolean drawCircle;
private float rect_w;
private float rect_h;
private int rect_color;
private float circle_radius;
private int circle_color;
Paint paint;
public DrawView(Context context) {
super(context);
paint = new Paint();
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
}
public DrawView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
paint = new Paint();
}
public void drawRect(float w, float h, int color) {
// define these variables privately at the top of the class
this.drawRect = true;
this.drawCircle = false;
this.rect_w = w;
this.rect_h = h;
this.rect_color = color;
}
public void drawCircle(float radius, int color) {
// define these variables privately at the top of the class
this.drawRect = false;
this.drawCircle = true;
this.circle_radius = radius;
this.circle_color = color;
}
#Override
public void onDraw(Canvas canvas) {
if (drawRect) {
paint.setColor(this.rect_color);
canvas.drawRect(0, 0, rect_w, rect_h, paint);
}
if (drawCircle) {
paint.setColor(this.circle_color);
canvas.drawCircle(0, 0, circle_radius, paint);
}
}
}
Then in your view Class, call it like this:
vClass = (DrawView) findViewById(R.id.draw);
vClass.drawRect(3,4,0x334434);
Seems like the problem it wasn't working the first time was...
when the main activity want to setContentView(...)... it crashes....
But when I leave it out of the xml
and create it at runtime like this
viewClass = new ViewClass(this);
layke = (LinearLayout) findViewById(R.id.layoutDraw);//wich is the second part of the flipperview
layke.addView(viewClass); // to at it to the right layout
it works....
My project is about image processing in android.I have a bitmap that I have loaded from a resource file (an PNG image). I want to draw it. But I couldn't.
Here my code snippet:
mB = BitmapFactory.decodeResource(getResources(), R.drawable.picture);
Canvas c = new Canvas(mB);
Paint p = new Paint();
c.drawBitmap(mB,0,0,p);
it didn't work. Is the code true? .Is there any thing more that I must do?
You should use an ImageView instead and load it by
imageView.setImageResource(R.drawable.picture);
If you want to manually draw it with a Canvas, you have to use a canvas that is passed into a draw() method and implement a Custom View.
Update to add example CustomView:
public class CustomView extends View {
private Paint mPaint;
private Drawable mDrawable;
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mDrawable = context.getResources().getDrawable(R.drawable.some_drawable);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDrawable.draw(canvas);
}
}
There are a couple of things you are missing.
First, I think you're misunderstanding the Canvas(Bitmap b) constructor. The Bitmap passed in there is one that the Canvas will draw into. This could be just a new Bitmap that you constructed.
Second, it is recommended that you use the Canvas that is passed to you in your View's onDraw method. Presumably that View is one from your Activity, either fetched from your XML layout via findViewById or constructed and passed to setContentView in the Activity's onCreate() method.
So, you are going to have to subclass View and override the onDraw method to get your drawing done. Something like:
public class MyView extends View {
#Override
public void onDraw (Canvas c) {
Bitmap mB = BitmapFactory.decodeResource(this.getContext().getResources(), R.drawable.picture);
c.drawBitmap(mB, 0, 0, null);
}
}
Then, in your Activity, you'll need to create an instance of your new View and pass it to the Activity via setContentView:
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mv = new MyView(this);
setContentView(mv);
}
You can instead call the setContentView(View v, ViewGroup.LayoutParameters lp) overload if you want to set up the LayoutParameters.
I haven't tested any of this, but it should at least get you on the right path.
I'm creating a custom widget by extending LinearLayout:
public class MyWidget extends LinearLayout {
private static Paint PAINT = new Paint(Paint.ANTI_ALIAS_FLAG);
static {
PAINT.setColor(Color.RED);
}
public MyWidget(Context context) {
this(context, null);
}
public MyWidget(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight()/2, canvas.getWidth()/2, PAINT);
// never gets called :-(
}
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
// this gets called, but with a canvas sized after the padding.
}
}
I can add children just fine, but I'm never getting my custom onDraw() being called. dispatchDraw() gets called, but that seems to have a different canvas (the one that's within the padding. I need to draw on the whole layout area). Is there some flag that needs to get set to get onDraw() called for the layout?
You need to call setWillNotDraw(false) in your constructor.
Because by default a layout does not need to draw, so an optimization is to not call is draw method. By calling setWillNotDraw(false) you tell the UI toolkit that you want to draw.