I'm an android developer. i'm working on a game and i need to change my letters style as below picture. How to add gradient in canvas as in the picture
this code add gradient but to whole view. if letters at bottom they are white if letters at top they are black
Paint p = new Paint();
// start at 0,0 and go to 0,max to use a vertical
// gradient the full height of the screen.
p.setShader(new LinearGradient(0, 0, 0, getHeight(), Color.BLACK, Color.WHITE, Shader.TileMode.MIRROR));
canvas.drawPaint(p);
try something like this:
class V extends View {
private String text = "Back To The Future";
private Paint paint;
public V(Context context) {
super(context);
paint = new Paint();
paint.setTextSize(32);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
Shader shader = new LinearGradient(0, paint.getTextSize() + bounds.top, 0, paint.getTextSize(), Color.RED, Color.YELLOW, TileMode.MIRROR);
paint.setShader(shader);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawText(text, 0, paint.getTextSize(), paint);
}
}
Related
I need to implement curved text which draw text on circular path on canvas.
It does draw circular path using
canvas.drawTextOnPath(QUOTE, circle, 485, 20, tPaint);
but it is not working for different length of the text.
Following is my Class to draw circular text on the canavs.
public class CircularTextVie extends View {
private String QUOTE = "";
private Path circle;
private Paint cPaint;
private Paint tPaint;
public CircularTextVie(Context context) {
super(context);
circle = new Path();
cPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
cPaint.setStyle(Paint.Style.STROKE);
cPaint.setColor(Color.LTGRAY);
cPaint.setStrokeWidth(3);
tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
tPaint.setStyle(Paint.Style.FILL_AND_STROKE);
tPaint.setColor(Color.BLACK);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.restore();
int xPos = (canvas.getWidth() /3);
int yPos = (int) ((canvas.getHeight() / 3) - ((tPaint.descent() + tPaint.ascent()) / 3)) ;
circle.addCircle(xPos, yPos, 150, Path.Direction.CW);
canvas.drawTextOnPath(QUOTE, circle, 485, 20, tPaint);
QUOTE="";
}
public void SetText(String text) {
this.QUOTE = text;
}
public void SetTypeFace(Typeface face) {
cPaint.setTypeface(face);
tPaint.setTypeface(face);
}
public void SetColor(int color) {
cPaint.setColor(color);
tPaint.setColor(color);
}
}
Thanks.
This can be done by varying the x and y positions based on textwidth
Define variables
private Rect textBounds;
private int mTextWidth, mTextHeight,centerX,centerY;
Add the below in the constructor of customview
textBounds = new Rect();
tPaint.getTextBounds(QUOTE, 0, QUOTE.length(), textBounds);
mTextWidth = Math.round(tPaint.measureText(QUOTE.toString())); // Use measureText to calculate width
mTextHeight = textBounds.height(); // Use height from getTextBounds()
Then in onDraw
canvas.drawCircle(centerX,centerY,150,mCirlcePaint);
circle.addCircle(centerX, centerY, 150, Path.Direction.CW);
// Note the 0 that's y offset. textdraw at circumference of the circle. Changing y you probably need to change the radius as well i guess.
canvas.drawTextOnPath(QUOTE, circle, (centerX)-(mTextWidth / 2f), 0, tPaint);
centerX,centerY are the center of the circle ie canvaswidht/2 and canvasHeight/2. I drew a circle for reference
The results for hello
The result for a bigger text
For numbers
Edit: To the question in comment
The math involved is in calculating the semi circle using text length
radius = (float) ((mTextWidth) / (Math.PI)). If text length is greater than your canvas you need to reduce the text size or use the full circle radius = (float) ((mTextWidth) / (2*(Math.PI))). Few other edge case you can consider to draw the text properly.
public class GraphicsView extends View {
private String QUOTE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private Path circle;
private Paint mCirlcePaint;
private Paint tPaint;
private Rect textBounds;
private int mTextWidth, mTextHeight, centerX, centerY;
private float radius;
public GraphicsView(Context context) {
super(context);
circle = new Path();
tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
tPaint.setStyle(Paint.Style.FILL_AND_STROKE);
tPaint.setColor(Color.BLACK);
tPaint.setTextSize(100f);
textBounds = new Rect();
tPaint.getTextBounds(QUOTE, 0, QUOTE.length(), textBounds);
mTextWidth = Math.round(tPaint.measureText(QUOTE.toString())); // Use measureText to calculate width
mTextHeight = textBounds.height(); // Use height from getTextBounds()
mCirlcePaint = new Paint();
mCirlcePaint.setStyle(Paint.Style.FILL);
mCirlcePaint.setColor(Color.GREEN);
radius = (float) ((mTextWidth) / (Math.PI));
}
#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.rotate(180, getWidth() / 2, getHeight() / 2);
canvas.drawCircle(centerX, centerY, radius, mCirlcePaint);
circle.addCircle(centerX, centerY, radius, Path.Direction.CW);
canvas.drawTextOnPath(QUOTE, circle, 0, 0, tPaint);
}
}
I have onDraw method where I want to cut a small piece of large bitmap. This will be a circle (position X and Y). Then I want to draw it by canvas.
I rewrite method from this answer for that reason, but always got grey circle instead circle piece of large Bitmap.
private Bitmap cutCircleBitmap() {
Bitmap output = Bitmap.createBitmap(2 * RADIUS, 2 * RADIUS, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(bitmapX - RADIUS, bitmapY - RADIUS, 2 * RADIUS, 2 * RADIUS);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawCircle(RADIUS, RADIUS, RADIUS, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
Use Canvas.drawRoundRect() and BitmapShader to do it :
public class CropView extends View {
public CropView(Context context) {
this(context, null);
}
public CropView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CropView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setFilterBitmap(true);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(radius * 2, radius * 2);
}
private Paint mPaint;
private int radius = 100;
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK); // draw background help us see the result
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sample);
canvas.drawBitmap(cropCircleBitmap(srcBitmap, 200, 60), 0, 0, mPaint);
}
private Bitmap cropCircleBitmap(Bitmap srcBitmap, float left, float top) {
Bitmap dstBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(dstBitmap);
canvas.drawBitmap(srcBitmap, -left, -top, mPaint);
mPaint.setShader(new BitmapShader(dstBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
dstBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
canvas.setBitmap(dstBitmap);
canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()), radius, radius, mPaint);
return dstBitmap;
}
}
I'm trying to do the following you can see in the picture, but instead of that black square, I'd like to have a white square:
This is my code so far:
public class SmallWhiteThing extends View {
Context context;
Paint paint = new Paint();
// CONSTRUCTOR
public SmallWhiteThing(Context context) {
super(context);
setFocusable(true);
}
public SmallWhiteThing(Context context, AttributeSet attrs)
{
super(context, attrs);
this.context = context;
}
public SmallWhiteThing(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
this.context = context;
}
#Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap b = Bitmap.createBitmap(120, 120, Bitmap.Config.ALPHA_8);
Canvas c = new Canvas(b);
c.drawColor(Color.WHITE);
paint.setStrokeWidth(0);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setTextSize(40);
paint.setAntiAlias(true);
c.drawText("Hello", 30, 30, paint);
canvas.drawBitmap(b, 140, 270, paint);
}
}
I tried as you can see this:
c.drawColor(Color.WHITE);
But without any luck.
Tips are really appreciated.
I'm trying somethin else, and I'm getting this:
Code:
Bitmap b = Bitmap.createBitmap(120, 120, Bitmap.Config.ALPHA_8);
Canvas c = new Canvas(b);
c.drawColor(Color.WHITE);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(0f);
c.drawRect(0, 0, 150, 150, paint);
canvas.drawBitmap(b, 100, 100, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
paint.setTextSize(40);
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
canvas.drawText("Helloo", 100, 200, paint);
For whoever needs it. This is working:
Current usage (fills a imageview in screen):
//Params: Text, textSize
createBlabla("Text to show", 35);
public void createBlabla(String text, int fontSize){
int paddingRight = 10;
int paddingLeft = 5;
int paddingBottom = 5;
//Paint config
Paint paint = new Paint();
paint.setTextSize(fontSize);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
paint.setAntiAlias(true);
Bitmap largeWhiteBitmap = Bitmap.createBitmap((int) paint.measureText(text) + paddingRight, fontSize + paddingRight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(largeWhiteBitmap);
canvas.drawColor(Color.WHITE);
canvas.drawText(text, paddingLeft, fontSize, paint);
ImageView imv = (ImageView)MainActivity.this.findViewById(R.id.imageView1);
imv.setImageBitmap(largeWhiteBitmap);
}
Note that what you see in the screen is a whole relative layout with an imageView in the middle. This imageview gets a Bitmap as Image with the previous code.
The relativeLayout has green background.
I am trying to have a custom EditText with a custom background which is not possible to draw using drawable XMLs
Here is what I have right now
public class EMEditText extends EditText {
private Bitmap framedBitmap;
public EMEditText(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas) {
if(framedBitmap == null) {
createDrawable(getWidth(), getHeight());
}
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
// canvas.drawBitmap(framedBitmap, 0, 0, paint);
}
private void createDrawable(int width, int height) {
// create a new bitmap of given size
Bitmap start = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(start);
RectF outerRect = new RectF(0, 0, width, height);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
// paint.setStrokeWidth(1);
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
canvas.drawRoundRect(outerRect, height / 2, height / 2, paint);
framedBitmap = start;
}
}
What is probably wrong in your code is that you are creating your own Canvas object in createDrawable() method though onDraw() method gives you the right Canvas which you should use for your drawings.
So what you probably want is to change createDrawable(int width, int height) method to createDrawable(int width, int height, Canvas c). Your code should look like this then:
#Override
protected void onDraw(Canvas canvas) {
if(framedBitmap == null) {
createDrawable(getWidth(), getHeight(), canvas);
}
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
// canvas.drawBitmap(framedBitmap, 0, 0, paint);
}
private void createDrawable(int width, int height, Canvas c) {
// create a new bitmap of given size
Bitmap start = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
c.setBitmap(start);
RectF outerRect = new RectF(0, 0, width, height);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
// paint.setStrokeWidth(1);
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
c.drawRoundRect(outerRect, height / 2, height / 2, paint);
framedBitmap = start;
}
As you can see, I changed also the body of your createDrawable() method so that it uses Canvas from onDraw() and sets it's Bitmap to the one created by you.
I am attempting to draw a bitmap along a rectangle, but I am not sure how to go about it. Is there a way to tile a bitmap along a Rect object using a paint property or something? I have looked, but I can't find anything that makes it do what I need it too, most of the tiling options won't tile it for a specific instance, they tile it along the entire screen, so everything using that bitmap ends up having one big bitmap tiling along all of them at the same time, without scrolling or anything.
Any ideas? If you need more info let me know, its kind of a weird question so I know I probably didn't mention something important.
William
There are a couple ways that you can attack this. I'll outline two of them here...
One way:
You can define a BitmapDrawable around the Bitmap. Set its TileMode to repeat. Give it some bounds via setBounds(rect) where rect is your Rect instance.
Here's a brief example using a View onDraw as context:
public class MyView extends View {
Rect rect;
Bitmap mBitmap;
BitmapDrawable mDrawable;
public MyView(Context context) {
super(context);
rect = new Rect(0, 0, 100, 100);
mBitmap = loadBitmap();
mDrawable = new BitmapDrawable(context.getResources(), mBitmap);
mDrawable.setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
mDrawable.setBounds(rect);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDrawable.draw(canvas);
}
public Bitmap loadBitmap() {
// included only for example sake
Paint paint = new Paint();
paint.setColor(Color.RED);
Bitmap bm = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bm);
canvas.drawRect(0,0,10,10, paint);
paint.setStyle(Style.STROKE);
paint.setColor(Color.BLUE);
canvas.drawRect(0, 0, 9, 9, paint);
return bm;
}
}
Note:
You can also define a BitmapDrawable in xml instead of doing it in code.
Also, if you know that a drawable you are loading via getResources().getDrawable(resourceId) is indeed just a Bitmap, you can cast it to a BitmapDrawable and set the TileMode there. A la:
public class MyView extends View {
Rect rect;
BitmapDrawable mDrawable;
public MyView(Context context) {
super(context);
rect = new Rect(0, 0, 400, 240);
mDrawable = (BitmapDrawable) context.getResources().getDrawable(R.drawable.ic_launcher);
mDrawable.setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
mDrawable.setBounds(rect);
this.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_launcher));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDrawable.draw(canvas);
}
}
This example shows the background being stretched, and a tiled version being draw over top of it.
Another way:
Loop in the x and y direction and repeatedly draw the bitmap into the rect:
public class MyView extends View {
Rect rect;
Bitmap mBitmap;
public MyView(Context context) {
super(context);
rect = new Rect(0, 0, 100, 100);
mBitmap = loadBitmap();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final int bmWidth = mBitmap.getWidth();
final int bmHeight = mBitmap.getHeight();
for (int y = 0, height = rect.height(); y < height; y += bmHeight) {
for (int x = 0, width = rect.width(); x < width; x += bmWidth) {
canvas.drawBitmap(mBitmap, x, y, null);
}
}
}
public Bitmap loadBitmap() {
// included only for example sake
Paint paint = new Paint();
paint.setColor(Color.RED);
Bitmap bm = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bm);
canvas.drawRect(0,0,10,10, paint);
paint.setStyle(Style.STROKE);
paint.setColor(Color.BLUE);
canvas.drawRect(0, 0, 9, 9, paint);
return bm;
}
}
I personally would go for the first (BitmapDrawable) method.
You can do it just like BitmapDrawable does:
Define Paint with bitmap shader and then draw rectangle with that paint:
> Paint paint = new Paint();
> paint.setShader(new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
>
> canvas.drawRect(destRect, paint);