I wanted to create something like a ComboBox, but the arrow-button on the right-side within the TextView. All the approaches I have seen up till now places the arrow outside the text-field (as an extra button) - which I don't like. To simulate it, I thought I could do it like
android:drawableRight="#android:drawable/arrow_up_float"
android:ems="10"
which looks good, in sense there is on the right side the arrow. I thought I could lay behind it a gradient paint like:
int witdhComboBox = 50;
#Override
protected void onDraw(Canvas canvas) {
//
Paint paint = new Paint();
final int bottom = getBottom() - 10;
paint.setShader(new LinearGradient(0, 0, 0,bottom,
Color.WHITE,
Color.GRAY,
Shader.TileMode.REPEAT));
canvas.drawRect(new Rect(getRight() - witdhComboBox,
getTop() - getPaddingTop() - getTopPaddingOffset()
+ getBottomPaddingOffset()
+ getPaddingBottom(),
getRight() - 8,
bottom), paint);
super.onDraw(canvas);
}
but suffer obviously inappropriate paddings resp. incorrect dimensions within the layouts. I looks fine when I'm in the eclipse:
but when I get on my Galaxy Note it looks too narrow:
and on a HTC Desire it looks too wide (and not properly ending which I wouldn't mind that much):
Is there a good way to place the gradient directly under the arrow? Cause currently I guess its a combined issue of resolution and different style of additional spaces.
Related
I have looked all over, but nothing has worked. Every time I try finding the center of the screen for my watch face, it always end up slightly higher than the center, and to the far right of the screen (This is different than the problem that the original template from Android Studio has, where the Watch face is slightly up and all the way to the far left of the screen). What could I be doing wrong?
(First screenshot on Left: My problem. Second screenshot: Original form of the Android Wear template from Android Studio)
#Override
public void onDraw(Canvas canvas, Rect bounds) {
if (isInAmbientMode()) {canvas.drawColor(Color.BLACK);
}
else {
canvas.drawRect(0, 0, bounds.width(), bounds.height(), mBackgroundPaint);
}
// Draw H:MM in ambient mode or H:MM:SS in interactive mode.
long now = System.currentTimeMillis();
mCalendar.setTimeInMillis(now);
int width = bounds.width();
int height = bounds.height();
float centerX = width / 2f;
float centerY = height / 2f;
String text = mAmbient
? String.format("%d:%02d", mCalendar.get(Calendar.HOUR),
mCalendar.get(Calendar.MINUTE))
: String.format("%d:%02d", mCalendar.get(Calendar.HOUR),
mCalendar.get(Calendar.MINUTE));
canvas.drawText(text, centerX, centerY, mTextPaint);
}
Full code can be found here
As far as i can tell from a quick look on your sources you already calculate mTextXOffset and mTextYOffset but don't use it for your draw call, hence the texts origin is centered in your problematic screenshot instead of the texts center.
adjusting your centerX and centerY by mTextXOffset and mTextYOffset should do the trick.
If you're drawing text using a center point you can use
mTextPaint.setTextAlign(Paint.Align.CENTER);
which will draw from the center. Otherwise the x coordinte represents the left hand side of the text you are drawing.
I am trying to draw a heart shaped Canvas using Path in Android. The code is as follows :
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Fill the canvas with background color
canvas.drawColor(Color.WHITE);
// paint.setShader(null);
// Defining of the heart path starts
path.moveTo(left + WIDTH / 2, top + HEIGHT / 4); // Starting point
// Create a cubic Bezier cubic left path
path.cubicTo(left+WIDTH/5,top,
left+WIDTH/4,top+4*HEIGHT/5,
left+WIDTH/2, top+HEIGHT);
// This is right Bezier cubic path
path.cubicTo(left + 3 * WIDTH / 4, top + 4 * HEIGHT / 5,
left + 4 * WIDTH / 5, top,
left + WIDTH / 2, top + HEIGHT / 4);
paint.setShader(new LinearGradient(0, canvas.getHeight()/4, canvas.getWidth(), canvas.getHeight()/4, new int[]{Color.RED, Color.YELLOW, Color.GREEN}, new float[]{0, 0.6f, 1}, Shader.TileMode.CLAMP));
canvas.drawPath(path, paint);
heart_outline_paint.setColor(getResources().getColor(R.color.heart_outline_color)); // Change the boundary color
heart_outline_paint.setStrokeWidth(4);
heart_outline_paint.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, heart_outline_paint);
}
I am able to draw heart without any issue and I am able to fill color inside the heart using the Fill option in Paint. But I should be able to fill the heart dynamically according to some data and it cannot be filled fully all the time. What I have achieved so far is as follows :
I have made an extensive search and came across a lot of things similar to this. Some of which includes :
Android fill in part of a path?
filling a circle gradually from bottom to top android
I also came across the concept of converting the canvas to bitmap and filling color inside the bitmap using Flood Fill Algorithm which lets users to fill colors inside the bitmap. However, I do not want the bitmap to fill the color while touching inside the heart but to fill while a button click action.
I thought that filling a circle gradually from bottom to top android
would give help me but it makes use of a circle and I am not well-versed in Canvas which makes me very weak in adapting the circle code to such a shape.
If anybody has some ideas or any insights on how to achieve this, it will be really helpful. Cheers. Thanks in advance.
P.S : I also tried some tricks using setShader in Paint but nothing would give me what I want.
EDIT :
I just stumbled upon a idea of drawing a rectangle over the heart with another color same as the background of the canvas so that it will look like its half filled !! I am still working on the idea and not sure how accurate this is gonna be for me. If someone has a better idea, you're most welcome.
I used clipPath function available in Canvas to achieve what I needed. I draw the heart by above method and draw a rectangle over it, and I use the clipPathfunction to clip out the region that is outside the heart.
public static double filled_amount = .90;
path.moveTo(left_x_moveto, left_y_moveto);
path.cubicTo(left_x1, left_y1, left_x2, left_y2, left_x3, left_y3);
path.cubicTo(right_x2, right_y2, right_x1, right_y1, left_x_moveto, left_y_moveto);
path.close();
Rect rect = new Rect((int)(canvas.getWidth()*.10),(int)(canvas.getHeight()*filled_amount),(int) canvas.getWidth(), (int) canvas.getHeight());
canvas.clipPath(path);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(path, paint);
canvas.drawRect(rect, rect_paint);
heart_outline_paint.setColor(getResources().getColor(R.color.heart_outline_color)); // Change the boundary color
heart_outline_paint.setStrokeWidth(15);
heart_outline_paint.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, heart_outline_paint);
This will give me the desired result of filling the heart dynamically. Changing the value of filled_amount dynamically and calling invalidate() will make it look like the heart is being filled dynamically.
#Henry's answer might be a better one but this did the trick for me and I dont look deeply in to the edges so a bit of zig-zags here and there is all right.
You could use Bitmap Masking to get a partially filled Heart. What you ideally do here is use one bitmap to mask the other.
In your case you could have a filled rectangle in the canvas and you have then have the heart shape in a new bitmap to act as the mask. You could then dynamically change the filling of the heart by changing the height of the background rectangle.
Refer this: https://stackoverflow.com/a/33483600/4747587. This contains the implementation of partially filling a Star. The idea is the same.
I know how to stroke text using custom views(EditText or TextView) but I couldn't able to achieve something beautiful like this one, which is done using Photoshop. And yes, it has outer shadow too.
What I have done so far is adjusting stroke width and stroke join style. However, if I increase the stroke width, the stroke took place the whole text.
As far as I have searched, there is a library called MagicTextView but it also couldn't give the result like that above.
Update: I have tweaked things based on suggestion by #pskink. It works now. However I can't drag anymore. If I drag that EditText, there is some weird lines showed up like this.
Here is the code:
#Override public void onDraw(Canvas canvas) {
final int x = this.getLeft();
final int y = this.getBottom();
mText = this.getText().toString();
p.setStrokeWidth(30);
p.setStyle(Style.STROKE);
p.setStrokeJoin(Join.ROUND);
p.setColor(0xffffffff);
canvas.drawText(mText, x, y, p);
p.setStyle(Style.FILL);
p.setColor(0xff000000);
canvas.drawText(mText, x, y, p);
}
After a few hours of tweaking, I have fixed the weird line issue stated in updated question. I think I should post here as the answer.
#Override public void onDraw(Canvas canvas) {
mText = this.getText().toString();
p.setStyle(Style.STROKE);
p.setStrokeJoin(Join.ROUND);
p.setShadowLayer(10, 1, 1, 0xcfcccccc);
canvas.drawText(mText, 0, getLineHeight(), p);
p.clearShadowLayer();
p.setStrokeWidth(35);
p.setStrokeJoin(Join.ROUND);
p.setStyle(Style.STROKE);
p.setColor(0xffffffff);
canvas.drawText(mText, 0, getLineHeight(), p);
p.setStyle(Style.FILL);
p.setColor(0xff000000);
canvas.drawText(mText, 0, getLineHeight(), p);
canvas.translate(xPos, yPos);
}
xPos and yPos are x and y values from ACTION_MOVE onTouch event. And We need to add the line height as a Y for the canvas text.
However, if I increase the stroke width, the stroke took place the whole text.
If the problem is that the stroke is centered, and you want it outside the text, see: Android Paint stroke width positioning
You must precalculate the desired width and height according to your stroke.
I would suggest trying a very bold font. In the image below, the white stroke would be centered on the red line (which would be the outline of each black letter).
In response to your update:
If I drag that EditText, there is some weird lines showed up.
The line might be the result of focus on the EditText. You can remove the focus explicitly: Android: Force EditText to remove focus?
Alternatively, you can style the focus (perhaps to be invisible, if it doesn't adversely affect the rest of your UI): How to change the color of a focused EditText when using "android:Theme.Holo.Light"?
Here is the situation. I am rendering to a canvas. Nothing else is being rendered, the canvas is effectively fullscreen. There is only one view.
I want to make a simple (text) button. This consists of two parts: visually drawing it, and checking bounds to see if it is pressed. These two things should be consistent.
Ideally the centering is optional, though I would expect switching it to be simple.
After far too many hours, I suspect it is not simply an alignment issue, but also a use of the API that is the source of the problem.
How can this be done?
Just use static layouts and then you can keep the text center aligned inside the canvas even if the size is increased by some limit by auto aligning the text.
Rect bounds = new Rect(x1, y1, x2, y2);// set the bounds
String textOnCanvas = "text to be wriiten";
StaticLayout sl = new StaticLayout(textOnCanvas, textPaint,
bounds.width(), Layout.Alignment.ALIGN_CENTER, 1, 1, true);
canvas.save();
float textHeight = getTextHeight(textOnCanvas, textPaint);
int numberOfTextLines = sl.getLineCount();
float textYCoordinate = bounds.exactCenterY() -
((numberOfTextLines * textHeight) / 2);
//text will be drawn from left
float textXCoordinate = bounds.left;
canvas.translate(textXCoordinate, textYCoordinate);
//draws static layout on canvas
sl.draw(canvas);
canvas.restore();
The parameter Layout.Alignment.ALIGN_CENTER of static layout will take care of the center alignment of the text in canvas.
I am trying to create the following simple shape in Android XML:
Just a rectangle combined with a triangle to form an arrow. The shape should be used as navigation button background.
On Windows Phone it would be no problem to create this shape in XAML but the XML drawing capabilities of Android seem to be much more limited.
I tried to create a layer-list drawable using a normal rectangle as "body" and rotated rectangle as triangle. Creating a triangle by rotating a rectangle works fine as long as the triangle is aligned with the border. As soon as I try to move/translate the triangle to the left (to the end of the body/box), the triangle is not triangle any more but of course just a rotated rectangle... Is there any way to clip off the one half of the rotated rectangle and move it to the end of the box in XML?
Of course this can be done in Code/Java, but I would like to know if it also possible XML.
I would need this kind of button in many different sizes and using a XML drawable would be much better (from my point of view) than using dozens of PNGs.
try this custom Shape:
Shape shape = new Shape() {
Path path = new Path();
#Override
protected void onResize(float width, float height) {
path.reset();
path.lineTo(width - height / 2, 0);
path.lineTo(width, height / 2);
path.lineTo(width - height / 2, height);
path.lineTo(0, height);
path.close();
}
#Override
public void draw(Canvas canvas, Paint paint) {
canvas.drawPath(path, paint);
}
};
ShapeDrawable d = new ShapeDrawable(shape);
d.getPaint().setColor(0xff6699bb);
someView.setBackgroundDrawable(d);
I can't comment so will answer.. I like the layerlist idea. example here:
Android custom shape
and triange example here: http://looksok.wordpress.com/2013/08/24/android-triangle-arrow-defined-as-an-xml-shape/
combining those answers may work.