Android drawCircle compatibility problems - android

I've got custom widget - blinking circle in custom frequency. In my onDraw method i paint a circle.
#Override
protected void onDraw(Canvas c) {
super.onDraw(c);
if (data[mBitIndex] == '1'){
c.drawCircle(c.getWidth() / 2, c.getHeight() / 2, c.getWidth() / 2, mPaint);
}
}
This works perfect on android 4.2.1, but if i try this on android 2.3, no circle shown. I've done some experiments to determine the problem
#Override
protected void onDraw(Canvas c) {
super.onDraw(c);
if (data[mBitIndex] == '1'){
c.drawColor(mPaint.getColor());
}
}
This works as i expected on both versions of android. But, it's a square, not circle, which i want.
How is it even possible to draw square, but not circle? I've searching on the internet, but noone has this problem before or it's only my problem. I don't get this, can anyone explain me where could be mistake?

On Honeycomb (API 13) or earlier, the hardware acceleration is buggy and cannot draw your circle.
Disable hardware acceleration for your view:
setLayerType(View.LAYER_TYPE_SOFTWARE,null);
This worked for me.
Or set targetSDKVersion to 14 or higher (which might cause other issues).

Related

Trying to draw on canvas using canvas.clipPath

I am trying to draw circle on darken background, trying to achive smth like this -
This actually worked on my Samsung s4 and Samsung tab 3, but won't work on s2 and some emulator (all sorrounding viewgroup is darken, and inside oval too, seems like it does not see my circleSelectionPath). Help me please to find the way to make it work on every device
final Paint paint = new Paint();
paint.setColor(Color.parseColor("#77000000"));
Path circleSelectionPath = new Path();
mRectF.set(l, t, r, b);
circleSelectionPath.addOval(mRectF, Path.Direction.CW);
canvas.clipPath(circleSelectionPath, Region.Op.XOR);
canvas.drawRect(bitmapRect.left, bitmapRect.top, bitmapRect.right, bitmapRect.bottom, paint );
canvas.restore();
bitmapRect contains my viewgroup dimens (for example : 0,0, 500,500)
Got it. Android has a bug with canvas.clipRect, they have optimized it, but on some android apis it simple don't work after optimization ) I found an issue.
So fix - disable hrdware acceleration for this view
(Build.VERSION.SDK_INT <= 19 && mCropShape == CropImageView.CropShape.OVAL) {
//TURN off hardware acceleration
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

Android Canvas drawText not working

I made a custom view using canvas's drawText method. Somehow none of the text is showing on any of the Jelly Bean devices. It works fine for ICS and below.
Does anyone know if anything has changed from API 15 to 16 for this method or any related methods?
Edit Code: (from the draw method where canvas is supplied as a parameter)
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(3);
paint.setColor(context.getResources().getColor(R.color.plot_background));
canvas.drawRect(new Rect(0,0,getWidth(),getHeight()), paint);
paint.setColor(color_text);
paint.setTextSize(getScaled(18.5f));
paint.setTextAlign(Align.CENTER);
canvas.drawText(title, (graphwidth / 2) + horstart, border/2+15, paint);
I know the line is been executed and the coordinates are correct because the same code works on the older platforms.
Thanks Eric. Figured out the error. I scale everything in the app base on canvas.getDensity(). getDensity() at the moment the draw function is ALWAYS 0 for jelly bean devices for some reason. But it does return the correct value for anything between 1.6 -> 4.0.3
I didn't post the code for that (which is my fault) is because I didn't suspect getDensity() to be the problem since it never did in the last two years while the app is in the market.
The workaround was to modify the getScaled function.
public float getScaled(Canvas canvas,float in){
return in * ( canvas.getDensity()==0 ? 1 : canvas.getDensity()/ 160.0f);
}
The documentation does say that DENSITY_NONE could be returned but I think what might have happened is that in Jelly Bean does the scaling for you since if I just multiply it by 1, it works as a charm on the two different density device that I just tested on.
(P.S. Can anyone familiar the internals of Android OS correct me if I am wrong or confirm it? )

Set transparent color in android webview

How to set transparent color in android webview?
<div style="background-color: black" >test</div>
How can I make black color to be transparent for the whole page (like chromakey)?
Had the same problem with the WebView, as it behaved randomly across different OS versions. Finnlay I fixed it with this code this after the loadDataWithBaseURL() call:
if (Build.VERSION.SDK_INT >= 11) {
webView.setBackgroundColor(0x01000000);
} else {
webView.setBackgroundColor(0x00000000);
}
I figure this will give the device something to draw, so various caching mechanisms will not kick in. But the result is practically the same as with total transparency, as it is undetectable by average human eye.
No performance penalties noticed as well.
Tested on several devices ranging from 2.2 to 4.2.
Cheers
try this
(YourWebview).setBackgroundColor(0x00000000);
I've found the solution. I've reimplemented OnDraw method of WebView
#Override
protected void onDraw(android.graphics.Canvas canvas) {
super.onDraw(canvas);
Paint p = new Paint();
p.setARGB(255, 0, 0, 0);
int removeColor = p.getColor();
p.setAlpha(1); // if Alpha is 0 it doesn't work. I don't know why
p.setXfermode(new AvoidXfermode(removeColor, 0, AvoidXfermode.Mode.TARGET));
canvas.drawPaint(p);
}
you can use this
webView.setBackgroundColor(0);

Canvas not displaying all drawn parts in Custom View?

I'm working on a custom view for an android application, similar to the Analog Gauge sample code available from Mind the Robot.
Running the code from listed site, I get see this on my screen:
(Motorola Droid, 2.2.3), (Emulator, 4.0.3)
(Xoom, 4.0.3)(Other phone, 4.0.3)
The hand is missing!
The drawing calls are being made (I can see them in logcat), but the canvas elements the calls draw are invisible.
It's not API level dependent, though; if I import it the right way into a project, it will hand will show up when I run it on the Xoom.
But, when I move the files to a different project folder (same source code, same layouts) it goes back to missing the dial.
What's going on? How could the same code be producing such different outcomes on different devices?
So, the key clue in my mystery seemed to be that it worked on the emulator, but not on the hardware devices.
Hardware Rendering
I did peruse the hardware rendering page on the Android Developer's website, but apparently not closely enough.
http://developer.android.com/guide/topics/graphics/hardware-accel.html
While it does mention that the API's are available beginning version 11, it does not say that Hardware Rendering is turned on for all applications by default, starting with API Level 14 (ICS).
What does this mean for us?
Almost everything is faster; except for the few things that don't work.
I managed to violate two of these, without realizing it:
Canvas.DrawTextOnPath()
Paint.setShadowLayer()
It's not mentioned in the API reference (or anywhere else I can find, and certainly not checked by Lint), but using any of the listed operations can do weird things.
In my case, Canvas.DrawTextOnPath() seemed to work just fine.
But when Android notice that the paint that I used on the hand had shadow layer set, it silently ignored it.
How do I know if my View is hardware accelerated?
From the documentation link above:
There are two different ways to check whether the application is hardware accelerated:
View.isHardwareAccelerated() returns true if the View is attached to a hardware accelerated window.
Canvas.isHardwareAccelerated() returns true if the Canvas is hardware accelerated
If you must do this check in your drawing code, use Canvas.isHardwareAccelerated() instead >of View.isHardwareAccelerated() when possible. When a view is attached to a hardware >accelerated window, it can still be drawn using a non-hardware accelerated Canvas. This >happens, for instance, when drawing a view into a bitmap for caching purposes.
In my case, the opposite appears to have occurred.
The custom view logs that it is not Hardware-accelerated; however, the canvas reports that it is hardware-accelerated.
Work Arounds and Fixings
The simplest fix is forcing the custom view to do software rendering. Per the documentation this can be accomplished by:
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Alternatively, you could remove the offending operations, and keep hardware rendering turned on.
Learn from my misfortune. Good luck, all.
I put it into init() and worked fine after that.
private void init() {
setLayerType(myView.LAYER_TYPE_SOFTWARE, null);
....
}
With myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); suggestion I can see hand. But I have still a problem: I see scale with only 0 written! As in the picture and two strage zeros out of the schema: (GALAXY NEXUS 4.2.1)
My drawScale() method is as in the example:
private void drawScale(Canvas canvas) {
canvas.drawOval(scaleRect, scalePaint);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
for (int i = 0; i < totalNicks; ++i) {
float y1 = scaleRect.top;
float y2 = y1 - 0.020f;
canvas.drawLine(0.5f, y1, 0.5f, y2, scalePaint);
if ((i % 5) == 0) {
int value = nickToDegree(i);
if ((value >= minDegrees) && (value <= maxDegrees)) {
String valueString = Integer.toString(value);
canvas.drawText(valueString, 0.5f, y2 - 0.015f, scalePaint);
}
}
canvas.rotate(degreesPerNick, 0.5f, 0.5f);
}
canvas.restore();
}
in my case i made this:
AnalogView bar = (AnalogView) findViewById(R.id.AnalogBar);
bar.setLayerType(bar.LAYER_TYPE_SOFTWARE, null);
if (value_list.size()>0) bar.SetData(Double.parseDouble(value_list.get(value_list.size()-1)));
where SetData in AnalogView is
public void SetData(double data) {
setHandTarget((float)data);
invalidate();
}
On Galaxy S4 Android 4.4.2
TYPE_TEMPERATURE is deprecated
use
TYPE_AMBIENT_TEMPERATURE
For anyone having problems with text drawing on scale in the initialisation do this:
scalePaint.setLinearText(true);

Canvas.drawCircle() with large circles under hardware acceleration

In the course of developing an Android application, I'm finding a need to draw
several unfilled concentric circles centered on an arbitrary point, enough that
some of them are only partly visible on the display. However, this does not
appear to work with hardware acceleration. My test rig is a stock Samsung Galaxy
Tab 10.1 running Android 3.2.
The following code comes from a test subclass of View I wrote to isolate the
issue:
private Paint paint = new Paint();
private int count = 0;
private static final int[] COLORS = { 0xffff0000, 0xff00ff00, 0xff0000ff, 0xffff00ff };
public TestCircles(Context context) {
super(context);
paint.setStrokeWidth(1.0f);
paint.setStyle(Paint.Style.STROKE);
}
public TestCircles(Context context, AttributeSet attributes) {
super(context, attributes);
paint.setStrokeWidth(1.0f);
paint.setStyle(Paint.Style.STROKE);
}
public boolean onTouchEvent(MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_DOWN)
invalidate();
return true;
}
protected void onDraw(Canvas canvas) {
// Pick the color to use, cycling through the colors list repeatedly, so that we can
// see the different redraws.
paint.setColor(COLORS[count++]);
count %= COLORS.length;
// Set up the parameters for the circles; they will be centered at the center of the
// canvas and have a maximum radius equal to the distance between a canvas corner
// point and its center.
final float x = canvas.getWidth() / 2f;
final float y = canvas.getHeight() / 2f;
final float maxRadius = (float) Math.sqrt((x * x) + (y * y));
// Paint the rings until the rings are too large to see.
for (float radius = 20; radius < maxRadius;
radius += 20)
canvas.drawCircle(x, y, radius, paint);
}
I am running TestCircles as the only View in an Activity, laying it out to fill
the available width and height (i.e. it is nearly full-screen). I can tap on
the display (triggering redraws) only a few times before the redraws no longer
occur (i.e. the circles' color doesn't change). Actually, the onDraw() code is
still running in response to each tap -- as proven with diagnostic messages --
but nothing changes onscreen.
When onDraw() first starts to fail to redraw, the debug log includes the
following entry, once for every call to onDraw():
E/OpenGLRenderer(21867): OpenGLRenderer is out of memory!
If I turn off hardware acceleration in the manifest, these problems go away --
not surprising since clearly OpenGL is having problems -- and actually it is
a good deal faster than the few times it actually works under hardware
acceleration.
My questions are:
Am I misusing Canvas, or is this a bug, or both? Is Android allocating large
bitmaps under the hood to draw these circles? It doesn't seem like this should be
this challenging to OpenGL, but I'm new to hardware accelerated app development.
What's a good alternative way to draw large unfilled circles that have portions
extending out of the clipping region of the Canvas? Losing hardware acceleration
is not an option.
Thanks in advance...
I've since learned from others that the problem I described here is the result of a bug in Android 3.2. The workaround for now is of course to use a software layer instead of hardware acceleration. Apparently this problem is fixed in Android 4.0 (Ice Cream Sandwich).

Categories

Resources