I'm new in Android and I've written the following sample code.
public class Circle extends View {
Paint paint = new Paint();
Path path = new Path();
private static final String s = "Hello world example";
public Circle(Context context) {
super(context);
paint.setColor(Color.BLACK);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(2);
paint.setAntiAlias(true);
paint.setTextSize(30);
}
public void onDraw(Canvas c) {
path.addCircle(getWidth()/2, getHeight()/2, 180, Direction.CW);
c.drawTextOnPath(s, path, 0, 10, paint);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
}
The Canvas.drawTextOnPath() is displaying the the text beginning from the right side (I mean positive X-axis). I want to display the text from top in a clock-wise. I want to change the starting position of the text. I'm confused about Android Canvas.translate() and Canvas.scale(). Or should I use Canvas.rotate()? I've pasted the output below for clear understanding my question.
I want to display the output in this form.
I've finally fixed my Canvas issue by adding the Canvas.rotate(float degrees, float px, float py) in my code before applying and Canvas methods. Below is the code.
public class Circle extends View {
Paint paint = new Paint();
Path path = new Path();
private static final String s = "Hello world example";
public Circle(Context context) {
super(context);
paint.setColor(Color.BLACK);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(2);
paint.setAntiAlias(true);
paint.setTextSize(30);
}
public void onDraw(Canvas c) {
c.rotate(-90, getWidth()/2, getHeight()/2);
path.addCircle(getWidth()/2, getHeight()/2, 180, Direction.CW);
c.drawTextOnPath(s, path, 0, 10, paint);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
}
I tried Canvas.rotate(float degrees) before but didn't worked. However, Canvas.rotate(float degrees, float px, float py) worked!
Instead of circle, arc can be used:
Path path = new Path();
RectF rect = new RectF(width/2 - radius, height/2 - radius, width/2 + radius, height/2 + radius);
path.addArc(rect 270, 270);
canvas.drawTextOnPath(msg., path, 0, 0, paint);
The path can be translated, rotated and scaled by using Matrix.
For example, the above code will draw the text starting from the first quadrant, i.e, from (y, 0). To start the drawing from (-y, 0) in clockwise direction,
Path path = new Path();
RectF rect = new RectF(width/2 - radius, height/2 - radius, width/2 + radius, height/2 + radius);
Matrix matrix = new Matrix();
matrix.setScale(-1, -1, width/2, height/2);
path.addArc(rect, 270, 270);
path.transform(matrix);
canvas.drawTextOnPath(msg, path, 0, 0, paint);
Related
I'm making an app that can freehand crop a picture using a canvas in android studio. My problem is that after cropping the picture, the cropped part stays in the same exact position as it was originally, whereas i want it to get centered and enlargened. Is there any way to take the non-transparent part and center it, or maybe remove the transparent part all-together?
Screenshot of my app where i want the banana to be centered
https://i.stack.imgur.com/8OKNT.png
Bitmap bitmap;
Path path = new Path();
Paint paint;
int width;
int height;
Rect src;
Rect dest;
public CutImage(Context context, Bitmap bitmap2) {
super(context);
bitmap = bitmap2;
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
paint.setStrokeWidth(5f);
width = getWindowManager().getDefaultDisplay().getWidth();
height = getWindowManager().getDefaultDisplay().getHeight();
src = new Rect(0, 0, bitmap.getWidth() - 1, bitmap.getHeight() - 1);
dest = new Rect(0, 0, width - 1, height - 1);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.getHeight();
canvas.drawBitmap(bitmap,src,dest, null);
canvas.drawPath(path, paint);
}
private void crop() {
Bitmap croppedBitmap =
Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(),bitmap.getConfig());
Canvas cropCanvas = new Canvas(croppedBitmap);
Paint paint = new Paint();
cropCanvas.drawPath(path,paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
cropCanvas.drawBitmap(bitmap,src,dest,paint);
bitmap = croppedBitmap;
showImage2(bitmap);
}
} ```
How to do this in android ? Is it possible using some selector designs? I have one option that I can use a icon for this and set it as drawableLeft but without using the icon how can I achieve this please guide me in good direction
You could achieve this with a custom Drawable. Something like:
public class BackgroundColorDrawable extends Drawable {
private Paint paint;
private RectF rectF;
private float cornerRadius = 20f;
private float borderThickness = 3.5f;
private int insetColour = Color.GREEN;
public BackgroundColorDrawable() {
paint = new Paint();
paint.setAntiAlias(true);
rectF = new RectF();
}
public void setInsetColour(int insetColour) {
this.insetColour = insetColour;
invalidateSelf();
}
public void setBorderThickness(float borderThickness) {
this.borderThickness = borderThickness;
invalidateSelf();
}
public void setCornerRadius(float cornerRadius) {
this.cornerRadius = cornerRadius;
invalidateSelf();
}
#Override
public void draw(Canvas canvas) {
paint.setColor(Color.GRAY);
rectF.set(0f, 0f, canvas.getWidth(), canvas.getHeight());
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint);
paint.setColor(Color.WHITE);
rectF.set(borderThickness, borderThickness, canvas.getWidth() - borderThickness, canvas.getHeight() - borderThickness);
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint);
paint.setColor(insetColour);
rectF.set(borderThickness, borderThickness, 60f, canvas.getHeight() - borderThickness);
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint);
paint.setColor(Color.WHITE);
rectF.set(30f, borderThickness, 60f, canvas.getHeight() - borderThickness);
canvas.drawRect(rectF, paint);
}
#Override
public void setAlpha(int alpha) { /* to implement */ }
#Override
public void setColorFilter(ColorFilter colorFilter) { /* to implement */}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
Then wherever you are using your EditText you just have to set the background drawable in code:
BackgroundColorDrawable drawable = new BackgroundColorDrawable();
editText.setBackground(drawable);
Note there's quite a bit of overdraw in this example (the same pixel gets drawn several times) which you could optimise for.
You'll also have to set some left padding on your EditText for the cursor to line up properly.
You can use a background-image on the EditText
editText.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.pic_name, 0);
I'm making a very very simple game in Android, and I'm not using OpenGL or any other libraries, just Java!
Now I'm stuck in designing my map...
I want to design something like this:
(Those lines should consider as walls and players can't get out of them)
How to design something like this using XML only? Or I should start using Unity3D?
This isn't done with xml, but you neither need any libraries.
public class Background extends View {
private static final int BORDER_WIDTH = 2; //in px
private int[] points; //2n = x, 2n+1 = y
public Background(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for(Drawable drawable : drawBackground()){
drawable.draw(canvas);
}
}
private Drawable[] drawBackground() {
Drawable[] drawables = new Drawable[2];
int width = getWidth();
int height = getHeight();
int corner = width / 4;
//draw border
Path path = new Path();
path.moveTo(0, corner);
path.lineTo(corner, 0);
path.lineTo(width, 0);
path.lineTo(width, height - corner);
path.lineTo(width - corner, height);
path.lineTo(0, height);
path.close();
drawables[0] = new ShapeDrawable(new PathShape(path, width, height));
drawables[0].setBounds(0, 0, width, height);
//draw inside the border
points = {
BORDER_WIDTH, corner,
corner, BORDER_WIDTH,
width - BORDER_WIDTH, BORDER_WIDTH,
width - BORDER_WIDTH, height - corner,
width - corner, height - BORDER_WIDTH,
BORDER_WIDTH, height - BORDER_WIDTH
}
path = new Path();
path.moveTo(points[0], points[1]);
for (int i = 2, i < points.length, i++) {
path.lineTo(points[i], points[++i]);
}
path.close();
ShapeDrawable shapeDrawable = new ShapeDrawable(new PathShape(path, width, height));
shapeDrawable.getPaint().setColor(Color.rgb(238, 238, 238));
shapeDrawable.setBounds(0, 0, width, height);
drawables[1] = shapeDrawable;
return drawables;
}
public Point[] getPoints() {
return points;
}
}
The result:
I've the following code below.
public class CompassActivity extends Activity {
public class OuterCircle extends View {
Paint paint = new Paint();
Path path = new Path();
private static final String s = "Hello world example";
public OuterCircle(Context context) {
super(context);
init();
}
private void init() {
paint.setColor(Color.WHITE);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(2);
paint.setAntiAlias(true);
}
private void drawDegreesOnCircle(Canvas c) {
path.addCircle(getWidth()/2, getHeight()/2, 180, Direction.CW);
c.drawTextOnPath(s, path, 0, 10, paint);
}
public void onDraw(Canvas c) {
int cx = getWidth()/2;
int cy = getHeight()/2;
c.drawCircle(cx, cy, 170, paint);
drawDegreesOnCircle(c);
}
}
}
The circle is drawn successfully. However, the string I've specified is not displayed. There is no error or warning in the code. Am I missing anything in my code? I'm trying to display the string around the circle. I got stuck here. :D
I've fixed the above issue by adding
setLayerType(View.LAYER_TYPE_SOFTWARE, null)
It is required to use the above method along with the
Canvas.drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint)
for Android API level 11 or higher. The string is now displayed successfully around the circle. Here is the correct code.
public class CompassActivity extends Activity {
public class OuterCircle extends View {
Paint paint = new Paint();
Path path = new Path();
private static final String s = "Hello world example";
public OuterCircle(Context context) {
super(context);
init();
}
private void init() {
paint.setColor(Color.WHITE);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(2);
paint.setAntiAlias(true);
}
private void drawDegreesOnCircle(Canvas c) {
path.addCircle(getWidth()/2, getHeight()/2, 180, Direction.CW);
c.drawTextOnPath(s, path, 0, 10, paint);
setLayerType(View.LAYER_TYPE_SOFTWARE, null); // Required for API level 11 or higher.
}
public void onDraw(Canvas c) {
int cx = getWidth()/2;
int cy = getHeight()/2;
c.drawCircle(cx, cy, 170, paint);
drawDegreesOnCircle(c);
}
}
}
You're missing a call to drawPath()
private void drawDegreesOnCircle(Canvas c) {
path.addCircle(getWidth()/2, getHeight()/2, 180, Direction.CW);
c.drawPath(path, paint);
c.drawTextOnPath(s, path, 0, 10, paint);
}
A very simple example just to get text in an angle on the center of the display.
public class DrawSomeText extends View {
Paint mPaint;
public DrawSomeText(Context context) {
super(context);
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
}
#Override
public void onDraw(Canvas canvas) {
Path path = new Path();
path.moveTo(getWidth()/2, getHeight()/2);
path.lineTo(getWidth(), getHeight());
path.close();
canvas.drawPath(path, mPaint);
canvas.drawTextOnPath("Hello World", path, 0, 0, mPaint);
}
}
How do I find the coordinates of the screen? I know e.g. a phone would have say a 960 x 540 resolution, but in the emulators some of the edges are not filled if I draw a shape to that resolution. Is there a way around this?
For the colour of the rectangle, it is seen there are two rectangles, and two of them have the same colour despite giving two separate colours for drawPaint. Just setting a new variable e.g. drawPaint2 returns errors. How to change the colour of both?
How to use the path function in the canvas. E.g. to draw a triangle? I have included my attempt in the code but it doesn't display a triangle.
public class DrawView extends View implements OnTouchListener
{
private Paint backgroundPaint = new Paint();
private Paint drawPaint = new Paint();
private Paint circlePaint = new Paint();
private Paint textPaint = new Paint();
private Paint path = new Paint();
private float sx, sy;
public DrawView(Context context)
{
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
backgroundPaint.setColor(Color.CYAN);
backgroundPaint.setAntiAlias(true);
backgroundPaint.setStyle(Style.FILL);
drawPaint.setColor(Color.WHITE);
drawPaint.setStyle(Style.FILL);
circlePaint.setColor(Color.DKGRAY);
circlePaint.setStyle(Style.FILL);
textPaint.setColor(Color.WHITE);
textPaint.setStyle(Style.FILL);
drawPaint.setColor(Color.GREEN);
drawPaint.setStyle(Style.FILL);
circlePaint.setColor(Color.RED);
circlePaint.setStyle(Style.FILL);
path.setColor(android.graphics.Color.RED);
path.setStyle(Paint.Style.FILL);
Path path = new Path();
path.moveTo(1, 1);
path.lineTo(20, 50);
path.moveTo(20, 50);
path.lineTo(100, 100);
path.moveTo(100, 100);
path.lineTo(1, 1);
path.close();
this.setOnTouchListener(this);
}
#Override
public void onDraw(Canvas canvas)
{
//canvas.drawPath(path, paint); <-- error
// to draw background
canvas.drawRect(this.getLeft(), this.getTop(), this.getRight(), this.getBottom(), backgroundPaint);
//to draw two rectangle with blue and green paint
canvas.drawRect(100,100, 340,540, drawPaint);
canvas.drawRect(00,00, 120,80, drawPaint);
//draw text with paint
canvas.drawText("Hello Dear Leader!", 110, 160, textPaint);
//draw a circle with green paint with the touch coordinates
canvas.drawCircle(sx-30,sy-30, 30, circlePaint);
//draw a circle with red paint with the touch coordinates
canvas.drawCircle(sx-80, sy-80, 10, circlePaint);
}
public boolean onTouch(View v, MotionEvent event)
{
//update the coordinates for the OnDraw method above, with wherever we touch
sx = event.getX();
sy = event.getY();
invalidate();
return true;
}
}
for the size you can easily call canvas.getWidth() and canvas.getHeight() and do all your values a percentage of those. Do never assume a constant!
You need to use two separate Paints to use two different colors. And remember that each paint is an object that needs initialisation.
// objects
private Paint drawPaint_WH = new Paint();
private Paint drawPaint_GR = new Paint();
// during construction
drawPaint_WH.setColor(Color.WHITE);
drawPaint_WH.setStyle(Style.FILL);
drawPaint_GR.setColor(Color. GREEN);
drawPaint_GR.setStyle(Style.FILL);
// and then during draw()
canvas.drawRect(100,100, 340,540, drawPaint_WH);
canvas.drawRect(0,0, 120,80, drawPaint_GR);
and then to make a triangle:
// object
private Path trianglePath;
// during construction
trianglePath = new Path();
trianglePath.moveTo(10, 10); // starting point
trianglePath.lineTo(10, 50); // 1st vertix
trianglePath.lineTo(50, 10); // 2nd vertix
trianglePath.lineTo(10, 10); // 3rd vertix and close
// then during draw()
canvas.drawPath(trianglePath, drawPaint_GR) // or whatever paint you want
ps.: do color the background it's easier to call canvas.drawColor(int colorVal);