Google Map Marker with custom background and text - android

I'm trying to customize an map marker so that it can be displayed with 3 main features:
9patch drawable as background
Custom text
Optional drawable to the left of the text (some markers have it, some don't)
I have used IconGenerator from android google map utils library, but somehow the entire clickable area of the marker is affected. An very big area around the marker is clickable and activates the marker. It also has issues with the content padding and gravity attributes.
I have added the custom hack on the map in order to bring to front the markers without opening the info window (I've setup an info window with no content to display and I've called showInfoWindow in Marker click event listener).
How can I manually created the icon for the marker and avoid the issue with the big clickable area around it?
I have also tried the implementation described here, basically the drawTextToBitmap() method:
private Bitmap drawTextToBitmap(#DrawableRes int backgroundRes, String text) {
Resources resources = getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap = BitmapFactory.decodeResource(resources, backgroundRes);
android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
if (bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// SET FONT COLOR (e.g. WHITE -> rgb(255,255,255))
paint.setColor(Color.rgb(255, 255, 255));
// SET FONT SIZE (e.g. 15)
paint.setTextSize((int) (15 * scale));
// SET SHADOW WIDTH, POSITION AND COLOR (e.g. BLACK)
paint.setShadowLayer(1f, 0f, 1f, Color.BLACK);
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
int x = (bitmap.getWidth() - bounds.width()) / 2;
int y = (bitmap.getHeight() + bounds.height()) / 2;
canvas.drawText(text, x, y, paint);
return bitmap;
}
But it doesn't work as expected, because my text is bigger than the background, and I also don't know how to add an resource to the left of the text.
This is the implementation for IconGenerator I'm using:
private BitmapDescriptor getBitmapDescriptorForProduct(#NonNull final MyCustomObject product, boolean isActive) {
if (product.shouldDisplayWithLabel) {
// We use an custom layout for displaying markers on the map
#SuppressLint("InflateParams") View view =
LayoutInflater.from(getActivity()).inflate(R.layout.my_custom_label, null);
// Get the text view which will display the text
TextView label = (TextView) view.findViewById(R.id.text);
// Set the left drawable if needed
label.setCompoundDrawablesWithIntrinsicBounds(product.shouldDisplayWithDrawable ? R.drawable.my_custom_drawable : 0, 0,
0, 0);
// Set the text for the label
label.setText(product.label);
label.setBackgroundResource(R.drawable.my_custom_background);
// Set the layout for the icon
mIconGenerator.setContentView(view); // set the custom layout
// We don't want the default background
mIconGenerator.setBackground(null);
// Disable the content padding as we handle it in the view and in the 9patch resources
mIconGenerator.setContentPadding(0, 0, 0, 0);
// Make the icon and create the BitmapDescriptor necessary for the marker creation
Bitmap icon = mIconGenerator.makeIcon();
return BitmapDescriptorFactory.fromBitmap(icon);
} else {
// Lazy initialization for the normal markers
if (null == simpleMarkerIcon) {
simpleMarkerIcon = BitmapDescriptorFactory.fromResource(R.drawable.my_simple_marker);
}
// Reuse the bitmap for the simple markers that will be displayed on the map.
return simpleMarkerIcon;
}
}
LE:
#Harpreet, this how the marker icon will look like using your solution:
As you can see, the properties of the view are not displayed correctly in the bitmap.

public static Bitmap createDrawableFromView(Context context, View view) {
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay()
.getMetrics(displayMetrics);
view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
view.measure(displayMetrics.widthPixels, displayMetrics.heightPixels);
view.layout(0, 0, displayMetrics.widthPixels,
displayMetrics.heightPixels);
view.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(),
view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
Note:- Just fill Context and add your complete custom created view/layout as an object of View
It'll help you.

Related

Save mapView as image without rendering it on screen

I'm creating free activity monitoring app similar to Strava. Using vtm-android as map library.
I would like save org.oscim.android.MapView as image, without rendering it to screen.
I found several solutions, how to save view as image, but unfortunately none of them is working when when view is not "attached" to existing component tree.
My expectation was to initialize MapView like this:
final String MAP_FILE = "somemap.map";
MapView mapView = new MapView(mContext);
final org.oscim.map.Map map = mapView.map();
MapFileTileSource tileSource = new MapFileTileSource();
String mapPath = new File(Environment.getExternalStorageDirectory(), MAP_FILE).getAbsolutePath();
if (tileSource.setMapFile(mapPath)) {
// Vector layer
VectorTileLayer tileLayer = map.setBaseMap(tileSource);
// Render theme
map.setTheme(VtmThemes.DEFAULT);
double latitude = 49.1625214;
double longitude = 20.2644075;
// Note: this map position is specific to Berlin area
map.setMapPosition(latitude, longitude, 1 << 12);
}
mapView.layout(0, 0, 200, 200);
//Get the dimensions of the view so we can re-layout the view at its current size
//and create a bitmap of the same size
int width = view.getWidth();
int height = view.getHeight();
int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
//Cause the view to re-layout
view.measure(measuredWidth, measuredHeight);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
//Create a bitmap backed Canvas to draw the view into
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
//Now that the view is laid out and we have a canvas, ask the view to draw itself into the canvas
view.draw(canvas);
ByteBuffer byteBuffer = ByteBuffer.allocate(bitmap.getByteCount());
bitmap.copyPixelsToBuffer(byteBuffer);
//save bytes from bytebuffer to file or db
But instead of map image, I get full transparent image.
To take screen shot you need render it on screen. Without rendering screenshot is not possible
mapView.getDrawingCache()
It will return you bitmap of current displaying.
Bitmap capturedScreen = Bitmap.createBitmap(mapView.getDrawingCache()); imageView.setImageBitmap(capturedScreen);
Here 'capturedScreen' will give you image of mapview.

Is there a way of customizing each Google Maps marker in Android Studio?

I am building a google maps app. I have different objects with coordinates but each object has a unique int value wich i would like to be shown next to a marker.
For example for an object with specific coorinates and value 123, i would like to put on the map(at those coords) the marker and next to it the value 123.
I've been doing some research and the only way I found plausible is to use an Android API to create your own bitmap image from a base image and some string that is "attached" and use that for the marker icon.
Is there a better way of doing that ?
On the same topic, cand you show the title of every marker on your map at the same time ?
https://stackoverflow.com/a/14812104
Please see the link. The snipet is used to add text on the maker which can also be customized.
Yes #kisslory you can fully customize each marker to suit your need.
While setting the bitmap for each marker you can create a new bitmap with from a given resource using the method below.
public static Bitmap drawTextToBitmap(Context gContext,
int gResId,
String gText) {
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap =
BitmapFactory.decodeResource(resources, gResId);
android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
// new antialised Paint
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
paint.setColor(Color.rgb(61, 61, 61));
// text size in pixels
paint.setTextSize((int) (14 * scale));
// text shadow
paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
// draw text to the Canvas center
Rect bounds = new Rect();
paint.getTextBounds(gText, 0, gText.length(), bounds);
int x = (bitmap.getWidth() - bounds.width())/2;
int y = (bitmap.getHeight() + bounds.height())/2;
canvas.drawText(gText, x, y, paint);
return bitmap;
}

Change Position of textOn and textOff in Android Swtich

I have implemented the Switch Widget this way:
<android.support.v7.widget.SwitchCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOff="#string/switch_on"
android:textOn="#string/switch_on"
app:showText="true"
android:gravity="right"
android:thumb="#drawable/slider_thumb"
app:switchMinWidth="200dp"
app:track="#drawable/slider_tracker">
Everything works fine, except that the text is written on top on the thumb. What i want t achieve is having the text displayed on the track. So, assuming the switch is checked, the text would be displayed on the left and when not checked, the textOff would be displayed on the right.
.
How can i achieve this. Thanks
I figured out i can achieve this by drawing a text on a bitmap, generate a bitmap drawable from that and change the track drawable of the switch to the bitmapdrawable.
Basically, i achieve this with the snippet below.
BitmapDrawable bitmapDrawable = new BitmapDrawable(drawTextToBitmap(this, R.drawable.test_, "Slide to Sign In"));
switchCompat.setTrackDrawable(bitmapDrawable);
public Bitmap drawTextToBitmap(Context gContext,
int gResId,
String gText) {
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap =
BitmapFactory.decodeResource(resources, gResId);
android.graphics.Bitmap.Config bitmapConfig =
bitmap.getConfig();
// set default bitmap config if none
if (bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
// new antialised Paint
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
paint.setColor(Color.rgb(61, 61, 61));
// text size in pixels
paint.setTextSize((int) (10 * scale));
// text shadow
paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
// draw text to the Canvas center
Rect bounds = new Rect();
paint.getTextBounds(gText, 0, gText.length(), bounds);
int x = (bitmap.getWidth() - (170));
int y = (bitmap.getHeight() + bounds.height()) / 2;
canvas.drawText(gText, x, y, paint);
return bitmap;
}
As for changing the drawable when the the switch is on and off,you can play with that using
switchCompat.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
}
});

Resizing a custom marker on Android maps

Im quite new to Android so forgive me if I have missed something.
I've got the following code which displays a custom marker on maps. This custom marker also has some text on it. It works well up to the point where I want to resize the marker by a certain amount when the text is longer.
The code I originally had for the custom marker was,
private Bitmap drawTextToBitmap(final int mResId, final String mText) {
Resources resources = getResources();
// Get the screen's density scale
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap = BitmapFactory.decodeResource(resources, mResId);
Bitmap.Config bitmapConfig = bitmap.getConfig();
if ( bitmapConfig == null ) {
bitmapConfig = Bitmap.Config.ARGB_8888;
}
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// Set font color
paint.setColor(Color.WHITE);
// Set font size and scale it
paint.setTextSize((int) (14 * scale));
// Set shadow width
paint.setShadowLayer(1f, 0f, 1f, Color.BLACK);
// Set anti-aliasing
paint.setAntiAlias(true);
// Make font bold
paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
Rect bounds = new Rect();
paint.getTextBounds(mText, 0, mText.length(), bounds);
int x = (bitmap.getWidth() - bounds.width())/2;
int y = ((bitmap.getHeight() + bounds.height())/2)-25;
canvas.drawText(mText, x, y, paint);
return bitmap;
}
How can I resize this bitmap and also increase the font size accordingly without loosing any resolution ? Unfortunately I cant give screenshots due to licensing/permission issues.
Found the solution which was to add the following before creating the canvas.
int newWidth = (int) (origBitmap.getWidth() * scalingFactor);
int newHeight = (int) (origBitmap.getHeight() * scalingFactor);
Bitmap bitmap = Bitmap.createScaledBitmap(origBitmap, newWidth, newHeight, true);
This will scale the bitmap accordingly. I can similarly scale the font using the same scalingFactor.

Android drawText including text wrapping

I am currently creating an image editor and am attempting to draw text on top of on image using canvas.drawText(). So far I have been successful in doing this but when the user enters text that is too long, the text just continues on one line out of the page and doesn't wrap itself to the width of the screen. How would I go about doing this? I have tried using a static layout but cannot seem to get it to work, has anyone got a tutorial to do this?
My function for drawing on a canvas using static layout:
public Bitmap createImage(float scr_x,float scr_y,String user_text){
Canvas canvas = new Canvas(image);
scr_x = 100;
scr_y = 100;
final TextPaint tp = new TextPaint(Color.WHITE);
canvas.save();
StaticLayout sl = new StaticLayout("" + user_text, tp, originalBitmap.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
sl.draw(canvas);
return image;
}
Okay, I've updated my code, but when I try to draw on the image nothing happens at all, I have no idea why either:
public Bitmap createImage(String user_text) {
// canvas object with bitmap image as constructor
Canvas canvas = new Canvas(image);
TextPaint tp = new TextPaint();
tp.setColor(Color.RED);
tp.setTextSize(50);
tp.setTextAlign(Align.CENTER);
tp.setAntiAlias(true);
StaticLayout sl = new StaticLayout("" + user_text, tp,
canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
canvas.translate(100, 100);
sl.draw(canvas);
return image;
}
Is staticlayout not meant to be used to draw on canvas?
Yes, StaticLayout is what you're meant to use to draw multi-line text on a Canvas. Save yourself a world of pain and don't think about breaking text yourself -- you're on the right path.
I'm not sure about the bitmap problem, but your second code above worked just fine to draw text on a canvas for me.
Learn to use StaticLayout , then draw the Layout object onto a canvas using the Layout.draw() method.
References
public Bitmap drawMultilineTextToBitmap(Context gContext,
int gResId,
String gText) {
// prepare canvas
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap = BitmapFactory.decodeResource(resources, gResId);
android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
// new antialiased Paint
TextPaint paint=new TextPaint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
paint.setColor(Color.rgb(61, 61, 61));
// text size in pixels
paint.setTextSize((int) (14 * scale));
// text shadow
paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
// set text width to canvas width minus 16dp padding
int textWidth = canvas.getWidth() - (int) (16 * scale);
// init StaticLayout for text
StaticLayout textLayout = new StaticLayout(
gText, paint, textWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
// get height of multiline text
int textHeight = textLayout.getHeight();
// get position of text's top left corner
float x = (bitmap.getWidth() - textWidth)/2;
float y = (bitmap.getHeight() - textHeight)/2;
// draw text to the Canvas center
canvas.save();
canvas.translate(x, y);
textLayout.draw(canvas);
canvas.restore();
return bitmap;
}
source : http://www.skoumal.net/en/android-drawing-multiline-text-on-bitmap/
You should handle it yourself, calculating the text size and wrapping the content in some way (break line at max width or wrap last word).
I already did it on Java SE with the FontMetrics, never for Android; but you should take a look:
http://developer.android.com/reference/android/graphics/Paint.FontMetrics.html
As pointed by Lisa, StaticLayout is the way to go to measure text wrapping.

Categories

Resources