I have drawn a graphic object ,say rectangle. I would like write some text at each corner of the rectangle. How to achieve this ?
private static class SimpleView extends View {
private ShapeDrawable mDrawable = new ShapeDrawable();
public SimpleView(Context context) {
super(context);
setFocusable(true);
this.mDrawable = new ShapeDrawable(new RectShape());
this.mDrawable.getPaint().setColor(0xFF0F00FF);
}
#Override
protected void onDraw(Canvas canvas) {
int x1 = 50;
int y1 = 150;
int width = 400;
int height = 50;
this.mDrawable.setBounds(x1, y1, x1 + width, y1 + height);
this.mDrawable.draw(canvas);
int x = 0;
int y = 0;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
etc
If you are using Canvas thenjust use the drawText() method.
drawText(String text, int start, int end, float x, float y, Paint paint)
Source: http://developer.android.com/reference/android/graphics/Canvas.html
Use canvas.drawText with the coordinates of the corners, and with Paint set at the appropriate alignment. i.e. you'd drawText at each corner, with the right corners having paint.align = RIGHT, and the left corners having paint.align = LEFT. That way, the text is drawn to the side of the square.
Related
I want to create a custom background around a block of text. For that, I have come up with a replacement span. Everything was right but the background color is not correctly fitting up with each text. line spacing between each text is 48dp. If I increase the spacing, then the span color is increasing and vice versa. Currently, it seems like the bottom portion of the background fills until the starting of the next line.
This is the code I'm using:
public class CoolBackgroundColorSpan extends ReplacementSpan {
private final int mBackgroundColor;
private final int mTextColor;
private final float mCornerRadius;
private final float mPaddingStart;
private final float mPaddingEnd;
private final float mMarginStart;
// private float mheight;
public CoolBackgroundColorSpan(int mBackgroundColor, int mTextColor, float mCornerRadius, float mPaddingStart, float mPaddingEnd, float mMarginStart) {
super();
this.mBackgroundColor = mBackgroundColor;
this.mTextColor = mTextColor;
this.mCornerRadius = mCornerRadius;
this.mPaddingStart = mPaddingStart;
this.mPaddingEnd = mPaddingEnd;
this.mMarginStart = mMarginStart;
}
#Override
public int getSize(#NonNull Paint paint, CharSequence text, int start, int end, #Nullable Paint.FontMetricsInt fm) {
return (int) (mPaddingStart + paint.measureText(text.subSequence(start, end).toString()) + mPaddingEnd);
}
#Override
public void draw(#NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, #NonNull Paint paint) {
float width = paint.measureText(text.subSequence(start, end).toString());
RectF rect = new RectF(x - mPaddingStart + mMarginStart, top, x + width + mPaddingEnd + mMarginStart, bottom);
paint.setColor(mBackgroundColor);
canvas.drawRoundRect(rect, mCornerRadius, mCornerRadius, paint);
paint.setColor(mTextColor);
canvas.drawText(text, start, end, x + mMarginStart, y, paint);
}
I have used LineHeightSpan. But this background color has a movement. This will move to the corresponding text below with each interval of time, like in karaoke. So that time, the line heigth is also increasing.
Since no one has answered yet, I'll post the answer
public void draw(#NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, #NonNull Paint paint) {
float width = paint.measureText(text.subSequence(start, end).toString());
RectF rect = new RectF(x - mPaddingStart + mMarginStart, top, x + width + mPaddingEnd + mMarginStart,bottom);
paint.setColor(mBackgroundColor);
canvas.drawRoundRect(rect, mCornerRadius, mCornerRadius, paint);
paint.setColor(mTextColor);
canvas.drawText(text, start, end, x + mMarginStart, y + (YourValue), paint);
}
Here give the value in (YourValue, lets say 11)
I have a custom view that is a circle. Here is the code for my CircleView:
public class CircleView extends View {
private static final int START_ANGLE_POINT = 90;
private final Paint paint;
private final RectF rect;
private float angle;
public CircleView(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);
rect = new RectF(strokeWidth, strokeWidth, 1000 + strokeWidth, 1000 + strokeWidth);
//Initial angle is zero
angle = 0;
}
#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;
} }
and here is how I declare it in the xml layout of an activity:
<com.my_package.ui.recording.CircleView
android:id="#+id/circleView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
All standard stuff. This is how my custom image looks like
Now, I want to place an imageView in the centre on the circleView? Does any one know how can I achieve that?
This is ideally what I would like to end up with:
Thank you in advance.
If you aren't set on using an ImageView and really just want to draw the bitmap in the center then have a look at canvas' drawBitmap method. This will allow you to draw it however/wherever you want.
I'm having trouble using a path to create a diamond shape on Android studio. It looks like I have a little more than half of the diamond, but I don't know what I am doing wrong and why the rest of it isn't printing out. I've been trying to change my code for hours and nothing is working. Could anyone please point out what I am doing wrong? Here is my code so far:
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.shapes.Shape;
public class Diamond extends Shape {
private int strokeWidth;
private final int fillColor;
private int strokeColor;
private Path path;
private Paint strokePaint;
private Paint fillPaint;
public Diamond(int strokeWidth, int fillColor, int strokeColor) {
this.strokeWidth = strokeWidth;
this.fillColor = fillColor;
this.strokeColor = strokeColor;
this.strokePaint = new Paint();
this.strokePaint.setStyle(Paint.Style.STROKE);
this.strokePaint.setStrokeWidth(strokeWidth);
this.fillPaint = new Paint();
this.fillPaint.setStyle(Paint.Style.FILL);
this.fillPaint.setColor(fillColor);
}
#Override
public void draw(Canvas canvas, Paint paint) {
canvas.drawPath(path, fillPaint);
canvas.drawPath(path, strokePaint);
}
#Override
protected void onResize(float width, float height) {
super.onResize(width, height);
path = new Path();
path.moveTo(width/2, 0);
path.lineTo(width, height);
path.lineTo(width/2, height*4);
path.lineTo(0, height);
path.close();
}
}
I think you should just need to change path.lineTo(width/2, height*4); to instead multiply the height by 2 as in path.lineTo(width/2, height*2);, using 4 makes the bottom half skewed longer than the top. There's also an example on this page drawing a rhombus which you can modify to draw a diamond by using the full width like:
public void drawRhombus(Canvas canvas, Paint paint, int x, int y, int width) {
int halfWidth = width / 2;
Path path = new Path();
path.moveTo(x, y + width); // Top
path.lineTo(x - halfWidth, y); // Left
path.lineTo(x, y - width); // Bottom
path.lineTo(x + halfWidth, y); // Right
path.lineTo(x, y + width); // Back to Top
path.close();
canvas.drawPath(path, paint);
}
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);
}
}
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/