I need to create ViewGroup custom shape. Its may be FrameLayout.It should look like
Its must be ViewGroup cause I need to add text or image inside.How can i do this? Thanks a lot.
There is a good tutorial here on creating custom polygon shapes. It is a fairly long process, but you will get there. In short, you will have to create custom XML attributes for a custom View.
The real magic is here:
#Override
protected void onDraw(Canvas canvas) {
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
int x = (measuredWidth/2) ;
int y = (measuredHeight/2) ;
int radius = Math.min(x,y) ;
if (sides < 3) return;
float a = (float) (Math.PI * 2)/sides;
int workingRadius = radius;
polyPath.reset();
// The poly is created as a shape in a path.
// If there is a hole in the poly, draw a 2nd shape inset from the first
for(int j = 0; j < ((fillPercent < 100) ? 2 : 1) ; j++){
polyPath.moveTo(workingRadius,0);
for (int i = 1; i < sides; i++) {
polyPath.lineTo((float)(workingRadius*Math.cos(a*i)),
(float)(workingRadius*Math.sin(a*i)));
}
polyPath.close();
workingRadius -= radius * fillPercent;
a = -a;
}
canvas.save();
canvas.translate(x, y);
canvas.rotate(startAngle);
canvas.drawPath(polyPath, fillPaint);
canvas.restore();
if(showInscribedCircle){
canvas.drawCircle(x,y,radius, inscribedCirclePaint);
}
super.onDraw(canvas);
}
Related
I have problem where i need to add a button on center of transparent area in image.
Example:
according to above image i have hundreds of photo frame and each frame there is a transparent area and i need to add a button on center of this transparent area.
Now i want a solution in which i can get coordinates of "x" programatically.
Please help.
public static PointF getTransparentCenter(Bitmap bitmap, Point viewSize) {
List<Point> transparentPoints = new ArrayList<>();
for (int i = 0; i < bitmap.getWidth(); i++) {
for (int j = 0; j < bitmap.getHeight(); j++) {
int pixel = bitmap.getPixel(i, j);
if ((pixel & 0xff000000) == 0) {
//the point color is transparent
transparentPoints.add(new Point(i, j));
}
}
}
int totalX = 0;
int totalY = 0;
for (Point transparentPoint : transparentPoints) {
totalX += transparentPoint.x;
totalY += transparentPoint.y;
}
float centerX = (float) totalX / transparentPoints.size();
float centerY = (float) totalY / transparentPoints.size();
float x = viewSize.x * centerX / bitmap.getWidth();
float y = viewSize.y * centerY / bitmap.getHeight();
return new PointF(x, y);
}
I think this is stupid, but I think there's no other way.
I know that creating objects inside the onDraw method is very costly. I want to draw a matrix of rounded rectangles, which coordinates are dynamic, and I can't cache all that rectangles, because I use a scroll view and there may be a lot of rectangles, there's no other overload for drawRoundRect method, which has primitive arguments, and I forced to create a Rectangle object in every iteration. Who can suggest an effective solution for that?
#Override
protected void onDraw(Canvas canvas) {
int h = getMeasuredHeight();
int tileSize = h / rows;
for(int i = 0; i < rows; ++i) {
for(int j = 0; j < columns; ++j) {
int x = j * tileSize;
int y = i * tileSize;
canvas.drawRoundRect(new RectF(x, y, x + tileSize, y + tileSize), 10, 10, tilePaint);
}
}
}
This is a just an example, rectangles can have arbitrary coordinates.
RectF has the set(left, top, right, bottom) method. You could allocate it on the constructor and it this method to change the Rectf's bounds.
mRect.set(x, y, x + tileSize, y + tileSize);
where mRect is RectF mRect = new RectF();
Is it possible to create and draw a Moving Grid on a canvas that recycles its points? I want to create a Grid on an android canvas that moves downwards and recycles its points when a point reaches the bottom of the screen.
The First part of the question is: How do I draw a grid with lines on an Android Canvas?
The Second part: How do I make it scroll and repeat?
The grid should look something like this:
I have tried doing this with a Bitmap , but I am not sure if that is as efficient as doing it By using the Draw Line feature. Plus, I cannot access the girds points when using a bitmap, so it is not very useful when trying to draw a graph for example.
I am developing a drawing app, and I encountered the same problem. I searched everywhere, but I could not found a direct solution. That is why I developed a library that do exactly that. It creates a infinite grid that can be transformed, include transformations are: Translate, Rotate and Scale. The library generates only the visible lines, that are shown on the View and are generated in real time using simple math. Here is a direct link to the library
The explanation is pretty simple, if you want to learn more about how it works your can check the Wiki page.
Here is a link to the library source code, if you are interested.
To tag onto Balha's answer:
the android/java equivalent looks something like this:
int canvasWidth = 0;
int canvasHeight = 0;
float gridSize = 20f;
float ecart = Math.max(mCanvasHeight, mCanvasWidth) / gridSize;
//last j index value
int lj= 0;
//last i index value
int li = 0;
canvasWidth = canvas.getWidth();
canvasHeight = canvas.getHeight();
for (int j = 0; j <= Math.min(canvasWidth, canvasHeight); j += (int)ecart)
{
for (int i = 0; i <= Math.max(canvasWidth, canvasHeight); i += (int)ecart)
{
li = i;
}
lj = j;
}
canvas.clipRect(0, 0, lj, canvas.getHeight());
for (int j = 0; j <= Math.min(canvasWidth, canvasHeight); j += (int)ecart)
{
for (int i = 0; i <= Math.max(canvasWidth, canvasHeight); i += (int)ecart)
{
//horizontal lines
canvas.drawLine(j, i, i, i, paint);
//vertical lines
canvas.drawLine(j, i, j, j, paint);
}
}
I know its too late but It can help someone else;
This Draws a perfect grid mesh
Note: This is a c# code
float gridSize = 20f;
var ecart = Math.Max(MaxHeight, MaxWidth) / gridSize;
//last j index value
int lj= 0;
//last i index value
int li = 0;
for (int j = 0; j <= Math.Min(canvas.Width, canvas.Height); j += (int)ecart)
{
for (int i = 0; i <= Math.Max(canvas.Width, canvas.Height); i += (int)ecart)
{
li = i;
}
lj = j;
}
canvas.ClipRect(0, 0, lj, canvas.Height);
for (int j = 0; j <= Math.Min(canvas.Width, canvas.Height); j += (int)ecart)
{
for (int i = 0; i <= Math.Max(canvas.Width, canvas.Height); i += (int)ecart)
{
//horizontal lines
canvas.DrawLine(j, i, i, i, paint);
//vertical lines
canvas.DrawLine(j, i, j, j, paint);
}
}
I'm trying to make an app that will take two pictures you specify via editText, compare the colors of each pixel on both images and create a new picture (bitmap) (that you can save to the sd card) containing the differences between the two original pictures.
I'm having a problem with creating this new bitmap. How can I achieve my goal? I don't really know how to do this, do I create the new bitmap first and then write into it, or do I get the differences first and then draw a bitmap from that? The pictures will be approx. 300x300 px.
this code is just out of my head and untested but it should get you on the right track.
final int w1 = b1.getWidth();
final int w2 = b2.getWidth();
final int h1 = b1.getHeight();
final int h2 = b2.getHeight();
final int w = Math.max(w1, w2);
final int h = Math.max(h2, h2);
Bitmap compare = Bitmap.createBitmap(w, h, Config.ARGB_8888);
int color1, color2, a, r, g, b;
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
if (x < w1 && y < h1) {
color1 = b1.getPixel(x, y);
} else {
color1 = Color.BLACK;
}
if (x < w2 && y < h2) {
color2 = b2.getPixel(x, y);
} else {
color2 = Color.BLACK;
}
a = Math.abs(Color.alpha(color1) - Color.alpha(color2));
r = Math.abs(Color.red(color1) - Color.red(color2));
g = Math.abs(Color.green(color1) - Color.green(color2));
b = Math.abs(Color.blue(color1) - Color.blue(color1));
compare.setPixel(x, y, Color.argb(a, r, g, b));
}
}
b1.recycle();
b2.recycle();
I would create the bitmap first and compute the differences between each pixel, but you're welcome to compute the differences first and then use Bitmap.copyPixels, but I think it's easier to understand the first way. Here is an example:
// Load the two bitmaps
Bitmap input1 = BitmapFactory.decodeFile(/*first input filename*/);
Bitmap input2 = BitmapFactory.decodeFile(/*second input filename*/);
// Create a new bitmap. Note you'll need to handle the case when the two input
// bitmaps are not the same size. For this example I'm assuming both are the
// same size
Bitmap differenceBitmap = Bitmap.createBitmap(input1.getWidth(),
input1.getHeight(), Bitmap.Config.ARGB_8888);
// Iterate through each pixel in the difference bitmap
for(int x = 0; x < /*bitmap width*/; x++)
{
for(int y = 0; y < /*bitmap height*/; y++)
{
int color1 = input1.getPixel(x, y);
int color2 = input2.getPixel(x, y);
int difference = // Compute the difference between pixels here
// Set the color of the pixel in the difference bitmap
differenceBitmap.setPixel(x, y, difference);
}
}
I have the following routine in a subclass of view:
It calculates an array of points that make up a line, then erases the previous lines, then draws the new lines (impact refers to the width in pixels drawn with multiple lines). The line is your basic bell curve, squeezed or stretched by variance and x-factor.
Unfortunately, nothing shows on the screen. A previous version with drawPoint() and no array worked, and I've verified the array contents are being loaded correctly, and I can see that my onDraw() is being triggered.
Any ideas why it might not be drawn? Thanks in advance!
protected void drawNewLine( int maxx, int maxy, Canvas canvas, int impact, double variance, double xFactor, int color) {
// impact = 2 to 8; xFactor between 4 and 20; variance between 0.2 and 5
double x = 0;
double y = 0;
int cx = maxx / 2;
int cy = maxy / 2;
int mu = cx;
int index = 0;
points[maxx<<1][1] = points[maxx<<1][0];
for (x = 0; x < maxx; x++) {
points[index][1] = points[index][0];
points[index][0] = (float) x;
Log.i(DEBUG_TAG, "x: " + x);
index++;
double root = 1.0 / (Math.sqrt(2 * Math.PI * variance));
double exponent = -1.0 * (Math.pow(((x - mu)/maxx*xFactor), 2) / (2 * variance));
double ePow = Math.exp(exponent);
y = Math.round(cy * root * ePow);
points[index][1] = points[index][0];
points[index][0] = (float) (maxy - y - OFFSET);
index++;
}
points[maxx<<1][0] = (float) impact;
for (int line = 0; line < points[maxx<<1][1]; line++) {
for (int pt = 0; pt < (maxx<<1); pt++) {
pointsToPaint[pt] = points[pt][1];
}
for (int skip = 1; skip < (maxx<<1); skip = skip + 2)
pointsToPaint[skip] = pointsToPaint[skip] + line;
myLinePaint.setColor(Color.BLACK);
canvas.drawLines(pointsToPaint, bLinePaint); // draw over old lines w/blk
}
for (int line = 0; line < points[maxx<<1][0]; line++) {
for (int pt = 0; pt < maxx<<1; pt++) {
pointsToPaint[pt] = points[pt][0];
}
for (int skip = 1; skip < maxx<<1; skip = skip + 2)
pointsToPaint[skip] = pointsToPaint[skip] + line;
myLinePaint.setColor(color);
canvas.drawLines(pointsToPaint, myLinePaint); / new color
}
}
update: Replaced the drawLines() with drawPoint() in loop, still no joy
for (int p = 0; p<pointsToPaint.length; p = p + 2) {
Log.i(DEBUG_TAG, "x " + pointsToPaint[p] + " y " + pointsToPaint[p+1]);
canvas.drawPoint(pointsToPaint[p], pointsToPaint[p+1], myLinePaint);
}
/// canvas.drawLines(pointsToPaint, myLinePaint);
I was attempting to write from within onCreate() and onStart(). The View and its Canvas are never actually rendered for the first time until the end of onStart().
aren't you suppose to call invalidate (like a mapview) to force the view to reload?
YourView.invalidate() (or maybe postInvalidate(), depending where you are : main sthread or not)
here is the detail