Last active
October 11, 2015 03:57
-
-
Save nutiteq/3798924 to your computer and use it in GitHub Desktop.
DefaultLabel.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.nutiteq.ui; | |
import java.util.LinkedList; | |
import java.util.List; | |
import android.graphics.Canvas; | |
import android.graphics.Paint; | |
import android.graphics.Paint.Align; | |
import android.graphics.Paint.Style; | |
import android.graphics.Path; | |
import android.graphics.Rect; | |
import android.graphics.RectF; | |
import com.nutiteq.components.TextureInfo; | |
import com.nutiteq.style.LabelStyle; | |
/** | |
* Simple text-based map label containing title and optional description. | |
*/ | |
public class DefaultLabel extends Label { | |
private static final LabelStyle DEFAULT_STYLE = LabelStyle.builder().build(); | |
private final String title; | |
private final String description; | |
private final LabelStyle style; | |
private Paint paint = null; | |
private int titleHeight; | |
private int descriptionHeight; | |
private int descriptionWidth; | |
private int width; | |
private int height; | |
/** | |
* Default constructor. | |
* | |
* @param title | |
* label title. | |
*/ | |
public DefaultLabel(String title) { | |
this(title, null); | |
} | |
/** | |
* Constructor for label with both title and description. Description will be aligned to | |
* the center of the label. | |
* | |
* @param title | |
* label title. | |
* @param description | |
* label description. Description supports \n separator for multiline texts. | |
*/ | |
public DefaultLabel(String title, String description) { | |
this(title, description, DEFAULT_STYLE); | |
} | |
/** | |
* Constructor for label with both title and description and description alignment style. | |
* | |
* @param title | |
* label title. | |
* @param description | |
* label description. Description supports \n separator for multiline texts. | |
* @param descAlign | |
* description alignment style. | |
*/ | |
public DefaultLabel(String title, String description, Align descAlign) { | |
this(title, description, LabelStyle.builder().setDescriptionAlign(descAlign).build()); | |
} | |
/** | |
* Constructor for label with title, description and custom label style. | |
* | |
* @param title | |
* label title. | |
* @param description | |
* label description. Description supports \n separator for multiline texts. | |
* @param style | |
* label style. | |
*/ | |
public DefaultLabel(String title, String description, LabelStyle style) { | |
this.title = title; | |
this.description = description; | |
this.style = style; | |
} | |
/** | |
* Get label title. | |
* | |
* @return label title. | |
*/ | |
public String getTitle() { | |
return title; | |
} | |
/** | |
* Get label description. | |
* | |
* @return label description. | |
*/ | |
public String getDescription() { | |
return description; | |
} | |
private void initializePaint() { | |
paint = new Paint(Paint.ANTI_ALIAS_FLAG); | |
paint.setTextAlign(style.descriptionAlign); | |
paint.setStyle(Style.FILL); | |
paint.setTypeface(style.titleFont); | |
paint.setTextSize(style.titleSize); | |
Rect titleSize = new Rect(); | |
paint.getTextBounds(title, 0, title.length(), titleSize); | |
titleHeight = titleSize.height(); | |
if (description != null && description.length()>0) { | |
paint.setTypeface(style.descriptionFont); | |
paint.setTextSize(style.descriptionSize); | |
String[] lines = wrapText(description, paint, style.descriptionWrapWidth, 0); | |
Rect lineSize = new Rect(); | |
int descWidth = 0, descHeight = 0; | |
for (String line : lines) { | |
if (line.length() == 0) { | |
line = " "; // HACKFIX: getTextBounds does not work with empty strings | |
} | |
paint.getTextBounds(line, 0, line.length(), lineSize); | |
descHeight += lineSize.height(); | |
descWidth = Math.max(descWidth, lineSize.width()); | |
} | |
descriptionHeight = descHeight; | |
descriptionWidth = descWidth; | |
width = (int) Math.max(titleSize.width(), descriptionWidth) + 2 * style.edgePadding; | |
height = (int) titleSize.height() + descriptionHeight + 2 * style.edgePadding + lines.length * style.linePadding; | |
} else { | |
descriptionHeight = 0; | |
descriptionWidth = 0; | |
width = (int) titleSize.width() + 2 * style.edgePadding; | |
height = (int) titleSize.height() + 2 * style.edgePadding; | |
} | |
} | |
@Override | |
public TextureInfo drawMarkerLabel() { | |
if (paint == null) { | |
initializePaint(); | |
} | |
TextureInfo textureInfo = getTextureInfo(width, height + Math.max(0, style.triangleSize - style.borderSize)); | |
Canvas canvas = new Canvas(textureInfo.bitmap); | |
// Draw background bubble | |
paint.setColor(style.borderColor); | |
canvas.drawRoundRect(new RectF(0, 0, width, height), style.roundedOutside, style.roundedOutside, paint); | |
paint.setColor(style.backgroundColor); | |
canvas.drawRoundRect(new RectF(style.borderSize, style.borderSize, width - style.borderSize, height - style.borderSize), | |
style.roundedInside, style.roundedInside, paint); | |
// Draw triangle | |
Path triangleOutside = new Path(); | |
triangleOutside.moveTo(0, 0); | |
triangleOutside.lineTo(style.triangleSize, 0); | |
triangleOutside.lineTo(style.triangleSize / 2, style.triangleSize); | |
triangleOutside.lineTo(0, 0); | |
float newBorderSize = (int) (style.borderSize * 1.4); | |
Path triangleInside = new Path(); | |
triangleInside.moveTo(newBorderSize, 0); | |
triangleInside.lineTo(style.triangleSize - newBorderSize, 0); | |
triangleInside.lineTo(style.triangleSize / 2, style.triangleSize - newBorderSize * 1.5f); | |
triangleInside.lineTo(newBorderSize, 0); | |
canvas.translate(width / 2 - style.triangleSize / 2, height - style.borderSize); | |
paint.setColor(style.borderColor); | |
canvas.drawPath(triangleOutside, paint); | |
paint.setColor(style.backgroundColor); | |
canvas.drawPath(triangleInside, paint); | |
canvas.setMatrix(null); | |
// Draw text | |
paint.setColor(style.titleColor); | |
paint.setTypeface(style.titleFont); | |
paint.setTextSize(style.titleSize); | |
Align align = paint.getTextAlign(); | |
paint.setTextAlign(style.titleAlign); | |
canvas.drawText(title, width / 2, style.edgePadding + titleHeight, paint); | |
paint.setTextAlign(align); | |
if (description != null) { | |
paint.setColor(style.descriptionColor); | |
paint.setTypeface(style.descriptionFont); | |
paint.setTextSize(style.descriptionSize); | |
int x = style.edgePadding; | |
if (Align.CENTER.equals(paint.getTextAlign())) { | |
x = width / 2; | |
} else if (Align.RIGHT.equals(paint.getTextAlign())) { | |
x = width - style.edgePadding; | |
} | |
drawString(canvas, paint, description, x, style.edgePadding + titleHeight); | |
} | |
return textureInfo; | |
} | |
@Override | |
public float getMarkerLabelAlpha() { | |
return style.alpha; | |
} | |
private void drawString(Canvas canvas, Paint paint, String str, int x, int y) { | |
Rect bounds = new Rect(); | |
String[] lines = wrapText(str, paint, style.descriptionWrapWidth, 0); | |
int yoff = 0; | |
for (String line : lines) { | |
if (line.length() == 0) { | |
line = " "; // HACKFIX: getTextBounds does not work with empty strings | |
} | |
paint.getTextBounds(line, 0, line.length(), bounds); | |
yoff += bounds.height() + style.linePadding; | |
canvas.drawText(line, x, y + yoff, paint); | |
} | |
} | |
private static String[] wrapText(String text, Paint paint, int wrapWidth, int currentX) { | |
// wrapped text lines | |
final List<String> wt = new LinkedList<String>(); | |
final int len = text.length(); | |
if (len == 0) { | |
return new String[0]; | |
} | |
int first = 0; | |
int last = 0; | |
boolean emptylineflag = false; | |
for (int i = 0; i < len; i++) { | |
// split at '\n' | |
if (text.charAt(i) == '\n') { | |
wt.add(text.substring(first, i)); | |
first = i + 1; | |
last = i; | |
emptylineflag = false; | |
continue; | |
} | |
// update last if necessary | |
if (text.charAt(i) == ' ') { | |
last = i; | |
// don't check to split - we would have splitted at the previous char | |
continue; | |
} | |
// check that wrapping is switched on | |
if (wrapWidth < 0) { | |
continue; | |
} | |
// check length, see if we should split | |
float w = paint.measureText(text, first, i + 1); | |
// we should not split if we printed nothing on the previous line | |
if ((first == 0 && w + currentX > wrapWidth) || (first != 0 && w > wrapWidth)) { | |
// yep, we should split, first to last, then the rest | |
// if last is equal to first, the first word doesn't fit, so add an | |
// empty string | |
// but set a flag to avoid adding it again | |
if (first < last || (first == last && !emptylineflag)) { | |
String s = text.substring(first, last); | |
wt.add(s); | |
} | |
if (first < last) { | |
// start with last+1 | |
emptylineflag = false; | |
first = last + 1; | |
} else { | |
emptylineflag = true; | |
} | |
} | |
} | |
// add the last string | |
wt.add(text.substring(first)); | |
return wt.toArray(new String[wt.size()]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment