I'm developing an app for Android, a small notepad app.
In my app I use a Gridview for create a grid of 2*X size and in each cell
I has a LinearLayout call AbstractNote that has in task to show a preview of each save
note in the app.
I what my AbstractNote to has a background image that is some bit rotate for show
the preview more beautifully. But my problems is while i rotate the image some of it falls outside of the AbstractNote Area, and I'not find a good way to show this to.
I has try to use View.setAnimation(...) and it works but give me rugged image and text,
and I has try to crate a custom Drawable (set as AbstractNote.setBackgroundDrawable(...)) that give me smooth image but not show the full image.
Do note, My target android is 2.1 and I not use View.setRotation(...)
Use a View.setAnimation for do this but get rugged image and text
Use custom drawable, but can't paint outside of the cell.
If somebody know how to fix it, by fix the rugged image and text in attempted 1 or
how to draw image outside the cell in attempted 2, I will be very grateful.
I has finally find a solution on the problem, the solution is not very good but work, the idea was to draw the cells item directly draw the background on the GridView and not the GridView childen/item
I Create a new GridView as:
public class NoteGridView extends GridView {
#Override
protected void dispatchDraw(Canvas canvas) {
final int count = getChildCount();
if (count > 0) {
for (int i = 0; i < this.getChildCount(); i++) {
// For each of my childen draw it backgrund that allow to draw bg that is bigger then cell.
View childAt = this.getChildAt(i);
if (childAt instanceof AbstractNote) {
final AbstractNote note = (AbstractNote) childAt;
// Set the zero point to the start of the childen, then call the childen draw methods.
canvas.save();
canvas.translate(childAt.getLeft(), childAt.getTop());
note.drawBackground(canvas);
canvas.restore();
}
}
}
super.dispatchDraw(canvas);
}
}
And in my children AbstractNote I add the method drawBackground, this do that background I what to draw in my AbstractNote is now draw on the GridView canvas that is much bigger then the small canvas I has in AbstractNote
Related
I have a precut image i.e One base image and multiple transparent layer of the the base image.
I am trying to add the layer image on top of base image to select the layer and apply different color on it.
I have tried the following way to achieve it but not able to finish.
ImageView - I am overlapping imageview with transparent layer image. It shows the blended image but the touch event detects the finally overlapped image id always. Because I draw the image with fill parent, all the layer image is also the same
Layer Drawable - It can allow only drawable images, but my use case is to load the precut from gallery or other resource. Even I can't select layer on touch.
GPUImage library - The image is not showing full imageview.
Regards
Sathiya
Extend the View class, make the onDraw() function draw what you want to draw. The onTouchEvent() function implement the touch events. What you're trying to do isn't subsumed in any view already made but it's pretty easy to make a view. Just draw the bitmaps on the canvas in the correct order with the correct paints with the right transparency.
#Override
protected void onDraw(Canvas canvas) {
int numLayers = mLayers.size();
for (int i = 0; i < numLayers; i++) {
canvas.save();
canvas.concat(matrix);
//or
canvas.translate(rect.left,rect.top);
Bitmap b = mLayers.get(i);
canvas.drawBitmap(b, paint);
canvas.restore();
}}
You end up doing this a bunch just adding bitmaps to the canvas in whatever places and order as needed.
In an Android project, I am using FrameLayout to contain a TextView. This TextView has a large shadow on it (to provide a glow). However, Android is detecting the TextView's bounding rect to be just that of the contained text, without the shadow, and as a result the compositor gets confused when objects animate around it.
As a workaround I tried forcing the TextView to have its own hardware surface (with setLayerType), but this too is closely cropped to the text and doesn't account for the shadow, so the shadow gets cut off.
I have tried adding padding to the FrameLayout, but that doesn't expand the surface - it only moves the TextView down and right by the padding amount.
If I set a background color on the FrameLayout, the surface does expand to cover its entire size, but unfortunately this background is visible, even if I set it to 0x01000000. If there were some way to force it to contain the entire background even if the background color is 0, that would be a suitable solution.
What is the easiest way to expand the hardware surface to include the text glow, ideally without affecting the position of the text itself?
The trick is to get Canvas to believe that every pixel has been touched, without actually having anything to paint. Simply drawing a ColorDrawable does not work, because every step along the way seems to detect that a fully-transparent color doesn't need to be rendered. And, apparently the render for the text shadow is also only rendering where the canvas thinks it's been invalidated – so, for example, only drawing a couple of background pixels will expand the surface but still does not cause the actual text shadow to be rendered.
However, there is an operation that will cause Canvas's clipping mask to get updated even with transparent pixels – a transparent Bitmap!
So, adding a background Drawable that renders out a transparent Bitmap has the desired effect. You can add a transparent bitmap as a resource (drawn using a BitmapDrawable), or you can do this:
final Bitmap bmp = Bitmap.createBitmap(2, 2, Bitmap.Config.ALPHA_8);
final Paint bmpPaint = new Paint();
wrappingFrameLayout.setBackground(new Drawable() {
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
public void draw(final Canvas c) {
c.drawBitmap(bmp, null, getBounds(), bmpPaint);
}
public void setAlpha(final int a) {}
public void setColorFilter(final ColorFilter cf) {}
});
Right now, I have it so that my layout consists of a Fragment that takes up the entire screen and displays an image. I want to make it so that an additional View exists on top of it, also taking up the entire screen. On that top layer, I want to be able to color it all black initially, and then create certain spots that are transparent (alpha?) and reveal the image displayed on the fragment behind it. So basically the screen will be all black except for a few spots where the image behind is showing through, which I would determine programmatically. I've looked into a bunch of the graphics and views that Android provides, but have no clue where to start. Is this suited for a SurfaceView if I just want it to be all black with some spots of alpha?
Once I select the correct view to use, I'm assuming that I just override the onDraw() method and then do something like canvas.setBody(black) and then add shapes of alpha to it? Will the shapes correctly affect the background color?
For your masking View, you can make a custom view that can keep track of which areas to unmask (as Rects or something similar) and then draw them in onDraw(Canvas) like this:
public class MaskView extends View {
private Set<Rect> mRects = new HashSet<Rect>();
private Paint mUnmaskPaint = new Paint();
{
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
/**
* Add an unmasking rectangle to this view's background.
*
* #param rect
* a rectangle used to unmask the background
*/
public void addUnmaskRect(Rect rect) {
mRects.add(rect);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
for (Rect r : mRects) {
canvas.drawRect(r, mUnmaskPaint);
}
}
}
Your Fragment (or whatever is keeping track of the unmask areas) passes Rects to MaskView via addUnmaskRect(Rect). Whenever the view is redrawn (remember to call invalidate() each time you are done passing Rects) it is first filled with black, and then has any rectangles unmask the black background. The coordinates for your rectangles must be set to the coordinate space of the view, but if the underlying image occupies the exact same area it should be relatively simple (you can also look at the View.getLocationInWindow(int[]) method to help you with this as well).
I looked at the H&M Android app and trying to figure out how to implement some widget.
Can anyone have an idea how this image frame is implemented?
I can guess that it using openGL.
A transparent png frame? Which could also be nine-patch!
I will venture a guess ;)
First the front image is created. In this case, it is built by inflating a linear layout with an ImageView and a TextView. Then this is cached to a Bitmap (at setup phase, not draw time).
In onDraw, that bitmap is drawn to the screen. Then the canvas is clipped to avoid drawing that area any more. Saves a lot of drawing time to not do a quadruple overdraw of transparent pixels.
Then the backgrounds are drawn like this:
for(int i = NUMBER_OF_LAYERS - 1; i > 0; i--) {
canvas.save();
float rotation = MAX_ANGLE * shiftModifier * ((float) i / (NUMBER_OF_LAYERS - 1));
canvas.rotate(rotation, mImageHalfWidth, mImageHalfHeight);
paint.setAlpha((int) (255f / (2 * i)));
canvas.drawRect(mBitmap.getBounds(), paint);
canvas.restore();
}
NUMBER_OF_LAYERS is the number of backgrounds layers.
MAX_ANGLE is the rotation angle for the most tilted layer.
shiftModifier is used to animate the background layers. It moves from zero (background completely hidden) to one (background angle = MAX_ANGLE).
paint is just a Paint with color set to white.
I have created a custom ImageView and in its onDraw method I need to draw some bitmaps based on user interaction like touch. Everything is working fine however slowly as I start adding more and more bitmap the application really slows down.
This is what I do in my onDraw of the Custom ImageView
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.e(TAG, "onDraw called");
for (int i=0; i < bitmapList.size(); i++){
drawBitmap(canvas, bitmapList.get(i));
}
}
As you can see, I am redrawing all the bitmaps in the List everytime onDraw is called naturally when the number of bitmap exceeds say 4-5 the operation becomes very expensive and slows the application down.
Any solution to this proble as to how can this be optimized?
Can calling drawBitmap in a different thread make the operation less expensive?
Is there a way to keep a copy of the previous canvas and then simply restore it in onDraw rather than drawing all the bitmaps again?
The question essentially is refreshing the View with lots of dynamic images on it and its optimization.
You should create a Bitmap which size must be equal to the ImageView's image size and draw all the bitmaps from the bitmapList on this bitmap only once. On every onDraw() call you should draw only this bitmap. When the bitmapList changes, this additional bitmap must be recreated.
You could use a backbuffer image to draw all your images into whenever they change, and then draw only the backbuffer image to the screen in onDraw()
// create backbuffer and draw it as seldom as possible
final Bitmap bufferBitmap = Bitmap.createBitmap(320, 240, Bitmap.Config.ARGB_8888);
final Canvas bufferCanvas = new Canvas(bufferBitmap);
for (int i=0; i < bitmapList.size(); i++){
drawBitmap(bufferCanvas, bitmapList.get(i));
}
// draw the buffered image as often as needed
canvas.drawBitmap(bufferBitmap ...);