add view to linearlayout on a circle drawn in canvas - android

I have drawn a circle using canvas draw method. Now I want to add a view on circumference of circle. I can get coordinate of circle but totally lost how to add view to that coordinate.
Code is as below -
public class CircleView2 extends LinearLayout {
private int centerX, centerY;
private float fixedRadius = 30;
private Paint paint;
private Logger logger;
private Context context;
TextView textView;
public CircleView2(Context context) {
super(context);
setWillNotDraw(false);
doInit(context);
}
public CircleView2(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
doInit(context);
}
private void doInit(Context context) {
this.context = context;
logger = new Logger(context);
fixedRadius = 30;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setColor(Color.rgb(227, 73, 90));
textView = new TextView(context);
}
#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.drawCircle(centerX, centerY, fixedRadius + 160, paint);
double x = centerX + (fixedRadius + 160) * Math.cos(Math.toDegrees(45.0));
double y = centerY + (fixedRadius + 160) * Math.sin(Math.toDegrees(45.0));
logger.debug(x + "");
logger.debug(y + "");
textView.setTextColor(Color.BLACK);
textView.setText("AAA");
textView.draw(canvas);
super.onDraw(canvas);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}
}
This draws circle just fine. But can't add textview. textview.draw(canvas) should add that to view, right ? How to add textview to view and that to at calculated coordinates ?
What I'm doing wrong here?

Related

Rectangle draw call in mainActivity

I draw a rectangle in the activity_main folder and I get these values to be drawn in integer.xml, but I do not want to do that.getInteger (R.integer.scanner_rect_width and getResources (). getInteger (R.integer.scanner_rect_height I get these values from the integer.xml folder, but how do I assign these values by creating a mainActivity object?
ScannerOverlay scannerOverlay = new ScannerOverlay (); as
ScanerOverlay.java
public class ScannerOverlay extends ViewGroup {
private float left, top, endY;
private int rectWidth, rectHeight;
private int frames;
private boolean revAnimation;
private int lineColor, lineWidth;
public ScannerOverlay(Context context) {
super(context);
}
public void setWidth(int pixels) {
rectWidth = pixels;
requestLayout();
invalidate();
}
public void setHeight(int pixels) {
rectHeight = pixels;
requestLayout();
invalidate();
}
public ScannerOverlay(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScannerOverlay(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.ScannerOverlay,
0, 0);
rectWidth = a.getInteger(R.styleable.ScannerOverlay_square_width, 150);
rectHeight = a.getInteger(R.styleable.ScannerOverlay_square_height, 150);
lineColor = a.getColor(R.styleable.ScannerOverlay_line_color, ContextCompat.getColor(context, R.color.scanner_line));
lineWidth = a.getInteger(R.styleable.ScannerOverlay_line_width, getResources().getInteger(R.integer.line_width));
frames = a.getInteger(R.styleable.ScannerOverlay_line_speed, getResources().getInteger(R.integer.line_width));
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
#Override
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
left = (w - dpToPx(rectWidth)) / 2;
top = (h - dpToPx(rectHeight)) / 2;
endY = top;
super.onSizeChanged(w, h, oldw, oldh);
}
public int dpToPx(int dp) {
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
}
#Override
public boolean shouldDelayChildPressedState() {
return false;
}
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw transparent rect
int cornerRadius = 0;
Paint eraser = new Paint();
eraser.setAntiAlias(true);
eraser.setColor(Color.WHITE);
RectF rect = new RectF(left, top, dpToPx(rectWidth) + left, dpToPx(rectHeight) + top);
canvas.drawRoundRect(rect, (float) cornerRadius, (float) cornerRadius, eraser);
// draw horizontal line
Paint line = new Paint();
line.setColor(lineColor);
line.setStrokeWidth(Float.valueOf(lineWidth));
// draw the line to product animation
if (endY >= top + dpToPx(rectHeight) + frames) {
revAnimation = true;
} else if (endY == top + frames) {
revAnimation = false;
}
// check if the line has reached to bottom
if (revAnimation) {
endY -= frames;
} else {
endY += frames;
}
canvas.drawLine(left, endY, left + dpToPx(rectWidth), endY, line);
invalidate();
}
}
activity_main.xml
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.yavuz.myapplication.MainActivity">
<com.example.yavuz.myapplication.ScannerOverlay
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#44000000"
app:line_color="#7323DC"
app:line_speed="6"
app:line_width="4"
/>
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
You have to create setters methods for width and height as below:
public void setWidth(int pixels) {
rectWidth = pixels;
requestLayout();
invalidate();
}
public void setHeight(int pixels) {
rectHeight = pixels;
requestLayout();
invalidate();
}
Then to use it MainActivity you use it as below:
ScannerOverlay scannerOverlay = new ScannerOverlay();
scannerOverlay.setWidth(200); // for example
scannerOverlay.setHeight(300);
setContentView(scannerOverlay);
I suppose that ScannerOverlay is a custom view.
from xml layout:
<thepackage_where_theclass.ScannerOverlay
app:scanner_rect_width="200"
app:scanner_rect_height="200"/>

Android : draw arc without resetting the previous drawn circle

I am trying to draw a circle which will represent time and after each complete circle, I want to change the color to indicate to the user that the next time unit has started and draw over the previous circle color rather than reset as shown in the example below.
I am trying to draw a circle using Draw Arc method in the following way
canvas.drawArc(mRect, 270, sweepAngle, false, fgPaint);
The sweep angle is controlled by an Object Animator :
outerCircleAnimator = ObjectAnimator.ofFloat(timeView, TimeView.SET_SWEEPWANGLE, 0, 360);
With the following code, I am able to achieve the following
The following is my View class :
public class TimeView extends View {
final protected Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
final protected Paint fgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
final protected Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private RectF mRect = new RectF();
private float sweepAngle;
private float radiusInDPI = 100;
private float radiusInPixels;
private float strokeWidthInDPI = 4;
private float stokeWidthInPixels;
private float dpi;
private int heightByTwo;
private int widthByTwo;
public TimeView(Context context) {
super(context);
init();
}
public TimeView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TimeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
#Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
heightByTwo = h / 2;
widthByTwo = w / 2;
mRect = new RectF(w / 2 - radiusInPixels, h / 2 - radiusInPixels, w / 2 + radiusInPixels, h / 2 + radiusInPixels);
}
private void init() {
DisplayMetrics metrics = getResources().getDisplayMetrics();
dpi = metrics.density;
radiusInPixels = dpi * radiusInDPI;
stokeWidthInPixels = dpi * strokeWidthInDPI;
bgPaint.setStrokeWidth(stokeWidthInPixels);
bgPaint.setStyle(Paint.Style.STROKE);
bgPaint.setColor(ContextCompat.getColor(getContext(), R.color.colorAccent));
fgPaint.setStrokeWidth(stokeWidthInPixels);
fgPaint.setStyle(Paint.Style.STROKE);
fgPaint.setColor(ContextCompat.getColor(getContext(), R.color.colorPrimary));
textPaint.setTextSize(24 * 3);
textPaint.setStyle(Paint.Style.STROKE);
textPaint.setColor(ContextCompat.getColor(getContext(), R.color.colorPrimary));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// canvas.drawCircle(widthByTwo, heightByTwo, radiusInPixels, bgPaint);
canvas.drawArc(mRect, 270, sweepAngle, false, fgPaint);
}
public static final Property<TimeView, Float> SET_SWEEPWANGLE =
new Property<TimeView, Float>(Float.class, "outerCircleRadiusProgress") {
#Override
public Float get(TimeView object) {
return object.getSweepAngle();
}
#Override
public void set(TimeView object, Float value) {
object.setSweepAngle(value);
}
};
public float getSweepAngle() {
return sweepAngle;
}
public void setSweepAngle(float sweepAngle) {
Log.v("Testing", "Sweep angle is " + sweepAngle + " " + (sweepAngle + 270));
this.sweepAngle = sweepAngle;
postInvalidate();
}
public void setColor(boolean change) {
if (change) {
fgPaint.setColor(ContextCompat.getColor(getContext(), R.color.mint_green));
} else {
fgPaint.setColor(ContextCompat.getColor(getContext(), R.color.colorPrimary));
}
}
}
onDraw is used to draw on the empty canvas. It is always starting from the beginning. You'll need to save the last fgPaint and:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (lastFgPaint != null) {
canvas.drawArc(mRect, sweepAngle, 360, false, lastFgPaint);
}
canvas.drawArc(mRect, 270, sweepAngle, false, fgPaint);
}

Customize a ProgressBar to become a Thermometer

How to customize a ProgressBar to look like a Thermometer ? with the possibility to change color.
My suggestion was to rotate the progressBar 90° to become vertical then have it overlay an image of an empty Thermometer but it's bad and messy solution.
I Think the best will be to either to extends View or ProgressBar class and customize the draw method but I have no idea how to draw Thermometer, any Help would be appreciated.
I created something like this for a project
package com.janslab.thermometer.widgets;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.Scroller;
import com.janslab.thermometer.R;
public class DummyThermometer extends View {
private Paint mInnerCirclePaint;
private Paint mOuterCirclePaint;
private Paint mFirstOuterCirclePaint;
//thermometer arc paint
private Paint mFirstOuterArcPaint;
//thermometer lines paints
private Paint mInnerLinePaint;
private Paint mOuterLinePaint;
private Paint mFirstOuterLinePaint;
//thermometer radii
private int mOuterRadius;
private int mInnerRadius;
private int mFirstOuterRadius;
//thermometer colors
private int mThermometerColor = Color.rgb(200, 115, 205);
//circles and lines variables
private float mLastCellWidth;
private int mStageHeight;
private float mCellWidth;
private float mStartCenterY; //center of first cell
private float mEndCenterY; //center of last cell
private float mStageCenterX;
private float mXOffset;
private float mYOffset;
// I 1st Cell I 2nd Cell I 3rd Cell I
private static final int NUMBER_OF_CELLS = 3; //three cells in all ie.stageHeight divided into 3 equal cells
//animation variables
private float mIncrementalTempValue;
private boolean mIsAnimating;
private Animator mAnimator;
public DummyThermometer(Context context) {
this(context, null);
}
public DummyThermometer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DummyThermometer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (attrs != null) {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Thermometer, defStyle, 0);
mThermometerColor = a.getColor(R.styleable.Thermometer_therm_color, mThermometerColor);
a.recycle();
}
init();
}
private void init() {
mInnerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mInnerCirclePaint.setColor(mThermometerColor);
mInnerCirclePaint.setStyle(Paint.Style.FILL);
mInnerCirclePaint.setStrokeWidth(17f);
mOuterCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mOuterCirclePaint.setColor(Color.WHITE);
mOuterCirclePaint.setStyle(Paint.Style.FILL);
mOuterCirclePaint.setStrokeWidth(32f);
mFirstOuterCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mFirstOuterCirclePaint.setColor(mThermometerColor);
mFirstOuterCirclePaint.setStyle(Paint.Style.FILL);
mFirstOuterCirclePaint.setStrokeWidth(60f);
mFirstOuterArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mFirstOuterArcPaint.setColor(mThermometerColor);
mFirstOuterArcPaint.setStyle(Paint.Style.STROKE);
mFirstOuterArcPaint.setStrokeWidth(30f);
mInnerLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mInnerLinePaint.setColor(mThermometerColor);
mInnerLinePaint.setStyle(Paint.Style.FILL);
mInnerLinePaint.setStrokeWidth(17f);
mOuterLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mOuterLinePaint.setColor(Color.WHITE);
mOuterLinePaint.setStyle(Paint.Style.FILL);
mFirstOuterLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mFirstOuterLinePaint.setColor(mThermometerColor);
mFirstOuterLinePaint.setStyle(Paint.Style.FILL);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mStageCenterX = getWidth() / 2;
mStageHeight = getHeight();
mCellWidth = mStageHeight / NUMBER_OF_CELLS;
//center of first cell
mStartCenterY = mCellWidth / 2;
//move to 3rd cell
mLastCellWidth = (NUMBER_OF_CELLS * mCellWidth);
//center of last(3rd) cell
mEndCenterY = mLastCellWidth - (mCellWidth / 2);
// mOuterRadius is 1/4 of mCellWidth
mOuterRadius = (int) (0.25 * mCellWidth);
mInnerRadius = (int) (0.656 * mOuterRadius);
mFirstOuterRadius = (int) (1.344 * mOuterRadius);
mFirstOuterLinePaint.setStrokeWidth(mFirstOuterRadius);
mOuterLinePaint.setStrokeWidth(mFirstOuterRadius / 2);
mFirstOuterArcPaint.setStrokeWidth(mFirstOuterRadius / 4);
mXOffset = mFirstOuterRadius / 4;
mXOffset = mXOffset / 2;
//get the d/f btn firstOuterLine and innerAnimatedline
mYOffset = (mStartCenterY + (float) 0.875 * mOuterRadius) - (mStartCenterY + mInnerRadius);
mYOffset = mYOffset / 2;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawFirstOuterCircle(canvas);
drawOuterCircle(canvas);
drawInnerCircle(canvas);
drawFirstOuterLine(canvas);
drawOuterLine(canvas);
animateInnerLine(canvas);
drawFirstOuterCornerArc(canvas);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//take care of paddingTop and paddingBottom
int paddingY = getPaddingBottom() + getPaddingTop();
//get height and width
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
height += paddingY;
setMeasuredDimension(width, height);
}
private void drawInnerCircle(Canvas canvas) {
drawCircle(canvas, mInnerRadius, mInnerCirclePaint);
}
private void drawOuterCircle(Canvas canvas) {
drawCircle(canvas, mOuterRadius, mOuterCirclePaint);
}
private void drawFirstOuterCircle(Canvas canvas) {
drawCircle(canvas, mFirstOuterRadius, mFirstOuterCirclePaint);
}
private void drawCircle(Canvas canvas, float radius, Paint paint) {
canvas.drawCircle(mStageCenterX, mEndCenterY, radius, paint);
}
private void drawOuterLine(Canvas canvas) {
float startY = mEndCenterY - (float) (0.875 * mOuterRadius);
float stopY = mStartCenterY + (float) (0.875 * mOuterRadius);
drawLine(canvas, startY, stopY, mOuterLinePaint);
}
private void drawFirstOuterLine(Canvas canvas) {
float startY = mEndCenterY - (float) (0.875 * mFirstOuterRadius);
float stopY = mStartCenterY + (float) (0.875 * mOuterRadius);
drawLine(canvas, startY, stopY, mFirstOuterLinePaint);
}
private void drawLine(Canvas canvas, float startY, float stopY, Paint paint) {
canvas.drawLine(mStageCenterX, startY, mStageCenterX, stopY, paint);
}
//simulate temperature measurement for now
private void animateInnerLine(Canvas canvas) {
if (mAnimator == null)
measureTemperature();
if (!mIsAnimating) {
mIncrementalTempValue = mEndCenterY + (float) (0.875 * mInnerRadius);
mIsAnimating = true;
} else {
mIncrementalTempValue = mEndCenterY + (float) (0.875 * mInnerRadius) - mIncrementalTempValue;
}
if (mIncrementalTempValue > mStartCenterY + mInnerRadius) {
float startY = mEndCenterY + (float) (0.875 * mInnerRadius);
drawLine(canvas, startY, mIncrementalTempValue, mInnerCirclePaint);
} else {
float startY = mEndCenterY + (float) (0.875 * mInnerRadius);
float stopY = mStartCenterY + mInnerRadius;
drawLine(canvas, startY, stopY, mInnerCirclePaint);
mIsAnimating = false;
stopMeasurement();
}
}
private void drawFirstOuterCornerArc(Canvas canvas) {
float y = mStartCenterY - (float) (0.875 * mFirstOuterRadius);
RectF rectF = new RectF(mStageCenterX - mFirstOuterRadius / 2 + mXOffset, y + mFirstOuterRadius, mStageCenterX + mFirstOuterRadius / 2 - mXOffset, y + (2 * mFirstOuterRadius) + mYOffset);
canvas.drawArc(rectF, -180, 180, false, mFirstOuterArcPaint);
}
public void setThermometerColor(int thermometerColor) {
this.mThermometerColor = thermometerColor;
mInnerCirclePaint.setColor(mThermometerColor);
mFirstOuterCirclePaint.setColor(mThermometerColor);
mFirstOuterArcPaint.setColor(mThermometerColor);
mInnerLinePaint.setColor(mThermometerColor);
mFirstOuterLinePaint.setColor(mThermometerColor);
invalidate();
}
//simulate temperature measurement for now
private void measureTemperature() {
mAnimator = new Animator();
mAnimator.start();
}
private class Animator implements Runnable {
private Scroller mScroller;
private final static int ANIM_START_DELAY = 1000;
private final static int ANIM_DURATION = 4000;
private boolean mRestartAnimation = false;
public Animator() {
mScroller = new Scroller(getContext(), new AccelerateDecelerateInterpolator());
}
public void run() {
if (mAnimator != this)
return;
if (mRestartAnimation) {
int startY = (int) (mStartCenterY - (float) (0.875 * mInnerRadius));
int dy = (int) (mEndCenterY + mInnerRadius);
mScroller.startScroll(0, startY, 0, dy, ANIM_DURATION);
mRestartAnimation = false;
}
boolean isScrolling = mScroller.computeScrollOffset();
mIncrementalTempValue = mScroller.getCurrY();
if (isScrolling) {
invalidate();
post(this);
} else {
stop();
}
}
public void start() {
mRestartAnimation = true;
postDelayed(this, ANIM_START_DELAY);
}
public void stop() {
removeCallbacks(this);
mAnimator = null;
}
}
private void stopMeasurement() {
if (mAnimator != null)
mAnimator.stop();
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
measureTemperature();
}
#Override
protected void onDetachedFromWindow() {
stopMeasurement();
super.onDetachedFromWindow();
}
#Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
switch (visibility) {
case View.VISIBLE:
measureTemperature();
break;
default:
stopMeasurement();
break;
}
}
}
attrs.xml file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Thermometer">
<attr name="therm_color" format="color" />
</declare-styleable>
</resources>
First I would provide 2 setters, one for color and one for the temperature value, normalized from 0 ... 1, where 0 means no visible bar, and 1 means a fully visible bar.
public void setColor(int color) {
mColor = color;
invalidate(); // important, this triggers onDraw
}
public void setValue(float value) {
mValue = -(value - 1);
invalidate(); // important, this triggers onDraw
}
Notice for value, I reverse the value, since we draw the bar from bottom up, instead from top down. It makes sense in the canvas.drawRect method.
If your CustomView may have custom sizes, set your size of the progressBar (I refer to the inner bar as progressBar) in onSizeChanged, as this gets called when the View has changed it's size.
If it is a fixed size, you can just provide those values statically in an init function or the constructor.
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mProgressRect = new Rect(
/*your bar left offset relative to base bitmap*/,
/*your bar top offset relative to base bitmap*/,
/*your bar total width*/,
/*your max bar height*/
);
}
Then in ondraw, take these values into account and draw accordingly.
First draw the Bitmap, depending on your selected color (I would provide the thermometer base as a Bitmap, as long as it does not have to be completely dynamically drawn (special requirements)
Then draw the progress bar, with an height based on mValue * totalHeight of the bar, using the color provided in the setter.
For example:
#Override
protected void onDraw(Canvas canvas) {
// draw your thermometer base, bitmap based on color value
canvas.drawBitmap( /*your base thermometer bitmap here*/ );
// draw the "progress"
canvas.drawRect(mProgressRect.left, mProgressRect.top + (mValue * mProgressRect.bottom - mProgressRect.top), mProgressRect.right, mProgressRect.bottom, mPaint);
}
Hope that helps.
P.S.:
If you want to have the thermometer base image also dynamically drawn, it's a slightly different story, it would involve creating a path first and draw it with a Paint object, instead of drawing the bitmap.
EDIT:
Even better, if you want a simple solution for the "roundness" of the bar, draw a line instead a rect.
Define a line paint object like this:
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(20); // thickness of your bar
then in onDraw, instead drawRect:
// draw the "progress"
canvas.drawLine(mProgressRect.left, mProgressRect.top + (mValue * mProgressRect.bottom - mProgressRect.top), mProgressRect.left, mProgressRect.bottom, mPaint);
Be sure to adjust your mProgressRectaccordingly.

Painting harmonic waves Android

I am making an app that looks like the pic below, the bottom harmonic wave doesn't change but the top one will by setting the amplitude, omega, omega inverse and phi.
I have x and y lines but I cant seem figure out how to even paint the bottom wave, y = sin(x). I have searched and tried to do it but have failed. Can anyone help or give direction to a resource that will help?
This is a simple example drawing two sine waves, taking care of view size changes, some axis scaling and simulation stepping.
<com.pixdart.view.HarmonicCustomView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DDD"/>
public class HarmonicCustomView extends View {
private Paint mPaint = new Paint();
private RectF mRectF = new RectF();
private float scaleY, scaleX;
public static final float STEP_X = 0.1f;
public static final int PERIODS_TO_SHOW = 5;
public HarmonicCustomView(Context context) {
super(context);
initialize();
}
public HarmonicCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public HarmonicCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRectF.set(0, 0, w, h);
mRectF.inset(mRectF.width() * 0.1f, mRectF.height() * 0.1f);
scaleX = (float) (2 * Math.PI * PERIODS_TO_SHOW / mRectF.width());
scaleY = mRectF.height() / 6;
}
public void initialize() {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(2f);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(0xFFFF0000);
for (float x = 0; x < mRectF.width(); x += STEP_X) {
float y = (float) (Math.sin(x * scaleX)) * scaleY;
canvas.drawPoint(x + mRectF.left, y + mRectF.top + scaleY, mPaint);
}
mPaint.setColor(0xFF0000FF);
for (float x = 0; x < mRectF.width(); x += STEP_X) {
float y = (float) (Math.sin(x * scaleX)) * scaleY;
canvas.drawPoint(x + mRectF.left, y + mRectF.top + scaleY * 5, mPaint);
}
}
}

Can't drawArc after scaling

I newbie to Android Development, and Canvas drawings.
When I draw stuff on canvas, its easier for me to work on rectangle portion of width=height=1.
I try to scale according, but when trying to drawArc its draw it badly.
Can you please tell me what I'm doing wrong?
public class MyChart extends View{
private RectF dimentionRect;
private Paint dimentionPaint;
private static final String TAG = "VERBOSE";
public MyChart(Context context){
super(context);
initDrawingTools();
}
public MyChart(Context context,AttributeSet attrs) {
super(context,attrs);
initDrawingTools();
}
private void initDrawingTools(){
dimentionPaint = new Paint();
dimentionPaint.setColor(Color.GREEN);
dimentionPaint.setStyle(Style.FILL);
}
#Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec){
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int chosenDimention = Math.min(widthSize, heightSize);
setMeasuredDimension(chosenDimention, chosenDimention);
Log.v(TAG, "onMeasure: "+chosenDimention);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.v(TAG, "onSizeChange");
}
#Override
public void onDraw(Canvas canvas){
float width = (float)getWidth();
Log.v(TAG, "onDraw: "+width);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(width, width);
dimentionRect = new RectF(0,0,1f,1f);
//canvas.drawRect(dimentionRect, dimentionPaint); //
canvas.drawArc(dimentionRect, 0, 180, true, dimentionPaint);
// canvas.drawCircle(0.5f, 0.5f, 0.3f, dimentionPaint);
canvas.restore();
}
}
Ok, I didn't find a solution but I was able to find a work-around for it.
I created a background bitmap and using it for a local Canvas which do the drawing stuff. after all drawings I draw the bitmap again into my canvas.
I know its not elegant but thats the solution I found
private void drawBackground(Canvas canvas){
if(background != null){
canvas.drawBitmap(background, 0,0,backgroundPaint);
Log.e(TAG, "Drawing background");
}
}
private void regenerateBackground(){
if(background != null){
background.recycle();
}
background = Bitmap.createBitmap(getWidth(), getWidth(), Config.ARGB_8888);
RectF rect = new RectF(0,0,getWidth(),getWidth());
Canvas c = new Canvas(background);
c.drawRect(rect, backgroundPaint);
}
#Override
protected void onDraw(Canvas canvas){
drawBackground(canvas);
float width = (float)getWidth();
Canvas c = new Canvas(background);
c.save(Canvas.MATRIX_SAVE_FLAG);
c.scale(width,width);
border = new RectF(0,0,1,1);
//
Paint p = new Paint();
p.setColor(Color.GREEN);
p.setStyle(Style.FILL);
c.drawArc(border, 0, 360,true, p);
c.restore();
}

Categories

Resources