Android: Can I have layers in a live wallpaper? - android

I want to create a live wallpaper, and I want to have the bottom background slide together with swiping homescreen pages, while another layer stays always on top of the background and under the app icons.
Is this possible and how can this be done?

You'll have to override public void onOffsetsChanged (float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset)
Using the value of xOffset, you can define a source rectangle that extracts part of your bitmap and draws that part on the screen.
This image should give you an understanding of how xOffset works:
Assuming that there are 5 homescreen pages,
If your picture is of size 960 x 800 (width x height) and if you want to draw a portion of size 480 x 800 every time, then you can define a source rectangle whose co-ordinates would be:
x1 = xOffset * (960 - 480); y1 = 0; x2 = x1 + 480, y2 = 800;
Then your destination rectangle would be the portion of the screen you want to draw onto.
You can then use public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint) method to draw the bitmap onto the screen.
I had used this technique a long time ago. I didn't check this in code before posting, and there may be alternatives (like using canvas.translate()). But hopefully this should help you get started. :)

Related

How to draw a circle on top of an image

My application takes an image from the camera, saves it and then displays it on an ImageView, but the next step is to place a circle on top of the displayed image when the user touches the screen, and then save the "modified image".
Kinda like a image editor if you wish, problem is I do not know where to begin with the image editing. I tried this
#Override
public boolean onTouch(View v, MotionEvent event) {
circleView.setVisibility(View.VISIBLE);
circleView.setX(event.getX()-125);
circleView.setY(event.getY()-125);
try{
Bitmap bitmap = Bitmap.createBitmap(relativeLayout.getWidth(),relativeLayout.getHeight(),Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
v.draw(canvas);
mImageView.setImageBitmap(bitmap);
FileOutputStream output = new FileOutputStream(Environment.getExternalStorageDirectory());
bitmap.compress(Bitmap.CompressFormat.PNG,100,output);
output.close();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
return true;
}//ENDOF onTouch
What can I do to save the image?
It'd be helpful if you included a bit more information about what libraries and language you're using. From the #override I'll assume this is java on android?
As for how to create a circle - there are many techniques you could use and there are probably more than a few libraries that you can use to do this. However, we can keep it pretty simple by using functions on the Bitmap object's interface, namely getPixels and setPixels.
What you need to do is grab a rectangle of pixels in to pre-allocated buffer (using getPixels), then draw your circle in to this buffer and then write the buffer back using 'setPixels'.
Here's a simple (although not exactly efficient) method for drawing a circle in the buffer you'd get from 'getPixels' in javaish pseudocode (untested):
//Return the distance between the point 'x1, y1' and 'x2, y2'
float distance(float x1, float y1, float x2, float y2)
{
float dx = x2 - x1;
float dy = y2 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
//draw a circle in the buffer of pixels contained in 'int [] pixels'
//at position 'cx, cy' with the given radius and colour.
void drawCircle(int [] pixels, int stride, int height, float cx, float cy, float radius, int colour)
{
for (int y = 0; y < height; ++y)
for (int x = 0; x < stride; ++x)
{
if (distance((float)x, (float)y, cx, cy) < radius)
pixels[x + y * stride] = colour;
}
}
This just asks the question, for each pixel, 'is the point 'x,y' inside the circle given by 'cx, cy, radius'?' and if it is, it draw a pixel.
More efficient approaches might include a scanline rasteriser that steps through the left and right sides of the circle, removing the need to do a costly 'distance' calculation for each pixel.
However, this 'implicit surface' approach is quite flexible and you can achieve a lot of effects with it. Other options might be to copy a pre made circle bitmap instead of creating your own on the fly.
You could also blend the 'colour' based on the fractional value of 'distance - radius' to achieve anti-aliasing.

Android Rotating Rectangle and understanding the Canvas

I'm looking at making something that looks like the following:
Which is basically a rectangle shape on the top left thats been rotated, and then two underneath it, tiled like it is.
I've had a go at doing it but just can't get it done, basically I use:
int x = getWidth();
int y = getHeight();
canvas.save();
canvas.rotate(-45);
canvas.drawRect(x/2, y/2, x/2+100, y/2+40, paint);
canvas.restore();
And I've noticed that what should be a rectangle rotated near the centre of the screen is instead one that is to the top right of the screen. When I try doing something similar to (0,0, 100,100) I don't get any rectangle at all.
I guess I'm confused whether the coordinate system changes when the rotation of the canvas is done, and what would be the easiest way in looking into getting the image above on android (besides just creating it in photoshop and adding the png).
The single argument rotate(angle) will use 0,0 as the pivot point.
If you want to rotate about your object, you should calculate some point on it to rotate about and use the 3 argument rotate(angle, pivotX, pivotY), ie:
int x = getWidth();
int y = getHeight();
canvas.save();
canvas.rotate(-45, x / 2, y / 2);
canvas.drawRect(x / 2, y / 2, x / 2 + 100, y / 2 + 40, paint);
canvas.restore();
I made your design just for fun:
int x = getWidth();
canvas.rotate(-45);
canvas.drawRect(-x, 0, x, h, green);
canvas.drawRect(-x, h, 0, 2 * h, purple);
canvas.drawRect(0, h, x, 2 * h, blue);
Where h is the height of the rectangle.

Android Open GL ES texture problems

I am having a problem that I think is possibly to do with texture coordinates, the image below shows my tile map being rendered - however sometimes there are gaps appearing between the tiles as can be seen in the screenshot at the following url (Half way down the screen there is a gap between tiles).
http://img15.imageshack.us/img15/4724/tileproblem.png
My texture regions are declared as
public class TextureRegion {
public final float u1, v1;
public final float u2, v2;
public final Texture texture;
public TextureRegion(Texture texture, float x, float y, float width, float height) {
this.u1 = x / texture.width;
this.v1 = y / texture.height;
this.u2 = this.u1 + width / texture.width;
this.v2 = this.v1 + height / texture.height;
this.texture = texture;
}
}
The tile textures come from an atlas and are 32x32 pixels, I am using GL_Nearest
being new to Open GL, I do not quite understand what I need to change.
Example of texture creation
tile = new TextureRegion(items, 192,160,34,34);
Cheers
Stuart
Make sure your texture are base 2, for example 128x256 or 512x512 etc.

Define touchable area on a scaled image in android

I have asked questions related to this before, but I think I was framing my objective incorrectly.
What I have: a custom ImageView that displays a graphic and defines multiple touchable areas as rectangles within the image. My problem is scaling. I want to define the touchable area of the image based on it's actual resolution in the bitmap file, but translate those coordinates so the the rectangle covers the same area on the scaled image.
This is what I've got so far:
When the view is created, calculate the ratio of the actual to scaled sizes
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
Drawable pic=this.getDrawable();
int realHeight= pic.getIntrinsicHeight();
int realWidth=pic.getIntrinsicWidth();
int scaledHeight=this.getHeight();
int scaleWidth=this.getWidth();
heightRatio=(float)realHeight/scaledHeight;
widthRatio=(float)realWidth/scaleWidth;
}
Now I want to take the coordinates that define rectangle(s) on the original (un-scaled) image
and draw that rectangle(s) to the same area of the image -- but accounting for scale:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint p=new Paint();
p.setStrokeWidth(1);
p.setColor(Color.BLUE);
for (HotSpot h: spots)
{
//Each hotspot has a rectangle defined in reference to the actual size of the image
Rect old=h.getRect();
float offsetLeft=old.left+(old.left*widthRatio);
float offsetTop=old.top+(old.top*heightRatio);
float offsetRight=old.right+(old.right*heightRatio);
float offsetBottom=old.bottom+(old.bottom*widthRatio);
RectF nRect=new RectF(offsetLeft,offsetTop,offsetRight,offsetBottom);
canvas.drawRect(nRect,p);
}
The results are "in the ball park" but not quite accurate. Any help is appreciated.
You can try this solution:
Get the screen density
Get the image height (or width)
Divide the height (or width) by the density, so you get the length in inches
Divide the coordinate by the length in inches, so you get a relationship between the coordinate and the image which is independent by the image effective size
When you have to draw the same point on a differently scaled image, multiply the last result for the length in inches of the second image (which you obtain using the same operations listed above)
Example:
On the first image:
float density = getResources().getDisplayMetrics().density;
int width = getWidth();
float inchesLength = width/density;
float scaledXCenter = xCenter / inchesLength;
On the same image with a different scale:
float density = getResources().getDisplayMetrics().density;
int width = getWidth();
float inchesLength = width/density;
float restoredXCenter = scaledXCenter * inchesLength;

Compass with bitmap is going everywhere in the screen

i want my compass to spin like this
but my result is that:
the compass is going everywhere in my screen...
where is my problem please?this is my compass.java code:
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GRAY);
int w = canvas.getWidth();
int h = canvas.getHeight();
int cw = w / 2;
int ch = h / 2;
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.compass);
canvas.translate(cw, ch);
if (mValues != null) {
canvas.rotate(-mValues[0]);
}
int cx = (mWidth - myBitmap.getWidth()) / 2;
int cy = (mHeight - myBitmap.getHeight()) / 2;
canvas.drawBitmap(myBitmap, cx, cy, null);
}
p.s.: i m sorry for the bad pictures but i really dont know how to explain my problem in english!Thanks
Since you have already translated to the center of the canvas, you may only need to offset the compass with its half width/height to center it. Try:
int cx = -myBitmap.getWidth() / 2;
int cy = -myBitmap.getHeight() / 2;
canvas.drawBitmap(myBitmap, cx, cy, null);
Also to get a good hang of transformations (translate, rotate), read The OpenGL Red book chapter 3, specifically the part Thinking about Transformations. While this is about OpenGL, you can use the knowledge for non-OpenGL transforms too.
EDIT:
Think in turtle logic. Your first translation takes your pencil to the center of your canvas. The rotation rotates your pencil. So now you could draw the compass exactly where the pencil is (no offsets), except that drawing the compass image is done starting from its top-left corner instead of its center. Therefore you need a last translation of (-compassWidth/2, -compassHeight/2). Note that this translation already occurs on the rotated x & y axes. Also note that you may pass 0/0 for cx/cy in drawBitmap if you manually apply that translation to the canvas itself.
So the full sequence is: translate to canvas center, rotate, translate negated to image center.
Don't decode the Bitmap in onDraw - do it when the view is created and reuse the Bitmap.
Make a Matrix and matrix.postRotate(mValues[0], half_width_of_bitmap, half_height_of_bitmap); and matrix.postTranslate(cw, ch);
Draw the bitmap with canvas.drawBitmap(bitmap, matrix, null);

Categories

Resources