Canvas draw circles horizontally in android view - android

I'm trying to draw 4 circles horizontally in a view. But the problem is I see only 3 half circles. Circles are not being drawn properly. What is wrong with below code?
CircleView.java
public class CircleView extends View
{
private int radius;
private Paint blackPaint = new Paint();
float eachDotWidth;
float x = 0;
float circleRadius;
float width, height;
public CircleView(Context context)
{
this(context, null);
}
public CircleView(Context context, AttributeSet attrs)
{
super(context, attrs);
blackPaint.setStyle(Paint.Style.STROKE);
blackPaint.setColor(Color.BLACK);
blackPaint.setStrokeWidth(5f);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
calculateDimensions();
}
private void calculateDimensions()
{
width = getWidth() ;
height = getHeight();
invalidate();
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
width = getWidth();
height = getHeight();
eachDotWidth = getWidth()/5;
circleRadius = getHeight()/2;
canvas.drawColor(Color.WHITE);
for(int i=0; i < 4; i++) {
x=(i*eachDotWidth)-circleRadius;
canvas.drawCircle(x, 2*circleRadius, circleRadius/2, blackPaint);
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
FrameLayout circleLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
circleLayout = (FrameLayout) findViewById(R.id.circle_layout);
CircleView circleView = new CircleView(this);
circleLayout.addView(circleView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
}
Please help me find and resolve the issue. Thanks.

You can create vertically circles:
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
width = getWidth();
height = getHeight();
eachDotWidth = getWidth()/8;
circleRadius = getHeight()/2;
canvas.drawColor(Color.WHITE);
for(int i=0; i < 4; i++) {
x=(2*i*eachDotWidth)+eachDotWidth;
canvas.drawCircle(x, eachDotWidth, eachDotWidth, blackPaint);
}
}
Also you can create horizontally circles:
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
width = getWidth();
height = getHeight();
eachDotWidth = getWidth()/8;
circleRadius = getHeight()/8;
canvas.drawColor(Color.WHITE);
for(int i=0; i < 4; i++) {
x=(2*i*circleRadius)+circleRadius;
canvas.drawCircle(circleRadius, x, circleRadius, blackPaint);
}
}
And also you can create diagonal circles (create y variable):
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
width = getWidth();
height = getHeight();
eachDotWidth = getWidth()/8;
circleRadius = getHeight()/8;
canvas.drawColor(Color.WHITE);
for(int i=0; i < 4; i++) {
y=(2*i*circleRadius)+circleRadius;
x=(2*i*eachDotWidth)+eachDotWidth;
canvas.drawCircle(x, y, circleRadius, blackPaint);
}
}

I think you need to revise the code drawing the circles. I don't know why you, for example, have separate values for a circle's radius and a "dot's width". I suggest that you count only with an each circle's (~ dot's) radius and add some spacing in between them to compound the width to suit your needs.
Try something like this (it draws four equal circles at zero coordinates across the canvas' width, but it doesn't account for the stroke's thickness):
// we want four equal circles across the whole width, so each circle's radius will be equal to 'width/(2*4)'
circleRadius = width/8;
// zero spacing for this example, but it can be defined
int spacingPx = 0;
canvas.drawColor(Color.WHITE);
for(int i=0; i < 4; i++) {
// the x-coordinate of each circle's middle will be a circle's radius offset by the width of the circles previously drawn plus a single spacing width multiplied by the number of the circles already drawn
x=(i*2*circleRadius) + circleRadius + i*spacingPx;
// we just simply pass the values – calculated x coordinate, y coordinate (here we want to have the circle's top at 0, so we need to set its middle y-coordinate to the value of its radius), the circle's radius and the Paint object that you already defined
canvas.drawCircle(x, circleRadius, circleRadius, blackPaint);
}
Here's how it looks like
If you want to customize it more to your needs, please specify how exactly would you like the circles to be drawn.

Using a Path and a RectF is more flexible if you want to draw shapes, you can take a look at this tutorial :
http://raphaelfavero.github.io/Creating_Animated_Custom_View/

Related

Draw Curved Text on Canvas with different length of Text in android

I need to implement curved text which draw text on circular path on canvas.
It does draw circular path using
canvas.drawTextOnPath(QUOTE, circle, 485, 20, tPaint);
but it is not working for different length of the text.
Following is my Class to draw circular text on the canavs.
public class CircularTextVie extends View {
private String QUOTE = "";
private Path circle;
private Paint cPaint;
private Paint tPaint;
public CircularTextVie(Context context) {
super(context);
circle = new Path();
cPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
cPaint.setStyle(Paint.Style.STROKE);
cPaint.setColor(Color.LTGRAY);
cPaint.setStrokeWidth(3);
tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
tPaint.setStyle(Paint.Style.FILL_AND_STROKE);
tPaint.setColor(Color.BLACK);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.restore();
int xPos = (canvas.getWidth() /3);
int yPos = (int) ((canvas.getHeight() / 3) - ((tPaint.descent() + tPaint.ascent()) / 3)) ;
circle.addCircle(xPos, yPos, 150, Path.Direction.CW);
canvas.drawTextOnPath(QUOTE, circle, 485, 20, tPaint);
QUOTE="";
}
public void SetText(String text) {
this.QUOTE = text;
}
public void SetTypeFace(Typeface face) {
cPaint.setTypeface(face);
tPaint.setTypeface(face);
}
public void SetColor(int color) {
cPaint.setColor(color);
tPaint.setColor(color);
}
}
Thanks.
This can be done by varying the x and y positions based on textwidth
Define variables
private Rect textBounds;
private int mTextWidth, mTextHeight,centerX,centerY;
Add the below in the constructor of customview
textBounds = new Rect();
tPaint.getTextBounds(QUOTE, 0, QUOTE.length(), textBounds);
mTextWidth = Math.round(tPaint.measureText(QUOTE.toString())); // Use measureText to calculate width
mTextHeight = textBounds.height(); // Use height from getTextBounds()
Then in onDraw
canvas.drawCircle(centerX,centerY,150,mCirlcePaint);
circle.addCircle(centerX, centerY, 150, Path.Direction.CW);
// Note the 0 that's y offset. textdraw at circumference of the circle. Changing y you probably need to change the radius as well i guess.
canvas.drawTextOnPath(QUOTE, circle, (centerX)-(mTextWidth / 2f), 0, tPaint);
centerX,centerY are the center of the circle ie canvaswidht/2 and canvasHeight/2. I drew a circle for reference
The results for hello
The result for a bigger text
For numbers
Edit: To the question in comment
The math involved is in calculating the semi circle using text length
radius = (float) ((mTextWidth) / (Math.PI)). If text length is greater than your canvas you need to reduce the text size or use the full circle radius = (float) ((mTextWidth) / (2*(Math.PI))). Few other edge case you can consider to draw the text properly.
public class GraphicsView extends View {
private String QUOTE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private Path circle;
private Paint mCirlcePaint;
private Paint tPaint;
private Rect textBounds;
private int mTextWidth, mTextHeight, centerX, centerY;
private float radius;
public GraphicsView(Context context) {
super(context);
circle = new Path();
tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
tPaint.setStyle(Paint.Style.FILL_AND_STROKE);
tPaint.setColor(Color.BLACK);
tPaint.setTextSize(100f);
textBounds = new Rect();
tPaint.getTextBounds(QUOTE, 0, QUOTE.length(), textBounds);
mTextWidth = Math.round(tPaint.measureText(QUOTE.toString())); // Use measureText to calculate width
mTextHeight = textBounds.height(); // Use height from getTextBounds()
mCirlcePaint = new Paint();
mCirlcePaint.setStyle(Paint.Style.FILL);
mCirlcePaint.setColor(Color.GREEN);
radius = (float) ((mTextWidth) / (Math.PI));
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
centerX = w / 2;
centerY = h / 2;
}
#Override
protected void onDraw(Canvas canvas) {
canvas.rotate(180, getWidth() / 2, getHeight() / 2);
canvas.drawCircle(centerX, centerY, radius, mCirlcePaint);
circle.addCircle(centerX, centerY, radius, Path.Direction.CW);
canvas.drawTextOnPath(QUOTE, circle, 0, 0, tPaint);
}
}

Place view in activity programmatically

I'm trying to draw a circumference that would represent the battery life in a activity.
My parent layout is a relative layout.
This is the inner class that draws the view:
public class DrawView extends View {
Paint mPaint = new Paint();
public DrawView(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG |
Paint.DITHER_FLAG |
Paint.ANTI_ALIAS_FLAG);
mPaint.setDither(true);
mPaint.setColor(Color.GRAY);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(1);
int size = 200;
int radius = 190;
int delta = size - radius;
int arcSize = (size - (delta / 2)) * 2;
int percent = 42;
//Thin circle
canvas.drawCircle(size, size, radius, mPaint);
//Arc
mPaint.setColor(getResources().getColor(R.color.eCarBlue));
mPaint.setStrokeWidth(15);
RectF box = new RectF(delta,delta,arcSize,arcSize);
float sweep = 360 * percent * 0.01f;
canvas.drawArc(box, 0, sweep, false, mPaint);
}
}
And in onCreate() I start the view this way:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
...
ViewGroup myLayout = (ViewGroup) findViewById(R.id.mainlayout);
drawing = new DrawView(this);
myLayout.addView(drawing);
}
But I need to locate this view in the layout, especifically in the center of it. To achieve this, I have modified onCreate()'s code this way:
ViewGroup myLayout = (ViewGroup) findViewById(R.id.mainlayout);
drawing = new DrawView(this);
RelativeLayout.LayoutParams layoutParams= new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
drawing.setLayoutParams(layoutParams);
myLayout.addView(drawing);
But it isn't having effect on the view. What would be then the correct way to define the params for the view?
You're adding DrawView with LayoutParams.WRAP_CONTENT, which means the system needs to ask the view its width and height. You should implement onMeasure() for that. But I've never done that so don't know the details.
Another way is to just use LayoutParams.MATCH_PARENT and draw your stuff in onDraw() centered yourself. In this case you will need to know the width and height of the canvas in order to calculate the coordinates of your draw calls. Calling getWidth() in onDraw() does not give you the expected results. You need to override onSizeChanged() and record the new width and height, like this:
private int canvasWidth;
private int canvasHeight;
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasWidth = w;
canvasHeight = h;
}
Then in onDraw() you can use canvasWidth and canvasHeight because the onSizeChanged() has already happened.

How do I create horizontal lines in multiline edittext on each line using xml? [duplicate]

I was taking a look at the notepad sample in the android SDK see here: http://developer.android.com/resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html
Thing is it only draws the current line the cursor is on e.g http://cdn2.staztic.com/screenshots/simple-notepad-app-al-1.jpg
But I'd like to display lines that fill up the screen e.g. http://www.itismyworld.info/wp-content/uploads/2010/03/AK-notebook.png
Any suggestions would be great. The relevent bit of code seems to be here:
protected void onDraw(Canvas canvas) {
// Gets the number of lines of text in the View.
int count = getLineCount();
// Gets the global Rect and Paint objects
Rect r = mRect;
Paint paint = mPaint;
/*
* Draws one line in the rectangle for every line of text in the EditText
*/
for (int i = 0; i < count; i++) {
// Gets the baseline coordinates for the current line of text
int baseline = getLineBounds(i, r);
/*
* Draws a line in the background from the left of the rectangle to the right,
* at a vertical position one dip below the baseline, using the "paint" object
* for details.
*/
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
}
// Finishes up by calling the parent method
super.onDraw(canvas);
}
This is the code, based on jkhouws1's suggestion and google's note editor
public class LinedEditText extends EditText {
private Rect mRect;
private Paint mPaint;
// we need this constructor for LayoutInflater
public LinedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(R.color.edit_note_line); //SET YOUR OWN COLOR HERE
}
#Override
protected void onDraw(Canvas canvas) {
//int count = getLineCount();
int height = getHeight();
int line_height = getLineHeight();
int count = height / line_height;
if (getLineCount() > count)
count = getLineCount();//for long text with scrolling
Rect r = mRect;
Paint paint = mPaint;
int baseline = getLineBounds(0, r);//first line
for (int i = 0; i < count; i++) {
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
baseline += getLineHeight();//next line
}
super.onDraw(canvas);
}
}
In Eclipse IDE press Ctrl+Shift+O to add all needed imports
I think this is what you need:
public class LinedEditText extends EditText {
private static Paint linePaint;
static {
linePaint = new Paint();
linePaint.setColor(Color.BLACK);
linePaint.setStyle(Style.STROKE);
}
public LinedEditText(Context context, AttributeSet attributes) {
super(context, attributes);
}
#Override
protected void onDraw(Canvas canvas) {
Rect bounds = new Rect();
int firstLineY = getLineBounds(0, bounds);
int lineHeight = getLineHeight();
int totalLines = Math.max(getLineCount(), getHeight() / lineHeight);
for (int i = 0; i < totalLines; i++) {
int lineY = firstLineY + i * lineHeight;
canvas.drawLine(bounds.left, lineY, bounds.right, lineY, linePaint);
}
super.onDraw(canvas);
}
}
maybe after that for loop, you draw estimated* additional lines.
getHeight() will return EditText's height in pixels
getLineHeight() will height of one standard line
so getHeight/getlineHeight-getCount will be number of lines left to draw.
you can't use getLineBounds, using the above functions you could calculate the position of the remaining lines to draw.
*Estimated since formatting of text could change the line height, but since there is no text in these lines yet that shouldnt be an issue. But for that same reason you should only draw the remaining lines, and not use this to draw all the lines.
<com.example.goh2.pronoornotepad.LinedEditText
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffcc4b"
android:gravity="top|left"
android:singleLine="false"
android:text=""
/>
The above XML works with the code from Max4ever's answer:
public class LinedEditText extends EditText {
private Rect mRect;
private Paint mPaint;
// we need this constructor for LayoutInflater
public LinedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(R.color.edit_note_line); //SET YOUR OWN COLOR HERE
}
#Override
protected void onDraw(Canvas canvas) {
//int count = getLineCount();
int height = getHeight();
int line_height = getLineHeight();
int count = height / line_height;
if (getLineCount() > count)
count = getLineCount();//for long text with scrolling
Rect r = mRect;
Paint paint = mPaint;
int baseline = getLineBounds(0, r);//first line
for (int i = 0; i < count; i++) {
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
baseline += getLineHeight();//next line
}
super.onDraw(canvas);
}
}

Creating game gravity in Android?

I am trying to create in game gravity in Android. I created an update method, a display, and gravity. Right now the app does not force close, but the ball just doesn't move. Do I need to use a canvas for the .getHieght() and .getWidth() methods?
public class MainActivity extends Activity {
private int c = Color.YELLOW;
private Canvas g;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
draw();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
// draws the ball
public void draw ()
{
Display display = getWindowManager().getDefaultDisplay();
int width = display.getHeight();
int height = display.getWidth();
Bitmap bitmap = Bitmap.createBitmap(width, height, Config.RGB_565);
g = new Canvas(bitmap);
g.drawColor(c);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
g.drawCircle(50, 10, 25, paint); //Put your values
update();
// In order to display this image, we need to create a new ImageView that we can display.
ImageView imageView = new ImageView(this);
// Set this ImageView's bitmap to ours
imageView.setImageBitmap(bitmap);
// Create a simple layout and add imageview to it.
RelativeLayout layout = new RelativeLayout(this);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
layout.addView(imageView, params);
layout.setBackgroundColor(Color.BLACK);
// Show layout in activity.
setContentView(layout);
}
private void update(){
// wall collisions;
if (x + dx > sp.getWidth() - radius - 1) {
x = sp.getWidth() - radius - 1;
// bounce off right wall;
dx = -dx;
// bounce off left wall;
} else if (x + dx < 0 + radius) {
x = 0 + radius;
dx = -dx;
} else {
x += dx;
}
// friction;
if (y == sp.getHeight() - radius - 1) {
dx *= xFriction;
if (Math.abs(dx) < .8) {
dx = 0;
}
}
// gravity;
if (y > sp.getHeight() - radius - 1) {
y = sp.getHeight() - radius - 1;
dy *= energyloss;
dy = -dy;
} else {
// velocity formula;
dy += gravity * dt;
// position formula;
y += dy * dt + .5 * gravity * dt * dt;
}
}
}
In my opinion, your approach is all wrong and is creating complexity.
Here's how I'd do it. Create two classes, one for the ball and one for somewhere to draw it. Something along these lines:
public class Ball{
private int radius;
private int xPosition;
private int yPosition;
private int color;
private Paint paint;
public Ball(int x, int y, int radius, int color)
{
this.xPosition = x; this.yPosition = y; this.radius = radius;
paint = new Paint(color);
}
void moveBall(int x, int y){
xPosition = x; yPosition =y;
}
void onDraw(Canvas canvas){
canvas.drawCircle(x, y, radius, paint);
}
}
Now somewhere to draw it.
public class Playground extends ImageView{
public Ball ball;
#Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if (ball != null ){
ball.onDraw(canvas);
}
}
}
In your activity, probably in onStart():
imageView.ball = new Ball(startX, startY, radius, Color.BLUE);
Move your "update" method into the ball class also and call ball.update() on a timer (or whenever you want to update it).
Replace the ImageView in your layout with the Playground class (first name that popped into my head).
Override onMeasure() in the ImageView extension to get height and width of the "playground".
That gives you the basics. I wrote this off the top of my head so please excuse typos etc
Also, review the answers given to you in your multiple previous questions on this topic and read the Android documentation on extending View classes, onDraw and onMeasure.
I think you're drawing just once, you may add a timer to trigger the draw() method

Draw rectangle multiple times in new position not working

Each time I create a new rectangle with this code it does not work, I can only draw to a specified position, if I use a variable to change position on execution it does not draw anything.
Inside a Asynctask method:
rect = new desenho(main.this, x, y);
Which calls this:
public class desenho extends View{
int x, y;
Paint mPaint = new Paint();
public desenho(Context context, int x, int y) {
super(context);
this.x = x;
this.y = y;
mPaint.setStrokeWidth(3);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLACK);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(width, y);
}
#Override
protected void onDraw(Canvas c) {
// TODO Auto-generated method stub
super.onDraw(c);
c.drawRect(5, y, width-5, y+x, mPaint);
}
}
It seems to me that you want the size to be independent of position. For that, these requirements must be met in your Canvas.drawRect(left, top, right, bottom, paint):
left - right = a
top - bottom = b
where a, b are constant. Example:
c.drawRect(xPos, yPos, xPos + width - 1, yPos + height - 1, mPaint);
You see in this example that
left - right = xPos - (xPos + width - 1) = 1 - width
top - bottom = yPos - (yPos + height - 1) = 1 - height
Both are constant → size is constant.

Categories

Resources