I am creating a custom view but the onDraw method is never being called. I tried doing this - setWillNotDraw(false) but it still doesn't work.
In fact, it doesn't even work after calling invalidate(). Here's my code -
public class Box extends View {
public Box (Context context) {
super (context);
init();
}
private void init() { // Initialize paint object
paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(mBoxColor);
setMeasuredDimension(200, 200);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(100, 100, 200, 200, paint);
}
}
My activity code -
Box box = new Box(this);
Please help
In your MainActivity.java
use
setContentView(box);
Related
I'm creating an Android game (basic game), and got stuck with displaying certain image on a canvas.
The game intention is to press the image and the image will change it's location.
I've made sure all the methods are written properly and image resource does exist.
The other questions which relates to "canvas isn't showing" here didn't assist me because my game doesn't involve any XML (yet).
I've followed this guide:
https://www.androidauthority.com/android-game-java-785331/
This is the my GameView class which suppose to create the image:
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
public GameView(Context context) {
super(context);
getHolder().addCallback(this);
thread = new MainThread(getHolder(), this);
setFocusable(true);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Canvas canvas=new Canvas();
thread.setRunning(true);
thread.start();
characterSprite = new CharacterSprite(BitmapFactory.decodeResource(getResources(),R.drawable.avdgreen));
characterSprite.draw(canvas);
}
#Override
public void draw(Canvas canvas){
super.draw(canvas);
characterSprite.draw(canvas);
}
}
My CharacterSprite class:
public CharacterSprite(Bitmap png) {
image = png;
x=100;
y=100;
}
public void draw(Canvas canvas) {
canvas.drawBitmap(image, 100, 100, null);
}
The Image should appear on the screen, yet all I get is blank screen.
Thanks.
I've setted up a simple application that once I have structured a Canvas puts an Rectangle inside it. I was asking myself if there's a method that allows me to fill that rettangle with an image.
This is my Canvas Class code:
public class MioCanvas extends View {
Paint paint;
Rect rect;
public MioCanvas(Context context) {
super(context);
paint = new Paint();
rect = new Rect();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.GRAY);
paint.setStrokeWidth(3);
canvas.drawRect(0, 1999999, canvas.getWidth() / 2, canvas.getHeight() / 2, paint);
}
}
This is my activity code:
public class MainActivity extends AppCompatActivity {
MioCanvas mioCanvas;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mioCanvas = new MioCanvas(this);
mioCanvas.setBackgroundColor(Color.GREEN);
setContentView(mioCanvas);
}
}
You can use a Bitmap with your custom rect as input.
Rect rectangle = new Rect(0,0,100,100);
canvas.drawBitmap(bitmap, null, rectangle, null);
it seems I have a problem understanding classes. It would be great if someone could help.
I'm trying to populate my Smartphone screen (android) with 3 circles of different color.
My problem is that by using the code below I only get one (blue) circle.
I considered that the Problem is that the y-value isn't set correctly and the 3 circles are hiding each other (so that only the blue one is visible). But when I log the y-value of the 3 circle objects, the y-values seem to be correct (200,500,800)
Whats am I doing wrong?
Thanks for your help in advance.
public class MainActivity extends Activity {
public Circle circleR;
public Circle circleG;
public Circle circleB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
circleR = new Circle(this, 200, 255, 0, 0);
setContentView(circleR);
circleG = new Circle(this, 500, 0, 255, 0);
setContentView(circleG);
circleB = new Circle(this, 800, 0, 0, 255);
setContentView(circleB);
}
}
public class Circle extends View {
public Paint paint;
public int y;
public Circle(Context context,int y, int r, int g, int b){
super(context);
paint=new Paint();
paint.setColor(Color.rgb(r,g,b));
this.y=y;
}
#Override
protected void onDraw(Canvas canvas){
canvas.drawCircle(30, this.y,30, paint);
}
}
The problem lies in setting the content view multiple times. Only the view set as last (the one with a blue circle) will be visible. If you want multiple circles to be visible at the same time you should draw them on one canvas localized inside one view. I rearranged your code so that it does what you wanted:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CirclesView circlesView = new CirclesView(this);
setContentView(circlesView);
}
}
public class CirclesView extends View {
public Circle circleR;
public Circle circleG;
public Circle circleB;
public CirclesView(Context context) {
super(context);
circleR = new Circle(200, 255, 0, 0);
circleG = new Circle(500, 0, 255, 0);
circleB = new Circle(800, 0, 0, 255);
}
#Override
protected void onDraw(Canvas canvas){
circleR.draw(canvas);
circleG.draw(canvas);
circleB.draw(canvas);
}
}
public class Circle {
public Paint paint;
public int y;
public Circle(int y, int r, int g, int b) {
paint = new Paint();
paint.setColor(Color.rgb(r,g,b));
this.y=y;
}
public void draw(Canvas canvas) {
canvas.drawCircle(30, this.y,30, paint);
}
}
Circle knows how to draw itself on a canvas which will be provided to it by a view.
I get 3 warning for object allocation during draw/layout
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
Paint textPaint = new Paint();
textPaint.setARGB(50,100,100,250);
textPaint.setTextAlign(Align.CENTER);
textPaint.setTextSize(50);
textPaint.setTypeface(font);
canvas.drawText("Logan is awesom",canvas.getWidth()/2,200,textPaint);
canvas.drawBitmap(pBall, (canvas.getWidth()/2), changingY, null);
if (changingY <canvas.getHeight()){
changingY += 10;
}else{
changingY=0;
}
Rect middleRect = new Rect();
middleRect.set(0, 400, canvas.getWidth(), 550);
Paint ourBlue = new Paint();
ourBlue.setColor(Color.BLUE);
canvas.drawRect(middleRect, ourBlue);
I get an error on new Rect();
and on both new Paint();
The exact error is avoid object allocation during draw/layout operations (prelocate and reuse instead)
Well, your 'error' points to exact problem. onDraw() method is called by OS many-many times, thus allocating something within this function is extremely bad idea.
You need to allocate your Rect and Paint beforehand and just use them within onDraw
class YourClass extends View
{
Rect middleRect;
Paint ourBlue;
Paint textPaint;
public YourClass()
{
//constructor
init();
}
private void init()
{
middleRect = new Rect();
ourBlue; = new Paint();
textPaint = new Paint();
ourBlue.setColor(Color.BLUE);
textPaint.setARGB(50,100,100,250);
textPaint.setTextAlign(Align.CENTER);
textPaint.setTextSize(50);
textPaint.setTypeface(font);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
canvas.drawText("Logan is awesom",canvas.getWidth()/2,200,textPaint);
canvas.drawBitmap(pBall, (canvas.getWidth()/2), changingY, null);
if (changingY <canvas.getHeight()){
changingY += 10;
}else{
changingY=0;
}
//if canvas size doesn't change - this can be moved to init() as well
middleRect.set(0, 400, canvas.getWidth(), 550);
canvas.drawRect(middleRect, ourBlue);
}
}
For me, I have got this error in layout especially when using display metrices.
I have used this imageview :
<com.steve.thirdparty.ScalableImageView
android:id="#+id/iv_posted_img_home"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:background="#drawable/golive_load_image"
android:layout_below="#+id/tv_user_posted_msg_post_items_home"
android:contentDescription="#string/cont_desc"/>
ScalableImageView.java:
import static com.steve.TabHomeActivity.displaymetrics;
public class ScalableImageView extends ImageView {
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
}
I solved this issue by adding the static DisplayMetrices in onCreate() method in Activity.
TabHomeActivity.java:
public static DisplayMetrics displaymetrics;
*inside onCreate()*
displaymetrics = new DisplayMetrics();
avoid object allocation during draw/layout operations (prelocate and reuse instead)
The message give You a solution on plate, so I don't understand what is Your question.
You have to move creation of new objects to onCreate method, so they are created just once and use them later in onDraw method.
I am trying to create an object that can be called whenever I want to draw something on the onDraw() function of my class. Here is my code which is not working:
//object class
public class DrawObject extends Canvas {
Paint paint = new Paint();
public void setColor(int color){
paint.setColor(color);
}
// I want to draw an arrow to instead of a line
public void drawArrow(float startPointX, float startPointY, float endPointX, float endPointY){
drawLine(startPointX, startPointY, endPointX, endPointY, paint);
// draw the rest of the arrow here
}
}
for the main class:
public class Screen extends ImageView{
Paint paint = new Paint();
public Screen(Context context){
super(context);
paint.setColor(Color.BLACK);
paint.setStyle(Style.STROKE);
}
public void onDraw(DrawObject drawObject){
//called DrawObject instead on Canvas
drawObject.drawArrow(10,10,100,100);
// I want to draw the arrow here but it is not working.
}
can someone please tell me what is the proper way to do it? Thanks.
I would actually do something along these lines:
Define an interface for drawable objects (to avoid confusion with the Android Drawable class, I've called it Paintable)
public interface Paintable {
public void paint(Canvas canvas) {}
}
Make any classes that you need to draw in a custom manner, such as the arrow you suggested, implement the Paintable interface, and override paint(Canvas canvas) and handle your drawing operations there.
public class Arrow implements Paintable {
//all sorts of cool shit here to define your arrow
#Override
public void paint(Canvas canvas) {
//draw your arrow on the canvas here
}
}
Maintain a list of Paintable objects in your custom ImageView, and simply call the paint() method for each object in the list. Yay for polymorphism!
public class Screen extends ImageView {
List<Paintable> paintableObjects;
public Screen(Context context) {
super(context);
paint.setColor(Color.BLACK);
paint.setStyle(Style.STROKE);
paintableObjects = new ArrayList<Paintable>();
}
public void addPaintable(Paintable p) {
paintableObjects.add(p);
}
public void onDraw(Canvas canvas) {
for(Paintable p : paintableObjects) {
p.paint(canvas);
}
}
}
Extending Canvas is the wrong approach since you get a canvas supplied by the system which you have to use. You can't force Android to use your subclass of Canvas. Instead you can simply pass the Canvas to your class whenever it needs it.
public class DrawObject {
Paint paint = new Paint();
public void setColor(int color) {
paint.setColor(color);
}
// I want to draw an arrow to instead of a line
public void drawArrow(Canvas canvas, float startPointX, float startPointY, float endPointX, float endPointY) {
canvas.drawLine(startPointX, startPointY, endPointX, endPointY, paint);
// draw the rest of the arrow here
}
}
And use like
public void onDraw(Canvas canvas){
drawObject.drawArrow(canvas, 10,10,100,100);
// I want to draw the arrow here but it is not working.
}
I really don't see the reason of extending the Canvas and defining your own object, unless you need to have some special control over it.
Normally you extend View and do all the drawing stuff in the onDraw() method through the Canvas object, ex:
public void onDraw(Canvas canvas){
canvas.drawLine(startPointX, startPointY, endPointX, endPointY, paint);
}
this bit is wrong
public void onDraw(DrawObject drawObject){ ... }
onDarw is a frame work method so sice you change the method signature this method will not be called.
There is no need to subclass canvas - its not the right approach.
so in you Screen class - override the standard onDraw method:
public void onDraw(Canvas c){
drawLine(startPointX, startPointY, endPointX, endPointY, paint);
}
to trigger the onDraw mthod programatically - call invalidate() on the Screen object.