I have a custom line view between a center button and 12 outer buttons, see pic.
Code block 1 is what I use to get the center points of each button combination.
Code block 2 is my 'custom drawing' , which draws the line between each set of center points, 12 lines in total.
The 12 custom lines are all inside an xml file.
The buttons and lines are passed into Public Class Drawline as in two separate arrays.
I've also created a class that uses Path to draw a triangle. this is sitting in the upper left hand corner of my graphic.
What I want.
A line between the centers of the buttons that stops short of the second end point.
I want the line between the points to end as you see between the buttons 'crispy crunchy' and 'balance'. I need help finding how to 'get' the x,y of this point. I also what to put the arrowhead on the end of the line.
public class Drawline {
public void drawLines(List<LineView> mlinesToDraw,ArrayList<Button> buttonsbalance, Context
context,Button btnbase) {
float centerXOnImage1;
double centerYOnImage1;
float centerXOfImageOnScreen1;
double centerYOfImageOnScreen1;
float centerXOnImage2;
float centerYOnImage2;
float centerXOfImageOnScreen2;
float centerYOfImageOnScreen2;
List<LineView> mLine = mlinesToDraw;
ArrayList<Button> btns = buttonsbalance;
PointF pointA;
PointF pointB;
for (int i = 0; i < mLine.size(); i++) {
Button button1 = btns.get(i + 1); //skip btnx0/btnbase
centerXOnImage1 = button1.getWidth() / 2;
centerYOnImage1 = (button1.getHeight()) / 2;//-actionBarHeight)/2;
centerXOfImageOnScreen1 = button1.getLeft()+ centerXOnImage1;
centerYOfImageOnScreen1 = button1.getTop() + (centerYOnImage1);
Button button2 = btnbase;
centerXOnImage2 = button2.getWidth() / 2;
centerYOnImage2 = (button2.getHeight()) / 2;//-actionBarHeight)/2;
centerXOfImageOnScreen2 = button2.getLeft() + centerXOnImage2;
centerYOfImageOnScreen2 = button2.getTop() + (centerYOnImage2);
pointA = new PointF(centerXOfImageOnScreen1, (float) centerYOfImageOnScreen1);
pointB = new PointF(centerXOfImageOnScreen2, (float) centerYOfImageOnScreen2);
mLine.get(i).setPointA(pointA);
mLine.get(i).setPointB(pointB);
mLine.get(i).draw();
}
}
Custom drawing class.
public class LineView extends View {
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private PointF pointA,pointB;
// private void init() {
// paint.setColor(Color.BLACK);
// }
public LineView(Context context) {
super(context);
// init();
}
public LineView(Context context, AttributeSet attrs) {
super(context, attrs);
// init();
}
public LineView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// init();
}
#SuppressLint("ResourceAsColor")
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
int color = R.color.GradientStart;
paint.setColor(color);
paint.setAntiAlias(true);
paint.setStrokeWidth(6);
canvas.drawLine(pointA.x, pointA.y, pointB.x, pointB.y, paint);
}
public void setPointA(PointF point){
pointA=point;}
public void setPointB(PointF point){
pointB=point;}
public void draw(){
invalidate();
requestLayout();
}}
I feel like there should be an easier way to do this but I've not found it yet.
I appreciate any help.
thanks,
Jim
Because I now the angle of each outer button and the radius to the point, I was able to get the location using polar coordinates. I then used the following conversion to get the corresponding x and y coordinates.
val x = radius * Math.cos(angle);
val y = radius * Math.sin(angle);
This gave me the alternate endpoint I needed to draw the line.
Related
I'm working on audio recording app.During recording i'm using visualizer like normal audio recording apps.But on specific time a want to draw a drawable on canvas visualizer(that is custom class extend View class).
Like this white drawable dot.
Here is my Custom view class.
public class VisualizerView extends View {
private static final int LINE_WIDTH = 1; // width of visualizer lines
private static final int LINE_SCALE = 75; // scales visualizer lines
private List<VisuallizerItem> visuallizerItems; // amplitudes for line lengths
private int width; // width of this View
private int height; // height of this View
private Paint linePaint; // specifies line drawing characteristics
//Boolean isImage=false;
// constructor
public VisualizerView(Context context, AttributeSet attrs) {
super(context, attrs); // call superclass constructor
linePaint = new Paint(); // create Paint for lines
linePaint.setColor(getResources().getColor(R.color.visualizerColor)); // set color to green
linePaint.setStrokeWidth(LINE_WIDTH); // set stroke width
}
// called when the dimensions of the View change
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
width = w; // new width of this View
height = h; // new height of this View
visuallizerItems = new ArrayList<VisuallizerItem>();
}
// clear all amplitudes to prepare for a new visualization
public void clear() {
visuallizerItems.clear();
}
// add the given amplitude to the amplitudes ArrayList
public void addAmplitude(VisuallizerItem visuallizerItem) {
// isImage=false;
visuallizerItems.add(visuallizerItem); // add newest to the amplitudes ArrayList
// if the power lines completely fill the VisualizerView
if (visuallizerItems.size() * LINE_WIDTH >= width) {
visuallizerItems.remove(0); // remove oldest power value
}
}
public void addAmplitudeImage(VisuallizerItem visuallizerItem) {
//isImage=true;
visuallizerItems.add(visuallizerItem); // add newest to the amplitudes ArrayList
// if the power lines completely fill the VisualizerView
if (visuallizerItems.size() * LINE_WIDTH >= width) {
visuallizerItems.remove(0); // remove oldest power value
}
}
// draw the visualizer with scaled lines representing the amplitudes
#Override
public void onDraw(Canvas canvas) {
int middle = height / 2; // get the middle of the View
float curX = 0; // start curX at zero
// for each item in the amplitudes ArrayList
for (VisuallizerItem power : visuallizerItems) {
if (power.isImage == -100) {
float scaledHeight = power.amplitude / LINE_SCALE; // scale the power
curX += LINE_WIDTH; // increase X by LINE_WIDTH
// draw a line representing this item in the amplitudes ArrayList
canvas.drawLine(curX, middle + scaledHeight / 2, curX, middle
- scaledHeight / 2, linePaint);
} else {//**Here i'm trying to draw mark on canvas**
power.isImage = -100;
//TODO draw attachment image here
Paint p = new Paint();
Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.yellow);
p.setColor(Color.RED);
canvas.drawBitmap(b, visuallizerItems.size(), middle, p);
}
}
}
}
This code add white mark once but remove it when onDraw calls again.
actually i want to draw a mark on canvas like above white dot.
Don't know why it remove it.Please help me
Thanks in advance
I created a custom TextView that is displayed in a GridView. When the user taps on the TextView, a black circle has to be displayed in the center of this TextView. Actually this used to work fine on my tablet (an ASUS TF300, something like that). FYI all clicked textviews are then saved in a local database and can be loaded again.
I also tested that on a smartphone. Weird thing : the black circle is not displayed after a tap. However I know that it works because the black circles are well displayed if I save my UI and reload it again.
Did I miss something ?
Please find the code of the custom TextView below.
public class ChordItemTextView extends TextView {
// Properties
private ChordItem item;
public void setChordItem(ChordItem item)
{
this.item = item;
}
private Paint fretPaint;
private Paint chordPaint;
private Paint textPaint;
private int paperColor;
public ChordItemTextView(Context context) {
super(context);
this.Init(context);
}
public ChordItemTextView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.Init(context);
}
private void Init(Context context)
{
// Resources retrieval
Resources myResources = getResources();
this.fretPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.fretPaint.setColor(myResources.getColor(R.color.fretColor));
this.chordPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.chordPaint.setColor(myResources.getColor(R.color.fretColor));
this.textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.textPaint.setColor(myResources.getColor(R.color.fretIndication));
this.textPaint.setTextSize(myResources.getDimension(R.dimen.fretFontSize));
this.paperColor = myResources.getColor(R.color.bgColor);
}
#Override
protected void onDraw(Canvas canvas) {
// paper color
canvas.drawColor(this.paperColor);
// fret line drawing
canvas.drawLine(0, getMeasuredHeight() / 2, getMeasuredWidth(), getMeasuredHeight() / 2, this.fretPaint);
canvas.drawLine((float) (getMeasuredWidth() * 0.99), 0, (float) (getMeasuredWidth() * 0.99), getMeasuredHeight(), this.fretPaint);
if (this.item.getFretNumber() == 0)
{
canvas.drawLine((float)( getMeasuredWidth() * 0.95), 0, (float)( getMeasuredWidth() * 0.95), getMeasuredHeight(), this.fretPaint);
}
// "tap" drawing
if (this.item.getIsPushed())
{
canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, getMeasuredHeight() / 4, this.chordPaint);
}
// fret number drawing
if (this.item.getStringNumber() == 1)
{
canvas.drawText(String.valueOf(this.item.getFretNumber()), getMeasuredWidth() / 2, getMeasuredHeight(), this.textPaint);
}
super.onDraw(canvas);
}
}
I have a function, y = 50sin(x/50) + 100.
Now what i want to do is to draw a curve for this function, but without any additional info from the graph plotters, I just need a wave on the screen. The X should correspond to my X parameter of the screen and Y to the Y parameter of the screen.
Here is the code of my current view.
public class Sinusoid extends View {
Paint paint = new Paint();
public Sinusoid(Context context) {
super(context);
paint.setColor(Color.RED);
}
#Override
public void onDraw(Canvas canvas) {
//todo draw the line using myFunction
}
private double myFunction(double x){
return 50 * Math.sin(x / 50) + 100;
}
}
Now the question is, what should i fill in my TODO?
Please help, any documentation or example will be very useful.
Thanks in advance.
The idea is to have something like this:
#Override
public void onDraw(Canvas canvas) {
for (int x=0; x<canvas.getWidth();x++) {
canvas.drawPoint(x,(float) myFunction(x),mPaint);
}
}
But you'll eventually need to adjust the value of your function given the canvas height.
Try something like this:
float xv=x0,yv= yo,x,y;
for (int i = 0; i < maxPoints; i++) {
x=i * scalex;
y=function(i)*scaley;
canvas.drawLine(xv, yv, x, y, paint);
xv=x;
yv=y;
}
The graphic will appears continuous.
I'm having simple custom view, which should effectively work as a progressbar.
I'd like to draw it with rounded corners, but that's seems to be not working for me..Below is whole code..In this state it gets drawn correctly, but without rounded corners. Once I set the strokeCap, or the layerType, the view gets effectively blank. Does anybody know why? And how to solve my issue?
EDIT: another interesting point is that eventhough drawLine works without strokeCap, drawPath does not draw any content at all. I have been drawing to canvas many times without ever having such weird issues..damn
EDIT 2: Path too large to be rendered into a texture - this am I getting while trying to render it with drawPath (but its definitely smaller then the maxWidth/height - the view is about 32x10dips)
public class CustomViewPagerIndicator extends View {
Paint mBgPaint;
Paint mFgPaing;
private int mMax;
private int mProgress;
public CustomViewPagerIndicator(Context context) {
this(context, null, 0);
}
public CustomViewPagerIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mMax = 1;
// setLayerType(LAYER_TYPE_SOFTWARE, null);
mBgPaint = new Paint();
mBgPaint.setColor(getResources().getColor(R.color.gray_2_translucent));
mBgPaint.setStyle(Paint.Style.STROKE);
mBgPaint.setStrokeWidth(R.dimen.grid_1);
// mBgPaint.setStrokeCap(Paint.Cap.ROUND);
mBgPaint.setAntiAlias(true);
mFgPaing = new Paint();
mFgPaing.setColor(getResources().getColor(R.color.gray_1));
mFgPaing.setStyle(Paint.Style.STROKE);
mFgPaing.setStrokeWidth(R.dimen.grid_1);
// mFgPaing.setStrokeCap(Paint.Cap.ROUND);
mFgPaing.setAntiAlias(true);
}
public void setMax(int max){
mMax = max;
};
public int getMax() {
return mMax;
}
public void setProgress(int progress){
mProgress = progress;
invalidate();
}
public int getProgress() {
return mProgress;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float step = getMeasuredWidth()/mMax;
canvas.drawLine(0, getMeasuredHeight()/2, canvas.getWidth(), getMeasuredHeight()/2, mBgPaint);
canvas.drawLine(0, getMeasuredHeight()/2, step*mProgress, getMeasuredHeight()/2, mFgPaing);
}
}
The root cause of the rounded corners not showing up is they are drawn off the edge of the canvas. You draw the line from one edge of the canvas to the other. drawLine draws the line at the coordinates given and then adds the caps. In your case, there is no room left on the canvas. You need to leave room for the caps by starting and ending drawing one half of your stroke length from the edges to leave room for the caps. See the example below. I have STROKE_SIZE as constant, but you probably want to load it with getDimension() on R.dimen.grid_1.
#Override
protected void onDraw(Canvas canvas) {
float step = (canvas.getWidth()-STROKE_SIZE/2)/(float)mMax;
canvas.drawLine(STROKE_SIZE/2, getMeasuredHeight()/2, canvas.getWidth()-STROKE_SIZE/2, getMeasuredHeight()/2, mBgPaint);
if(mProgress != 0) {
canvas.drawLine(STROKE_SIZE / 2, getMeasuredHeight() / 2, step * mProgress, getMeasuredHeight() / 2, mFgPaing);
}
}
I draw a graph with canvas in android, but I want to shift it to left or right side. I don't want to scroll it, I just want to shift it in one page by which you can see the graph is shifting lively.
I would be appreciated if any body help me.
I am looking for a an answer to this question as well. I have a solution but it is to slow and uses a lot of CPU time. I am drawing two graphs with a width of 200 pixels and have the values stored in an array. I just shift the values in the array and moves them into a path.
I would be nice to have a solution where the canvas gets shifted by 1 pixel to the left and the 200th column gets drawn with the new value. With both paths are empty it takes about 2ms (Droid Incredible) to draw the paths. When the 2 paths are filled up it can take more than 40ms. This would give still 25fps but I would like to run other threads at the same time and don't want to waste CPU time.
Here is the source.
public class OSCI extends View
{
Integer[] codebuffer = new Integer[200];
Integer[] codebuffer1 = new Integer[200];
private static final String TAG = "MyActivity";
long start;
int code=0;
// private static final String TAG = "MyActivity";
public OSCI(Context context)
{
super(context);
Arrays.fill(codebuffer, 1);
Arrays.fill(codebuffer1, 1);
}
public OSCI(Context context, AttributeSet attrs)
{
super(context, attrs);;
Arrays.fill(codebuffer, 1);
Arrays.fill(codebuffer1, 1);
}
#Override
protected void onDraw(Canvas canvas)
{
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.YELLOW);
Path path = new Path();
path.moveTo(0, 70);
Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint1.setStyle(Paint.Style.STROKE);
paint1.setStrokeWidth(2);
paint1.setColor(Color.GREEN);
Path path1 = new Path();
path1.moveTo(0, 70);
int max = Collections.max(Arrays.asList(codebuffer));
if(max==0)max=1;
for (int a = 0; a < codebuffer.length; a++)
{
if (codebuffer[a] < 0)code=0;
code = 70 * codebuffer[a] / max;
path.lineTo(a * 2 + 2, 70 - code);
path1.lineTo(a * 2+ 2, 70 - (codebuffer1[a]));
}
start=(SystemClock.elapsedRealtime());
canvas.drawPath(path1, paint);
canvas.drawPath(path, paint1);
Log.v(TAG, " "+(SystemClock.elapsedRealtime()-start));
}
public void newValue(int value, int valuew)
{
System.arraycopy(codebuffer, 1, codebuffer, 0, 199);
codebuffer[199] = value;
System.arraycopy(codebuffer1, 1, codebuffer1, 0, 199);
codebuffer1[199] = valuew;
invalidate();
}
}