I'm trying to draw multiple rectangles inside of a linear layout which is sitting inside of a scrollview. This is my code for the rectangle view:
private class RectView extends View{
int leftX, rightX, topY, bottomY;
boolean isAppt;
private Paint rectPaint;
private Rect rectangle;
public RectView(Context context, int _leftX, int _rightX, int _topY, int _bottomY, boolean _isAppt){
super(context);
leftX = _leftX;
rightX = _rightX;
topY = _topY;
bottomY = _bottomY;
isAppt = _isAppt;
init();
}
private void init(){
rectPaint = new Paint();
if(isAppt){
rectPaint.setARGB(255, 0, 0, 255);
rectPaint.setColor(Color.BLUE);
}
else{
rectPaint.setARGB(255, 0, 0, 0);
rectPaint.setColor(Color.WHITE);
}
rectPaint.setStrokeWidth(2);
rectPaint.setStyle(Style.STROKE);
rectangle = new Rect(leftX, topY, rightX, bottomY);
}
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawRect(rectangle, rectPaint);
}
}
And this is how I'm currently trying to display the rectangles:
RectView rv = new RectView(context, 0, 100, 0, 100, true);
firstDemarc.addView(rv);
firstDemarc.postInvalidate();
firstDemarc is the linear layout inside of my scrollview. Currently I'm not seeing any rectangles. The onDraw function is not being called. How do I properly display the rectangles inside of my scrollview?
You need to give the view some layout parameters:
int width = right - left;
int height = bottom - top;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width, height);
params.leftMargin = left;
params.topMargin = top;
setLayoutParams(params);
When you draw the rect, you need to draw from 0,0, until the width / height of the rect. The linear layout will handle the positioning according to the margins / layout params.
Related
I have drawn a circle with an inner radius and outer radius using drawArc() method. I am facing difficulty in making it to the centre of the screen. Currently, with the below code I am getting it near the left corner.
public Circle(Context context, AttributeSet attrs) {
super(context, attrs);
final int strokeWidth = 180;
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(strokeWidth);
DisplayMetrics metrics = new DisplayMetrics();
((Activity)getContext())
.getWindowManager().getDefaultDisplay().getMetrics(metrics);
int width = metrics.widthPixels;
int height = metrics.heightPixels;
rect = new RectF(width/2-strokeWidth, height/2-strokeWidth,
width/2+strokeWidth, height/2+strokeWidth);
Shader shader = new SweepGradient(rect.centerX(), rect.centerY(),
colours, null);[![enter image description here][1]][1]
Matrix matrix = new Matrix();
matrix.setRotate(225, rect.centerX(), rect.centerY());
shader.setLocalMatrix(matrix);
paint.setShader(shader);
//Initial Angle (optional, it can be zero)
angle = 0;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint);
}
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.
I have method, which should create a Bitmap from the RelativeLayout. My RelativeLayout creates dynamically and place all input Views into the circle. It looks like this:
public class CircleView extends RelativeLayout {
static final int centerId = 111;
private final int radius;
Bitmap returnedBitmap;
private RelativeLayout.LayoutParams createNewRelativeLayoutParams() {
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.ABOVE, centerId);
lp.addRule(RIGHT_OF, centerId);
return lp;
}
private View prepareElementForCircle(View elem, int distX, int distY) {
RelativeLayout.LayoutParams lp = createNewRelativeLayoutParams();
elem.measure(0, 0);
int deltaX = elem.getMeasuredWidth() / 2;
int deltaY = elem.getMeasuredHeight() / 2;
lp.setMargins(distX - deltaX, 0, 0, radius - distY - deltaY);
elem.setLayoutParams(lp);
return elem;
}
public CircleView(Context context, int radius, View[] elements) {
super(context);
this.radius = radius;
RelativeLayout.LayoutParams lpView = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
this.setLayoutParams(lpView);
View center = new View(context);
center.setId(centerId);
RelativeLayout.LayoutParams lpcenter = new RelativeLayout.LayoutParams(
0, 0);
lpcenter.addRule(CENTER_HORIZONTAL);
lpcenter.addRule(CENTER_VERTICAL);
center.setLayoutParams(lpcenter);
this.addView(center);
this.addView(prepareElementForCircle(elements[0], 0, 0));
if (elements.length % 2 == 0) {
this.addView(prepareElementForCircle(elements[elements.length / 2],
0, 2 * radius));
}
if (elements.length > 2) {
for (int i = 1; i <= (elements.length - 1) / 2; i++) {
int y = i * 4 * radius / elements.length;
int x = (int) Math.sqrt(Math.pow(radius, 2)
- Math.pow((radius - y), 2));
this.addView(prepareElementForCircle(elements[i], x, y));
this.addView(prepareElementForCircle(elements[elements.length
- i], -x, y));
}
}
}
When I pass several views into my CircleView and setContentView of it, everything works fine. But I need also implement ability to rotate this CircleView. So I need to convert my RelativeLayout to the Bitmap. I do it like this:
public Bitmap getBitmapFromView() {
this.measure(MeasureSpec.makeMeasureSpec(createNewRelativeLayoutParams().width, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(createNewRelativeLayoutParams().height, MeasureSpec.UNSPECIFIED));
this.layout(0, 0, this.getMeasuredWidth(), this.getMeasuredHeight());
this.setGravity(Gravity.CENTER);
Bitmap returnedBitmap = Bitmap.createBitmap(this.getMeasuredWidth(), this.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(returnedBitmap);
this.draw(c);
return returnedBitmap;
}
as a result I've got my view, but it looks like ugly. So not every view displays and they are not in circle. So my guess is what measuring of the View acts not like it should to be. Maybe, I should to measure all the children? Or maybe call Bitmap convertion method in onPreDraw()? I've tried both of solutions but they didn't work for me.
I solved this by
public Bitmap getBitmapFromView() {
DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics();
this.measure(MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.EXACTLY));
this.layout(0, 0, this.getMeasuredWidth(), this.getMeasuredHeight());
this.setGravity(Gravity.CENTER);
Bitmap returnedBitmap = Bitmap.createBitmap(this.getMeasuredWidth(),
this.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(returnedBitmap);
this.draw(c);
return returnedBitmap;
}
so DisplayMetrics solved my problem.
I'm looking for help with the following scaling problem.
I have built my own View class (custom view) which is a child of a Dialog.
In this custom view I plot a graph in vertical direction from bottom to top.
The graph can be greater or less than the size of the View.
Therefore I would like to draw the graph onto the Canvas (which is greater than the View) using the onDraw() method (see code below) and later scale the Canvas to fit into the View.
Things I've tried already include using a ScaleAnimation with duration=0 or calling the canvas.scale() method. Everytime the same result; the graph is not scaled.
I already read different threads like:
How to resize a custom view programmatically?
Android scale view
Thank you for your help.
VerticalGraphView Code:
public class VerticalGraphView extends View {
private static final String TAG = "VerticalGraphView";
private int[] ch1_data = new int[1000];
private int[] ch2_data = new int[1000];
private int mCanvasHeight = 1000;
private int mCanvasWidth = 242;
private Paint ch1_color = new Paint();
private Paint ch2_color = new Paint();
private Paint zero_color = new Paint();
private Paint grid_paint = new Paint();
private Paint outline_paint = new Paint();
public VerticalGraphView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(TAG, "VerticalGraphView-Constructor called!");
}
protected void onFinishInflate() {
super.onFinishInflate();
Log.d(TAG, "onFinishInflate()-called!");
// Log.i(TAG, "New Size set for height = " + setSizeHeight);
}
protected void onDraw(Canvas canvas) {
Log.d(TAG, "onDraw()-called!");
// // RESIZE TO FIT THE DATA
// Bitmap b = Bitmap.createBitmap(mCanvasWidth, ch1_data.length, Bitmap.Config.ARGB_8888);
// Canvas canvas = new Canvas(b);
// canvas.setBitmap(b);
ch1_color.setColor(Color.BLUE);
ch2_color.setColor(Color.RED);
zero_color.setColor(Color.argb(80,0,0,00));
zero_color.setStrokeWidth(3f);
grid_paint.setColor(Color.rgb(200, 200, 200));
outline_paint.setColor(Color.BLACK);
outline_paint.setStrokeWidth(2f);
if (canvas != null) {
// Redraw the background
canvas.drawRGB(255, 255, 255);
// Draw vertical grey lines
for (int vertical = 1; vertical<6; vertical++) {
if (vertical == 3) { // Draw line in the middle
canvas.drawLine( vertical*(mCanvasWidth/6)+1, 1,
vertical*(mCanvasWidth/6)+1,
mCanvasHeight+1,
zero_color);
} else {
canvas.drawLine( vertical*(mCanvasWidth/6)+1, 1,
vertical*(mCanvasWidth/6)+1,
mCanvasHeight+1,
grid_paint);
}
}
// Draw horizontal grey lines
for (int horizontal = 1; horizontal<10; horizontal++) {
canvas.drawLine(1, horizontal*(mCanvasHeight/10)+1,
mCanvasWidth+1,
horizontal*(mCanvasHeight/10)+1,
grid_paint);
}
// draw outline
canvas.drawLine(0, 0, (mCanvasWidth+1), 0, outline_paint); // top
canvas.drawLine((mCanvasWidth), 0, (mCanvasWidth), (mCanvasHeight+1),
outline_paint); //right
canvas.drawLine(0, (mCanvasHeight), (mCanvasWidth), (mCanvasHeight),
outline_paint); // bottom
canvas.drawLine(0, 0, 0, (mCanvasHeight+1), outline_paint); //left
// plot data
int middle = mCanvasWidth / 2;
for (int x=0; x<(ch2_data.length-1); x++) {
canvas.drawLine((middle + ch2_data[x]),(mCanvasHeight - x),
(middle + ch2_data[x+1]),
(mCanvasHeight - x+1),
ch2_color);
canvas.drawLine((middle + ch1_data[x]),(mCanvasHeight - x),
(middle + ch1_data[x+1]),
(mCanvasHeight - x+1),
ch1_color);
}
}
Log.e(TAG, "canvas.Height = " + canvas.getHeight());
Log.e(TAG, "canvas.Width = " + canvas.getWidth());
// RESIZE TO FIT THE VIEW, only in Y-Direction
// Fits the canvas onto the view
float ratio = ((float) canvas.getHeight()) / (float) mCanvasHeight;
Log.e(TAG, "SCALE: ratio = " + ratio);
// ScaleAnimation anim = new ScaleAnimation(1f,1f,1f,ratio, 0.5f, 0.5f);
// anim.setDuration(1000);
// this.startAnimation(anim);
// canvas.scale(0f, ratio, canvas.getWidth() * 0.5f , canvas.getHeight() * 0.5f);
// canvas.save(Canvas.MATRIX_SAVE_FLAG);
// canvas.scale(0f, ratio, mCanvasWidth * 0.5f , mCanvasHeight * 0.5f);
// canvas.restore();
// canvas.scale(0f, 0.5f, mCanvasWidth * 0.5f , mCanvasHeight * 0.5f);
// canvas.scale(100, 100);
// canvas.getMatrix().postScale(0.5f, 0.5f);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(242, 500);
// params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
this.setLayoutParams(params);
// RelativeLayout layout = (RelativeLayout) findViewById(R.id.relativeLayoutRight);
// ViewGroup.LayoutParams params = layout.getLayoutParams();
// params.height = 500;
// params.width = canvas.getWidth();
// layout.setLayoutParams(params);
// invalidate();
// DRAW THE CANVAS
super.onDraw(canvas);
}
public void setData(int[] data1, int[] data2 ) {
Log.d(TAG, "setData()-called!");
ch1_data = data1;
ch2_data = data2;
}
/**
* This method sets the height of the View.</br>
* <b><u>NOTE:</u></b> The method call deletes all data stored for the graph.
* #param newHeight the new height of the view
*/
public void setHeight(int newHeight) {
mCanvasHeight = newHeight;
ch1_data = new int[newHeight];
ch2_data = new int[newHeight];
}
}
layout.xml which is used in the Dialog:
<com.android.Ui.VerticalGraphView
android:id="#+id/verticalGraphView"
android:layout_width="242dp"
android:layout_height="1000dp"
android:layout_centerInParent="true" />
you are not supposed to change the layout in the onDraw() method. in the onDraw method you have to take the current layout state and deal with it (and draw inside its boundaries).
try to calculate the needed size of the view , and then set the layout params . upon each time you need to scale , do it again . if an update is needed , call invalidate() .
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.