how to draw svg line on canvas in sequence? - android

the idea is, i want to make animated kanji letter (in sequence) like this project HTML5 Stroke Animation. And my problem is, when i call onDraw method my canvas just draw simultaneously. I couldn't find much info about it on the internet, so any clue would be much appreciated if you have already come across the same situation.
here is my code:
public class MainActivity extends AppCompatActivity {
private TextView txt;
private SvgPathParser svgPathParser;
private PathView pathView;
private String sPath =
"M32.49,17.39c0.14,1.08,0.24,2.44-0.12,3.77c-2.29,8.41-11.14,24.16-21.81,35.56" +
"|M25.03,42c0.59,0.61,0.76,1.97,0.76,3.23c0,10.08,0.08,28.85,0,40.77c-0.02,3.48-0.04,6.4-0.04,8.38" +
"|M55.1,14.25c0.05,0.65,0.16,1.69-0.09,2.6c-1.55,5.6-8.51,16.02-17.36,24.43" +
"|M53.88,27.02c0.94,0.18,3.7,0.29,4.62,0.18c4.47-0.52,18.49-2.45,26.44-3.62c2.43-0.36,4.03-0.45,6.45-0.17" +
"|M52.82,39.44c1.03,0.85,1.4,3.75,0.72,5.89c-3.37,10.67-6.4,19.7-11.35,30.04c-1.45,3.03-0.49,4.25,1.47,4.33c10.84,0.43,18.96,1.05,29.44,3.78c5.98,1.55,12.27,4.02,17.89,7.93" +
"|M54.69,42.07c6.68-0.95,22.21-3.14,26.69-3.43c3.45-0.22,4.43,1.81,4.14,4.54c-1.33,12.48-5.94,37.8-10.23,47.46c-2.3,5.17-4.97,4.12-7.54,1.33" +
"|M68.32,43.35c0.45,0.88,0.63,2.39,0.13,4.22c-2.32,8.56-7.53,25.28-10.01,32.34" +
"|M32.07,61.64c3.43,0.61,5.94,0.44,8.42,0.17c12.25-1.31,31.7-3.07,49-3.92c2.76-0.14,5.75-0.41,8.43,0.38";
String[] arrayPath = sPath.split("\\|");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new PathView(this));
}
private Path path(String sPath) throws ParseException {
svgPathParser = new SvgPathParser();
return svgPathParser.parsePath(sPath);
}
public class PathView extends View {
Path path;
Paint paint;
List<Path> paths;
float length;
public PathView(Context context) {
super(context);
init();
}
public PathView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PathView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void init() {
paths = new ArrayList<>();
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
path = new Path();
for (int i = 0; i < arrayPath.length; i++) {
try {
paths.add(path(arrayPath[i]));
// path = );
} catch (ParseException e) {
e.printStackTrace();
}
}
// Measure the path
for (Path path : paths) {
this.path = path;
PathMeasure measure = new PathMeasure(path, false);
length = measure.getLength();
float[] intervals = new float[]{length, length};
ObjectAnimator animator = ObjectAnimator.ofFloat(PathView.this, "phase", 1.0f, 0.0f);
animator.setDuration(2000);
animator.start();
}
}
//is called by animtor object
public void setPhase(float phase) {
Log.d("pathview", "setPhase called with:" + String.valueOf(phase));
paint.setPathEffect(createPathEffect(length, phase, 0.0f));
invalidate();//will calll onDraw
}
private PathEffect createPathEffect(float pathLength, float phase, float offset) {
return new DashPathEffect(new float[]{pathLength, pathLength},
Math.max(phase * pathLength, offset));
}
#Override
public void onDraw(Canvas c) {
super.onDraw(c);
for (Path path : paths) {
this.path = path;
c.drawPath(path, paint);
}
}
}
}

Related

Android Custom Class using drawable png inside Canvas.draw

I've followed some forums and I'm lost with this problem:
I have a Custom View that draws 9 circles for me as shown below:
This circles must be an icon to the main one and 8 images for the others and it must be a drawable resource (I have png pictures in on my drawable folder).
How may I proceed to set this drawable images instead of the colors?
This is my actual code:
public class CircleView extends View {
public static interface IMenuListener{
public void onMenuClick(MenuCircle item);
}
public static class MenuCircle{
private int x,y,radius;
public int id;
public String text;
}
private Paint mainPaint;
private Paint secondPaint;
private Paint textPaint;
private int radius_main =130;
private int menuInnerPadding = 40;
private int radialCircleRadius = 60;
private int textPadding = 25;
private double startAngle = - Math.PI/2f;
private ArrayList<MenuCircle> elements;
private IMenuListener listener;
public void setListener(IMenuListener listener){
this.listener = listener;
}
public void clear(){
elements.clear();
listener=null;
}
public CircleView(Context context) {
super(context);
init();
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
elements = new ArrayList<>();
}
public void addMenuItem(String text,int id){
MenuCircle item = new MenuCircle();
item.id = id;
item.text=text;
elements.add(item);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
mainPaint = new Paint();
mainPaint.setColor(Color.DKGRAY); //color of main circle
secondPaint = new Paint();
secondPaint.setColor(Color.DKGRAY); // color of 8 circles
textPaint = new Paint();
textPaint.setColor(Color.BLACK); // text under 8 circles
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int centerX = canvas.getWidth()/2 ;
int centerY= canvas.getHeight()/2;
canvas.drawCircle(centerX,centerY,radius_main,mainPaint);
for(int i=0;i<elements.size();i++){
double angle =0;
if(i==0){
angle = startAngle;
}else{
angle = startAngle+(i * ((2 * Math.PI) / elements.size()));
}
elements.get(i).x = (int) (centerX + Math.cos(angle)*(radius_main+menuInnerPadding+radialCircleRadius));
elements.get(i).y = (int) (centerY + Math.sin(angle)*(radius_main+menuInnerPadding+radialCircleRadius));
canvas.drawCircle( elements.get(i).x,elements.get(i).y,radialCircleRadius,secondPaint);
float tW = textPaint.measureText(elements.get(i).text);
canvas.drawText(elements.get(i).text,elements.get(i).x-tW/2,elements.get(i).y+radialCircleRadius+textPadding,textPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN){
for(MenuCircle mc : elements){
double distance = Math.hypot(event.getX()-mc.x,event.getY()-mc.y);
if(distance<= radialCircleRadius){
//touched
if(listener!=null)
listener.onMenuClick(mc);
return true;
}
}
}
return super.onTouchEvent(event);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
}

Canvas is not drawing in custom Android View

I have created my custom View in Android and trying to draw a circle in that but nothing is drawing but with no errors.
Here is my code
public class ColorOptionsView extends RelativeLayout {
private View mValue;
private ImageView mImage;
private Paint paint;
String cirlceText;
int circleColor,circleTextColor;
float circleTextSize;
public ColorOptionsView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ColorOptionsView, 0, 0);
try {
cirlceText = a.getString(R.styleable.ColorOptionsView_circleText);
circleColor = a.getColor(R.styleable.ColorOptionsView_circleColor, 0);
circleTextColor = a.getColor(R.styleable.ColorOptionsView_circleTextColor, 0);
circleTextSize = a.getFloat(R.styleable.ColorOptionsView_circleTextSize,20);
} finally {
a.recycle();
}
}
public void setCirlceText(String cirlceText) {
this.cirlceText = cirlceText;
invalidate();
requestLayout();
}
public void setCircleColor(int circleColor) {
this.circleColor = circleColor;
invalidate();
requestLayout();
}
public void setCircleTextColor(int circleTextColor) {
this.circleTextColor = circleTextColor;
invalidate();
requestLayout();
}
public void setCircleTextSize(float circleTextSize) {
this.circleTextSize = circleTextSize;
invalidate();
requestLayout();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
paint.setColor(circleColor);
int centerX = this.getMeasuredWidth()/2;
int centerY = this.getMeasuredHeight()/2;
int raduis = 150;
canvas.drawCircle(centerX,centerY,raduis,paint);
paint.setColor(circleTextColor);
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(cirlceText,centerX,centerY,paint);
canvas.drawLine(0,100,100,0,paint);
}
I am not getting where I went wrong. Devs check it and help me out.

Custom view is displayed properly, unable to repaint (invalidate) after an onClick event

I'm having repaint vs invalidate issues in Android. I have a simple activity that creates a button and displays my custom view (drawGrid class). I am attempting to repaint the grid plus a line after the onClick event. My main question is, how do I repaint from within my drawGrid class? Any nudge in the right direction would be appreciated here.
public class MainActivity extends Activity implements View.OnClickListener {
DrawGrid drawGrid;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
drawGrid = new DrawGrid(this);
drawGrid.setBackgroundColor(Color.BLACK);
setContentView(R.layout.activity_main);
View ballButton2 = findViewById(R.id.right_btn);
ballButton2.setOnClickListener(this);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.right_btn:
drawGrid.move();
}
}
}
public class DrawGrid extends View {
int x = 25;
int y = 25;
int index = 0;
public ArrayList<ArrayList<Integer>> playerOneRed = new ArrayList<>(100);
Paint paint = new Paint();
public DrawGrid(Context context) {
super(context);
paint.setColor(Color.BLUE);
paint.setStrokeWidth(2);
this.setBackgroundColor(Color.BLACK);
}
public DrawGrid(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public DrawGrid(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
paint.setColor(Color.BLUE);
paint.setStrokeWidth(2);
this.setBackgroundColor(Color.BLACK);
}
#Override
public void onDraw(Canvas canvas) {
Log.d("MyApp", "x is " + x);
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
for (int i = 0; i < 3000; i = i + 40) {
canvas.drawLine(i, 0, i, 3000, paint);
}
for (int i = 0; i < 3000; i = i + 40) {
canvas.drawLine(0, i, 3000, i, paint);
}
paint.setColor(Color.RED);
paint.setStrokeWidth(8);
// canvas.drawLine(0, 1000, 3000, 1000, paint);
for (ArrayList<Integer> iter : playerOneRed) {
canvas.drawLine(iter.get(0), iter.get(1), iter.get(2), iter.get(3), paint);
}
}
public void move() {
playerOneRed.add(new ArrayList<Integer>(4));
playerOneRed.get(index).add(0);
playerOneRed.get(index).add(1000);
playerOneRed.get(index).add(x + 250);
x = x + 250;
playerOneRed.get(index).add(1000);
index++;
Invalidate();
}
}

Android: Draw Custom TextView on Canvas

I have following TextView
public class Cube extends TextView {
Context mContext;
Drawable background;//Hintergrund des Blocks
char mLetter;//Buchstabe des Blocks
int x, y;//Koordinaten des Blocks
#SuppressWarnings("deprecation")
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public Cube(Context context, char letter, int _x, int _y) {
super(context);
mContext = context;
mLetter = letter;
background = ContextCompat.getDrawable(getContext(), R.drawable.cube);
x = _x;
y = _y;
this.setText("" + letter);
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN)
this.setBackgroundDrawable(background);
else
this.setBackground(background);
}
public void drawCube(Canvas canvas){//how to draw now!? This is called from a separate thread in SurfaceView
}
}
If I call following in drawCube():
background.setBounds(x, y, x + 20, y + 20);
background.draw(canvas);
it just draws the backgroundDrawable. But how can I draw it with the text/the letter inside? That it looks like this: (The background ist the canvas, the orange and white one is the Background and the "A" is the letter/text)
EDIT: Code at 21.09
This is my (shortened) thread:
public class CanvasThread extends Thread {
private SurfaceHolder mSh;
private ArrayList<Cube> mCubes;
private Canvas mCanvas;
private Context mContext;
private boolean mRun = false;
private boolean mDown = false;
private boolean newCube = false;
public CanvasThread(SurfaceHolder sh, Context context){
mSh = sh;
mCubes = new ArrayList<>();
mContext = context;
}
public void run(){
while(mRun){
mCanvas = null;
try{
mCanvas = mSh.lockCanvas(null);
synchronized (mSh){
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
newCube = true;
for(int i = 0; i < mCubes.size(); i++){
if(mCubes.get(i).getSpeed() > 0)
newCube = false;
if(mDown) {
if (mCubes.get(i).moveDown(feld)) {
mDown = false;
}
}
//mCubes.get(i).invalidate();
//mCubes.get(i).requestLayout();
mCubes.get(i).draw(mCanvas);
}
if(newCube)
addCube();
}
} finally {
if(mCanvas != null){
mSh.unlockCanvasAndPost(mCanvas);
}
}
}
}
public void addCube(){
Random r = new Random();
Cube cube = new Cube(mContext, mBuchstaben[r.nextInt(29)], r.nextInt(10), 0, mCanvas);
mCubes.add(cube);
}
}
This is my (shortened) fragment which uses the canvas/surface view:
public class KlassischFragment extends Fragment implements SurfaceHolder.Callback {
SurfaceHolder sh;
SurfaceView sv;
private CanvasThread thread;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_klassisch, container, false);
sv = (SurfaceView) view.findViewById(R.id.surfaceView);
sh = sv.getHolder();
sh.addCallback(this);
sh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
return view;
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new CanvasThread(sh, getContext());
thread.setRunnable(true);
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
//thread.setRunnable(false);
while(retry){
try{
thread.join();
retry = false;
} catch(InterruptedException ie){
//Immer wieder versuchen
}
break;
}
thread = null;
}
}
Here is an example on how to draw a text on top of a square. Some of the values hardcoded but you should be able to make them dynamic.
public class Cube extends View {
private final static String TEST_STRING = "ABC";
private Paint mBackgroundPaint;
private Paint mTextPaint;
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public Cube(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public Cube(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public Cube(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public Cube(Context context) {
this(context, null, -1);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Just for demo purposes this should be calculated properly
int desiredWidth = 100;
int desiredHeight = 100;
setMeasuredDimension(desiredWidth, desiredHeight);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int savedCount = canvas.save();
drawRectangle(canvas);
drawText(canvas);
canvas.restoreToCount(savedCount);
}
private void init() {
mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBackgroundPaint.setColor(Color.BLUE);
mBackgroundPaint.setStyle(Paint.Style.FILL);
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
// This need to be adjusted based on the requirements that you have
mTextPaint.setTextSize(20.0f);
}
private void drawRectangle(Canvas canvas) {
canvas.drawRect(0, 0, getWidth(), getHeight(), mBackgroundPaint);
}
private void drawText(Canvas canvas) {
Rect rect = new Rect();
// For simplicity I am using a hardcoded string
mTextPaint.getTextBounds(TEST_STRING, 0, 1, rect);
int w = getWidth(), h = getHeight();
float x = (w - rect.width()) / 2, y = ((h - rect.height()) / 2) + rect.height();
canvas.drawText(TEST_STRING, 0, 1, x, y, mTextPaint);
}
}

Draw circle on canvas simulating animation android

I need to draw an empty circle with a margin of 10 px. The problem that i've encountered is that i need to simulate the draw of the circle in 2 seconds and after that to start drawing on the top of it another one with another color. I'm using a custom view and i've tried to implement my logic into onDraw method and invalidate the view every 50 milisecond. The problem is that i can't manage to draw the circle...i draw only crapy figures. Does somebody know how can i draw a circle without using the canvas.drawCircle method because that method is drawing the circle directly without animation.
My current code
public class CustomAnimationView extends View{
private Canvas canvas;
private int count = 0;
private Paint paint;
private int mLeft;
private int mRight;
private int mBottom;
private int mTop;
public CustomAnimationView(Context context) {
super(context);
}
public CustomAnimationView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomAnimationView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setAttributes(attrs);
}
private void setAttributes(AttributeSet attrs) {
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
if(paint == null){
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(10);
paint.setColor(Color.BLACK);
}
if(count<150){
drawFirstQuarter(count);
}
count++;
}
public void drawFirstQuarter(int count){
RectF oval = new RectF(mLeft, mTop, mRight, mBottom);
canvas.drawArc(oval, 90, 30, true, paint);
}
public void setRect(int top, int bottom, int left, int right){
mBottom = bottom;
mTop = top;
mLeft = left;
mRight = right;
}
}
Right now I'm just tring to draw a bit of a circle.
Thanks. I've solved it.
Here is a code sample
public class CustomAnimationView extends View{
private Canvas canvas;
private int mCount = 0;
private Paint paint1;
private Paint paint2;
private RectF oval1;
private Context context;
private int mColorCount = 0;
public CustomAnimationView(Context context) {
super(context);
this.context = context;
}
public CustomAnimationView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public CustomAnimationView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
setAttributes(attrs);
}
private void setAttributes(AttributeSet attrs) {
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
if(paint1 == null){
paint1 = new Paint();
paint1.setAntiAlias(true);
paint1.setStyle(Style.STROKE);
paint1.setStrokeWidth(10);
}
if(paint2 == null){
paint2 = new Paint();
paint2.setAntiAlias(true);
paint2.setStyle(Style.STROKE);
paint2.setStrokeWidth(10);
}
if(mCount % 360 == 0 ){
mColorCount++;
}
if(mColorCount % 2 == 0){
paint1.setColor(context.getResources().getColor(R.color.white));
paint2.setColor(context.getResources().getColor(R.color.black));
}else{
paint2.setColor(context.getResources().getColor(R.color.white));
paint1.setColor(context.getResources().getColor(R.color.black));
}
if(oval1 == null)
oval1 = new RectF(5,5,canvas.getWidth()-5, canvas.getHeight()-5);
drawFirstQuarter(mCount, oval1);
}
public void drawFirstQuarter(int count, RectF oval){
canvas.drawArc(oval, 90, 360, false, paint2);
canvas.drawArc(oval, 90, count, false, paint1);
if(mCount == 330)
mCount = 0;
else
mCount += 30;
}
}

Categories

Resources