I've been trying to solve my problem for a long time now. However, I'm at a loss. The problem is this:
I have a Custom Android View that I render 10 rectangles on(kind of
like a bar chart all the same length, different color)
When updating one of the rectangles with different opacity, it
doesn't change. So I clear the Canvas. But this causes a flicker,
not all the time, but sometimes
What I've tried doing:
Render everything to an offscreen bitmap, then blting it, this still
doesn't solve my issue
Use a SurfaceView and render in another thread
A combination of 1 and 2
In the end, I think the problem is that the background gets erased, but I don't want it to erase. However, I can never get the new "pixels" to show up. I also tried experimenting with different transfer modes like SRC, SRC_ATOP, when I tried number 1, it helps, but does not get rid of the problem.
Does anyone have any guidance on what could be going wrong? Or any other possible solutions?
I have finally figured it out. I don't have to clear the back ground, just temporarily change the paint mode to SRC.
context.paint.setStyle(Paint.Style.FILL);
context.paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
context.canvas.drawPath(context.path, context.paint);
context.paint.setXfermode(null);
Related
I've been fiddling around with RenderBlur on an image for my login screen, i've gotten everything to work with a runnable() and a delay to blur the image immediately, however i'm trying to make it a slow blur while the username and password fields come into view.
I've had a bit of a look around (could be looking in the wrong places) but I haven't found anything related to what i'm after. I've attempted to use a while loop and have a blurradius value increment with a delay afterwards and send to the blurBitmap class method, but it either still blurs it immediately (meaning I probably messed something up somewhere and will most likely keep trying with this method until a better solution is found).. or it crashes.
Does anyone know if, in the first place this is possible with RenderScript? And if so, what should I be searching for.
Thanks for any help you can provide.
Resources: https://futurestud.io/blog/how-to-use-the-renderscript-support-library-with-gradle-based-android-projects
You can do this with RenderScript, though how you are doing it now doesn't sound like a good idea. Look into using a custom Animator which you can then run a RS blur against the image. Using Animator will be more flexible in the long run and automatically ties in with the view system rather than requiring you to handle View or Activity state explicitly.
The approach #JasonWihardja outlined will also work, but again I would suggest doing this in an Animator or similar mechanism.
Blurring an image repeatedly might cause some performance issues with your app.
Here's what you could do:
Arrange 2 images (1 for the clear image and the other for the
maximum blur version) so that the blur image is placed exactly on
top of the clear image. The easiest way would be placing 2 ImageViews in a FrameLayout
To achieve the "slow" blur effect, initially set the blur image's alpha to 0.
Then, using one of the view, issue a postDelayed event to slowly increase the blur image's alpha to 255.
Hej guys, so this is the first time in about 7 years that I have not been able to find an answer to a programming issue, nor have I gotten close to what the issue might be in the first place.
Alright so let's begin from the start. I've followed some tutorials and examples on the Android SurfaceView and how to draw on its Canvas in another thread. So far, no issues, everything draws like I expect. I'm currently working on a scenario where I have some padding around my SurfaceView, which means that the background of the parent view (a FrameLayout) renders around the aforementioned SurfaceView. This is where things become interesting as I use the same color for the parent background as I do for clearing the SurfaceView's Canvas.
The root (=parent) FrameLayout has its background set in the theme like
<item name="android:windowBackground">#color/palette_primary_dark</item>
which is defined in colors.xml like
<color name="palette_primary_dark">#28252C</color>
and in my thread constructor, I retrieve the same color into the global variable mClearColor like
mClearColor = ContextCompat.getColor(context, R.color.palette_primary_dark);
where the context is the Context I receive from my SurfaceView.
The following code is the render loop that runs in my thread
#Override
public void run() {
while (mShouldRun) {
Canvas canvas = null;
try {
canvas = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
if (canvas != null) {
canvas.drawColor(mClearColor);
onDrawFrame(canvas);
}
}
} finally {
if (canvas != null) {
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
So far, so good. No errors and everything draws; the background isn't black and it looks like the color I want. But here's the catch, it ISN'T actually the color I want. It's off by a hair. The color I defined in my XML is #28252C but according to my GIMP color picker tool it actually draws #292429. Weird.
Then I started searching further and discovered that the color I'm using to draw touch indicators (where my fingers are located on the screen) should be #FF1744 but actually is #FF1442.
This left me scratching my head and desperately trying other ways of drawing the right color on my canvas. I've tried Canvas.drawColor(), Canvas.drawARGB() and Canvas.drawRGB(), but to no avail. In drawColor() I even tried different ways of retrieving my color, like mClearColor, Color.parseColor("#28252C"), Color.argb(255, 40, 37, 44) and so on. Nothing worked.
Then I came across the fact that drawColor() uses PorterDuff.Mode.SRC_OVER by default, so I tried using PorterDuff.Mode.SRC to get the pure color I'm feeding it, but no happy faces :(
Then I just started trying stuff but nothing seemed to work. When I tried setLayerType() in my SurfaceView, something did change though. The following screenshot shows how it looked like with the default LAYER_TYPE_NONE value
LAYER_TYPE_NONE
Now when I change this to either LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE the same layout looks like follows
LAYER_TYPE_SOFTWARE/HARDWARE
The weird thing is now that it actually is the correct color and renders how I want it to, it still doesn't draw the lines and info about the touch. Calls to my onTouchListener are still being made, which in its turn should provide data to draw the lines on the screen. The latter doesn't work though, it doesn't actually draw the lines. I have no clue what causes this weird issue that changes my colors... Any help would be greatly appreciated :)
Edit #1:
I have done some more research today and as per this answer by Romain Guy and the following self-answered question by Adrian Lopez, setLayerType() actually does more harm than it solves problems. So I now have even less pointers as to what could cause or solve my issue :/ I'll make sure to edit the question when I have found more information and answer it if I found a solution :)
The SurfaceView's surface is configured to use RGB 565 by default.
In onCreate(), set the color format of the surface with setFormat() to get RGB 8888 instead:
mSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT);
I know this is quite the same question as partial-invalidation-in-custom-android-view-with-hardware-acceleration but I thought I will explain my problem more detailled and hope someone will have an answer on how to solve the problem.
I wrote a simple TicTacToe app which was working fine on the emulator. But wasn't working on the device since I found out it was working as expected on the device when I disabled hardware acceleration.
All the fields are drawn with Canvas.drawBitmap(), also the "empty" fields with an empty white image. The lines are drawn with Canvas.drawLine()
I'm using partial invalidation with invalidate(Rect) because I want to redraw only the area which was choosen to set a cross/circle with the according image using again Canvas.drawBitmap(). But then the whole area is invalidated, means I see the whole area/screen is gray (the white images and lines disappeared) and only the image for the cross/circle is set in the choosen area.
When I print out the invalidated field rect with Canvas.getClipBounds() in the method onDraw(), with hardware acceleration it is the whole area (example "0,0,320,407") and without hardware acceleration the same rect which I invalidated with invalidate(Rect) (e.g. "106,135,106,135").
At the moment as workaround I redraw all the fields whith the according image and lines. How can I prevent to have the whole area invalidated with hardware acceleration?
If this matters: I'm using Android version 4.1.2 on Samsung Galaxy Young Duos S6312.
Regards
Sandro
I have post my answer in your given link. To understand the problem , you should know the difference between software rendering and hardware rendering. That's really a big topic which I won't cover here. I think the best approach is to read the source code(I did the same thing a few days ago). The key question is "what is DisplayList and when it is used"
. Repeat my answer here, the Canvas in onDraw is simply used to rebuild the DisplayList. That doesn't mean everything in your View will be redrawn.
I have a GLSurfaceView with a renderer assigned to it. On this view, I draw images which seem to be offset to the left compared to where I have requested that they be drawn on it. This problem has only arisen since I switched from Canvas-based rendering, which rendered the images in their correct positions, to OpenGL 1.0 rendering, which doesn't.
I have read through my code and have found absolutely nothing that could be causing this. What frustrates me is that I know there is nothing wrong with the positions I set using my code, but the problem still persists.
Now, here's the best part of it all. When I pause the application by pressing the home button, and then restart the application through the task manager, the positions are fixed and are exactly how they should be, which leads me to believe that the problem isn't with the positions I set using my code, but how I've set up my surface view. I've checked the dimensions in the onSurfaceChanged() parameters only to find that they are always as they should be, which leaves me even more confused.
Does anyone have any idea what could be causing this problem?
After much digging through my project, I discovered I was setting positions based on the dimensions of the GLSurfaceView before onSurfaceChanged had been called in the onSurfaceCreated method, therefore the width/height of the view at this point was 0 which affected the positions of my objects on the screen.
I feel really stupid now.
What is the best way to draw circles on a canvas that should have an alpha layer and change sizes? Should I use a View or a Surfaceview? The circles should also be clickable. And it should be smooth transitions when changing color size and position?
Should I put this in a runnable or use invlaidate in onDraw?
I would prefer that something like this also worked smoothly in low-end devices.
Any suggestions? I'm new to this kind of animations in Android.
If you are constantly drawing and taking user input at the same time, I would use a SurfaceView. However, if the only draw changes you plan on making to the circles happen when you touch them, then a simple View onDraw() override would probably do the trick. In the end it will just depend on what all is going on.
The point of the SurfaceView is to have that separate thread for drawing. If what you're doing could be in any way considered "game-like," then go for a SurfaceView; otherwise, stick with a View.
I say this because I'm currently working on a project with constant drawing using a View. The shapes that I'm drawing respond to touch and you can scroll through the View while it is still invalidating over and over. All this with a View and it still runs just fine on lower-end devices (I've only gone back to GingerBread, though).
Good luck!
I should also mention that in the project drawing in a View, almost everything has various alpha values and what not and runs fine.