I want to have three separate rectangles that would fill up with gradient. Depending on the value X the gradient would be placed differently. For example if value X = 75 the gradient would be 75% green and 25% red. I wanted to know if there is any library or a method that would allow me to do this in java (android studio).
To implement this, you could use LinearGradient for the gradient and then create a custom view with methods allowing you to change the layout of the gradient.
public class GradientView extends View {
Paint paint;
LinearGradient gradient;
int[] colors = [Color.RED, Color.GREEN];
public GradientView(Context context, int gradientHeight) {
super(context);
paint = new Paint();
setGradientHeight(gradientHeight);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
paint.setShader(colorGradient);
canvas.drawPaint(paint);
}
public void setGradientHeight(int height){
colorGradient = new LinearGradient(0, 0, 0, height * 0.01 * super.getHeight(), colors, null, Shader.TileMode.MIRROR);
paint.setShader(colorGradient);
invalidate();
}
}
Haven't tested the code, but it should certainly work something like this.
Related
I made a custom View Class that draws the waveform of an audio file, unfortunately, I'm having some problems with changing the background color of the canvas/custom view to transparent.
I can change the background color inside the onDraw function canvas.drawColor(Color.WHATEVER);
However, this works with any color but transparent, which shows black instead.
This works: canvas.drawColor(Color.BLUE);
This doesn't: canvas.drawColor(Color.TRANSPARENT);
Also, if I use the Android Studio Layout inspector, it seems to actually work, but in reality it does not. See the screenshot here:
Layout Inspector vs Android Emulator Screenshot
public class SimpleWaveform extends View {
Context context;
public Paint beforePlaySectionPencil = new Paint();
public Paint playSectionPencil = new Paint();
public Paint afterPlaySectionPencil = new Paint();
public Paint peakPencilBefore = new Paint();
public Paint peakPencilPlay = new Paint();
public Paint peakPencilAfter = new Paint();
public Paint xAxisPencil = new Paint();
public void init() {
beforePlaySectionPencil.setStrokeWidth(10);//set bar width (ERA /2)
beforePlaySectionPencil.setColor(ContextCompat.getColor(getContext(), R.color.aaDarkBlue));
playSectionPencil.setStrokeWidth(10); // (ERA /2)
playSectionPencil.setColor(ContextCompat.getColor(getContext(), R.color.aaLightBlue));
afterPlaySectionPencil.setStrokeWidth(10); // (ERA /2)
afterPlaySectionPencil.setColor(ContextCompat.getColor(getContext(), R.color.aaDarkBlue));
peakPencilBefore.setStrokeWidth(barGap / 8);//set peak outline width (ERA /6)
peakPencilBefore.setColor(0xfffe2f3f);
peakPencilPlay.setStrokeWidth(barGap / 8); //(ERA /6)
peakPencilPlay.setColor(0xfffe2f3f);
peakPencilAfter.setStrokeWidth(barGap / 8); //(ERA /6)
peakPencilAfter.setColor(0xfffe2f3f);
xAxisPencil.setStrokeWidth(1);
xAxisPencil.setColor(0x88ffffff);
#Override
protected void onDraw(Canvas canvas) {
if (clearScreenListener != null) {
clearScreenListener.clearScreen(canvas);
} else {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
}
if (clearScreen) {
clearScreen = false;
return;
}
drawWaveList(canvas);
canvas.drawColor(Color.TRANSPARENT);
}
private void drawWaveList(Canvas canvas) {
if (showBar) {
canvas.drawLines(barPoints, 0, playSectionLeftOffset * barUnitSize, beforePlaySectionPencil);
canvas.drawLines(barPoints, playSectionLeftOffset * barUnitSize, (playSectionRightOffset - playSectionLeftOffset) * barUnitSize, playSectionPencil);
canvas.drawLines(barPoints, playSectionRightOffset * barUnitSize, (barNum - playSectionRightOffset) * barUnitSize, afterPlaySectionPencil);
}
if(showXAxis){
canvas.drawLines(xAxisPoints, xAxisPencil);
}
}
}
I did a bit of research and found out how to achieve that in a canvas.
Take a look at this explanation.
Hi guys I recently started developing an android game, but i have encountered an issue with drawRectangle.
public void draw(Canvas canvas) {
super.draw(canvas);
canvas.drawColor(Color.BLACK);
canvas.drawRect(new Rect(100,100,100,100), new Paint(Color.WHITE));
}
this Doesnt seem to work, but i have already drew on screen using another class with a draw method using the same logic but im curious why this doesnt work
private Paint myPaint = new Paint();
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
canvas.drawColor(Color.BLACK);
myPaint.setColor(Color.WHITE);
canvas.drawRect(new Rect(100,100,100,100), myPaint);
}
this doesnt work either
There are three issues in your implementation:-
Paint object doesn't take color in constructor, it takes a flag.
So you could have done something like Paint p = new Paint(Paint.ANTI_ALIAS_FLAG) and then set the color as p.setColor(Color.WHITE).
The Rect object should be something like new Rect(0,0,100,100).
In your case [new Rect(100,100,100,100)] the rectangle will be drawn as a rectangle with 0 width,
0 height and its upper left coordinate will be (100,100) and its
bottom right coordinate will be (100,100).
NEVER create objects in onDraw.
Paint's constructor doesn't take a color. It takes integer flags. So you just made a really weird paint object with every flag set, but you didn't set the color.
See: https://developer.android.com/reference/android/graphics/Paint.html#Paint(int)
This worked
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
canvas.drawColor(Color.BLACK);
myPaint.setColor(Color.WHITE);
canvas.drawRect(testRect, myPaint);
}
Where
private Rect testRect = new Rect(0,0,100,100}
private Paint myPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
I need to create a view that is filled with a dynamic color at runtime. I've accomplished this task however the actual view needs to have a "peak" on the right side. Typically ImageView's are only square or rectangular. Does anyone know how I would accomplish adding a triangular peak to the view?
For example:
You can override the onDraw event of the ImageView and do whatever you need with the canvas object.
public class MyImageView extends ImageView {
...
#Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
Point[] point = ... //create three points here for the triangle
Paint paint = ... // create your desired color
drawTriangle(canvas, point, paint);
}
And for the triagle draw (see this SO answer):
private void drawTriangle(Canvas canvas, Point[] point, Paint paint) {
float [] points = new float[8];
points[0] = point[0].x;
points[1] = point[0].y;
points[2] = point[1].x;
points[3] = point[1].y;
points[4] = point[2].x;
points[5] = point[2].y;
points[6] = point[0].x;
points[7] = point[0].y;
canvas.drawVertices(VertexMode.TRIANGLES, 8, points, 0, null, 0, null, 0, null, 0, 0, paint);
Path path = new Path();
path.moveTo(point[0].x , point[0].y);
path.lineTo(point[1].x,point[1].y);
path.lineTo(point[2].x,point[2].y);
canvas.drawPath(path,paint);
}
I'm currently stuck in front of a problem.
I work on Android with API 19 with Eclipse IDE using Java.
I've done an Activity which contains some Layouts. And i've put in one of these layout a custom class which inherits from GLSurfaceView in order to provide a 3D rendering for the user.
But actually i have a problem on a specific device, the "Epson moverio" glasses which works with Android 4.04.
When the softkeyboard pops out, it shows me the GLSurfaceView and also a black square which have the same dimensions as GLSurfaceView and this black square is contiguous with the GLSurfaceView. I don't understand why i have this bug, because it works well on classic devices like samsung tablets and i have another version of the view on which i draw 2D shapes using canvas, and i don't get the black square problem, it seems that kind of problem happens only with openGL rendering context (i'm using openGL 2.0 ES).
it seems that this bug occurs only when the softkeyboard pops on the screen.
I tried to put an invalidate() and a forceLayout function call in onSurfaceChanged and onSizeChanged but it doesn't work.
I point out that the bug only occurs on the "Epson moverio" glasses and i don't understand why.
Is it a good way to build my own class which inherits from GLSurfaceView, and put it into the Activity's layout in order to display 3D or is there another better way to do that kind of feature ?
Here's some snippet of code of my GLSurfaceView class implementation
#Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
long time = SystemClock.uptimeMillis() % 10000L;
float angleInDegrees = (360.0f / 10000.0f) * ((int) time);
if (_trolleyContentInfoList != null && _trolleyCaracteristics != null) {
_matrixTools.loadIndentity(MatrixType.MODEL_MATRIX);
drawTrolleyStructure(angleInDegrees);
drawTrolleyShelves(angleInDegrees);
//drawTrolleyWheels(angleInDegrees);
}
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO Auto-generated method stub
GLES20.glViewport(0, 0, width, height);
float aspect = (float)width / height;
float fovy = 60.0f;
float near = 0.1f;
float far = 10.0f;
_width = width;
_height = height;
_matrixTools.loadIndentity(MatrixType.PROJECTION_MATRIX);
_matrixTools.perspective(MatrixType.PROJECTION_MATRIX, fovy, aspect, near, far);
this.forceLayout();
}
#Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
this.forceLayout();
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0.8f, 0.8f, 0.8f, 0.0f);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
_matrixTools.loadIndentity(MatrixType.VIEW_MATRIX);
_matrixTools.lookAt(MatrixType.VIEW_MATRIX, 0.0f, 0.0f, -2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
_matrixTools.loadIndentity(MatrixType.MODEL_MATRIX);
_cubeDrawer = new CubeDrawer();
_cubeDrawer.initialize();
}
And, finally, here's how my custom class inherits from GLSurfaceView
public class Trolley3DView extends GLSurfaceView implements GLSurfaceView.Renderer, ITrolleyPreviewView{
}
Edit : Okay after a test i've seen that the black square dissapear after typing something into a TextView in the Activity. Must i understand that i should invalidate the Activity in order to force it to refresh when the softkeyboard pops out ?
Okay, i finnaly found the reason of the bug. You have to set the color of the View on which you display openGL content, and the black square will magically disapear.
Let suppose we have the custom ListView which extends onDraw() method by drawing some rectangle in it.
class Listpicker extends ListView {
//..Some other methods here..//
#Override
protected void onDraw(android.graphics.Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(glassPickerBitmap, null, glassRect, semiTransparrentPaint);
}
}
The bitmap drawn represent some sort of glass which is rectangle with width equal to the width of listview and some height. What I want is when list item scrolls into this rectangle the color used for drawing text (not all item with background and etc.) would be changed into some another color. So, for example, when list item fits so that only half height of text fits into glassPickerBitmap, the outside part of list item should remain in its ordinal colors, and the part that is inside glassPickerBitmap should change its text color. List items are simple TextViews without any background.
How can be this achieved? Maybe any ColorFilters assigned to the Paint? But where? onDraw() method of Listview is not even called when ListView is scrolled... Can be this done inside customized views, for example, that will be ListView's items? Or may be some Color/Shader/do not know what else overlay can be used here, but where?
EDIT (added image examples):
Here is example of some crop from real-life app. There are 2 ListViews: one on the left side, other on the right. Glass is the grayed rectangle. Now, left list has "United States Dollar" currency selected. And I am scrolling right ListView in that way, that selection is somewhere between USD and Afghan Afghani. Now, what I want, is that USD currency in the left ListView would be drawn in red (exact color doesn't matter now, I will change it later to something meaningful) AND, in the same time, bottom part of "United States Dollar" and top part of "Afghan Afghani" in the right ListView would be drawn also in the same red color.
This color changing should be done in dynamic way - color should be changed only for the part of text that is under glass rectangle during scrolling of the list.
*OK, EUR and USD here are special currencies drawn with not standard cyan color. The question is about at least text with white color. But if it will be possible to change also cyan color it would be great.
As you can tell in their implementation they use and update a fixed position in their ListAdapter so then they update the View that matches accordingly, which is to me the easiest and simpler way to do it, but you don't get the half-half colored text, which I think you still want :)
So here is probably one of the worst answers I've given, sorry about it, I'll probably revisit this or hope someone can point you to a better solution
You can see a blurry demo at:
http://telly.com/Y98DS5
The dirty way:
Create a Paint with a proper ColorMatrixColorFilter, for the purposes of answering this I'm just desaturating, you'll have to figure out your 5x4 matrix for ColorMatrix to get the cyan your looking for. Also you will need some Rects to define source and dest when drawing below.
Create an off screen Bitmap and Canvas which you'll use to draw your list, that's done in onSizeChanged so we have proper view layout values, here you can start noticing the dirtiness as you will have to allocate a Bitmap as big as your ListView so you may get OutOfMemoryException.
Override draw to use your off screen Canvas and let ListView draw to it, then you can draw the Bitmap to the given Canvas that will draw your list as usual, then draw just the part of that Bitmap which will be drawn differently using the Paint we defined before, you will get overdraw for those pixels.
Finally draw your pre-fabricated glass Bitmap, I would recommend a n-patch (9-patch) so it scales and looks sharp across screens and densities, then you get more overdraw for those pixels.
The whole cake looks like:
public class OverlayView extends ListView {
private RectF mRect;
private Rect mSrcRect;
private Paint mPaint;
private Canvas mCanvas;
private Bitmap mBitmap;
private float mY;
private float mItemHeight;
public OverlayView(Context context) {
super(context);
initOverlay();
}
public OverlayView(Context context, AttributeSet attrs) {
super(context, attrs);
initOverlay();
}
public OverlayView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initOverlay();
}
private void initOverlay() {
// DO NOT DO THIS use attrs
final Resources res = getResources();
mY = res.getDimension(R.dimen.overlay_y);
mItemHeight = res.getDimension(R.dimen.item_height);
//
mRect = new RectF();
mSrcRect = new Rect();
mPaint = new Paint();
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(0);
mPaint.setColorFilter( new ColorMatrixColorFilter(colorMatrix) );
}
#Override
public void draw(Canvas canvas) {
super.draw(mCanvas);
canvas.drawBitmap(mBitmap, 0, 0, null);
canvas.drawBitmap(mBitmap, mSrcRect, mRect, mPaint);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRect.set(0, mY, w, mY + mItemHeight);
mRect.roundOut(mSrcRect);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
}
So that said, I hope you end up with a cleaner solution, even if you don't get that half-half sexiness :)
First, keep a spare bitmap and canvas:
class Listpicker extends ListView {
Bitmap bitmapForOnDraw = null;
Canvas canvasForOnDraw = null;
Make sure it's the right size:
#override
protected void onSizeChanged (int w, int h, int oldw, int oldh) {
if (bitmapForOnDraw != null) bitmapForOnDraw.recycle();
bitmapForOnDraw = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
canvasForOnDraw = new Canvas(bitmapForOnDraw);
}
And when we come to drawing the list:
#override
protected void onDraw(android.graphics.Canvas realCanvas) {
// Put the list in place
super.onDraw(realCanvas);
// Now get the same again
canvasForOnDraw.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
super.onDraw(canvasForOnDraw);
// But now change the colour of the white text
canvasForOnDraw.drawColor(0xffff00ff, PorterDuff.Mode.MULTIPLY);
// Copy the different colour text into the right place
canvas.drawBitmap(bitmapForOnDraw, glassRect, glassRect overwritePaint);
// finally, put the box on.
canvas.drawBitmap(glassPickerBitmap, null, glassRect, semiTransparrentPaint);
}