Rounded corner google map android? [duplicate] - android

I want to give the map a nice looking rounded corners as the two boxes below it have.
I can't do it with the map fragment it self because there is not a background property to a
fragment.
setting the map inside a layout and setting it background to a rounded shape didn't help me
as well and this is the result:
I could merge the map but this would make it smaller and i would like to avoid it.
EDIT:
#Ryan this is the new result #2:
I guess this is not bad, no even close to the corners on the other boxes,
but still not bad with a little more work a could get somewhere close i just dont have a normal image editor.
but one thing that still bothers me now is the separation between the "Location" Textview and the map it's self. could i painted the patch in other way so that there was now distance? this is how i did it:
Well I have finally figured this out:
this is what i used for the patch:
Thanks.

I know it's an old post, but you can try using Cards like so:
<android.support.v7.widget.CardView
android:layout_width="300dp"
android:layout_height="350dp"
android:layout_gravity="center_horizontal|center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
app:cardCornerRadius="12dp"
app:cardElevation="12dp">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v7.widget.CardView>

I haven't tried this, but I'd put a view with rounded corners and a transparent middle on top of the mapView / mapFragment.
That is, put the mapFragment and the rounded corner view in a FrameLayout with both filling the FrameLayout, then make the middle of the rounded corner view transparent.
For further clarification, you could do it in a layout as follows:-
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="#+id/mapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/rounded_background"
android:orientation="vertical" >
</LinearLayout>
</FrameLayout>
The rounded_background is a 9-patch with rounded corners and a transparent middle. E.g.
Hope that helps,
Ryan

The easiest way is to wrap the map fragment inside a FrameLayout along with an ImageView. The Imageview would display a rounded rectangle on top of the map fragment. In its simplest form you will see the map fragment inside the rounded rectangle with its corners sticking out of the rounded rectangle because the map view itself is not rounded. To overcome this visual oddity simply apply a layout_margin value on map fragment. The value should be equal to the rectangle's border width.
<FrameLayout
android:id="#+id/map_container"
android:layout_width="wrap_content"
android:layout_height="340dp" >
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="3dp"
android:name="com.google.android.gms.maps.SupportMapFragment"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/map_bg_box" />
</FrameLayout>
The rectangle drawable is defined as an xml shape as below
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="3dp"
android:color="#ff000000" />
<corners android:bottomRightRadius="7dp" android:bottomLeftRadius="7dp"
android:topLeftRadius="7dp" android:topRightRadius="7dp"/>
</shape>
Notice the stroke width of the rectangle is 3dp that is exactly the same value we applied to the layout_margin property of the map fragment. The result is a nicely round cornered map fragment as shown in the screenshot below

Wrap the map fragment in this layout:
package com.example.yourpackage;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
/**
* Just extend any Layout you like/need
*/
public class RoundedLayout extends RelativeLayout {
private Path mPathCorners = new Path();
private Path mPathCircle = new Path();
private float mCornerRadius;
/**
* border path
*/
private Path mPathCornersBorder = new Path();
private Path mPathCircleBorder = new Path();
private int mBorderWidth = 0;
private int mBorderHalf;
private boolean mShowBorder = false;
private int mBorderColor = 0xFFFF7700;
private float mDensity = 1.0f;
/**
* Rounded corners or circle shape
*/
private boolean mIsCircleShape = false;
private Paint mPaint = new Paint();
private float dpFromPx(final float px) {
return px / mDensity;
}
private float pxFromDp(final float dp) {
return dp * mDensity;
}
public RoundedLayout(Context context) {
this(context, null);
}
public RoundedLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundedLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDensity = getResources().getDisplayMetrics().density;
// just a default for corner radius
mCornerRadius = pxFromDp(25f);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(mBorderColor);
setBorderWidth(Math.round(pxFromDp(2f)));
}
/**
* Switch to circle or rectangle shape
*
* #param useCircle
*/
public void setShapeCircle(boolean useCircle) {
mIsCircleShape = useCircle;
invalidate();
}
/**
* change corner radius
*
* #param radius
*/
public void setCornerRadius(int radius) {
mCornerRadius = radius;
invalidate();
}
public void showBorder(boolean show) {
mShowBorder = show;
invalidate();
}
public void setBorderWidth(int width) {
mBorderWidth = width;
mBorderHalf = Math.round(mBorderWidth / 2);
if (mBorderHalf == 0) {
mBorderHalf = 1;
}
mPaint.setStrokeWidth(mBorderWidth);
updateCircleBorder();
updateRectangleBorder();
invalidate();
}
public void setBorderColor(int color) {
mBorderColor = color;
mPaint.setColor(color);
invalidate();
}
// helper reusable vars, just IGNORE
private float halfWidth, halfHeight, centerX, centerY;
private RectF rect = new RectF(0, 0, 0, 0);
private RectF rectBorder = new RectF(0, 0, 0, 0);
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// just calculate both shapes, is not heavy
// rounded corners path
rect.left = 0;
rect.top = 0;
rect.right = w;
rect.bottom = h;
mPathCorners.reset();
mPathCorners.addRoundRect(rect, mCornerRadius, mCornerRadius, Path.Direction.CW);
mPathCorners.close();
// circle path
halfWidth = w / 2f;
halfHeight = h / 2f;
centerX = halfWidth;
centerY = halfHeight;
mPathCircle.reset();
mPathCircle.addCircle(centerX, centerY, Math.min(halfWidth, halfHeight), Path.Direction.CW);
mPathCircle.close();
updateRectangleBorder();
updateCircleBorder();
}
// helper reusable var, just IGNORE
private int save;
#Override
protected void dispatchDraw(Canvas canvas) {
save = canvas.save();
canvas.clipPath(mIsCircleShape ? mPathCircle : mPathCorners);
super.dispatchDraw(canvas);
canvas.restoreToCount(save);
if (mShowBorder) {
canvas.drawPath(mIsCircleShape ? mPathCircleBorder : mPathCornersBorder, mPaint);
}
}
private void updateCircleBorder() {
// border path for circle
mPathCircleBorder.reset();
mPathCircleBorder.addCircle(centerX, centerY, Math.min(halfWidth - mBorderHalf,
halfHeight - mBorderHalf), Path.Direction.CW);
mPathCircleBorder.close();
}
private void updateRectangleBorder() {
// border path for rectangle
rectBorder.left = rect.left + mBorderHalf;
rectBorder.top = rect.top + mBorderHalf;
rectBorder.right = rect.right - mBorderHalf;
rectBorder.bottom = rect.bottom - mBorderHalf;
mPathCornersBorder.reset();
mPathCornersBorder.addRoundRect(rectBorder, mCornerRadius - mBorderHalf, mCornerRadius -
mBorderHalf, Path.Direction.CW);
mPathCornersBorder.close();
}
}
In layout will be like this:
<com.example.yourpackage.RoundedLayout
android:id="#+id/maplayout"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_margin="20dp">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="200dp"
tools:context="com.example.yourpackage.MapsMarkerActivity"/>
</com.example.yourpackage.RoundedLayout>
In code can be like this for a round shape with border:
RoundedLayout rl = (RoundedLayout) findViewById(R.id.maplayout);
rl.setShapeCircle(true);
rl.showBorder(true);
rl.setBorderWidth(2);
This layout can be used to shape any view.
It's incredible how google is incapable of making competent (usable) complete demos for it's android API.

For other people looking into this, I just tackled this using GoogleMap.snapshot and manipulating the bitmap result with this stack over flow answer:
How to make an ImageView with rounded corners?
Mind you this is only valid if you are going to have a static map that is not going to be interacted with.
Make sure you take the snap shot after the map is loaded.
I updated the image view helper code to draw with path to support rounding only some corners. ie. If you want to round only 2 of the corners.
You just need the path round rect function that takes a float[]
I show a progress bar until I get a callback from GoogleMap loaded listener than I take the snapshot.
If you take your snapshot too early you will get can't create bitmap with 0 width and height error.
Hope this helps someone looking for rounded corners or other weird shape in static map snapshot.

If you are only trying to target API 21 (Lollipop) and higher
This is the easiest way possible.
parentView.setClipToOutline(true);
Result

Following #Nouman_Hanif post I ended up with a solution that looks quite good.
map_rounded_corner_overlay.xml:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="1dp"
android:color="#color/white" />
<corners android:radius="<your_desired_view_corner_radius>"/>
</shape>
My map xml file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_margin="1dp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/map_rounded_corner_overlay" />
</RelativeLayout>

Related

Unable to get exact circle shape when using card view

I'm using card view for floating action button in android material design. I'm using following code for get the circle
<android.support.v7.widget.CardView
android:id="#+id/fab"
android:layout_width="38dp"
android:layout_height="38dp"
android:layout_marginBottom="10dp"
android:layout_marginRight="10dp"
card_view:background="#color/blue"
card_view:cardCornerRadius="19dp"
card_view:cardPreventCornerOverlap = "false"
card_view:cardElevation="6dp" >
</android.support.v7.widget.CardView>
I have set corner radius as half of width. but still I can't get the circle shape.
To achieve a circular shape using Card view you can set the shape property, android:shape="ring". app:cardCornerRadius should be set to half the width or height of the child view
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:innerRadius="0dp"
android:shape="ring"
app:cardCornerRadius="75dp">
<ImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center"
android:background="#drawable/image" />
</android.support.v7.widget.CardView>
I have solved the problem. Now android providing design library for material design, which has the FloatingActionButton. No need of customizing card view for floating action button.
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin" />
Add design library in gradle dependencies
compile 'com.android.support:design:23.1.1'
For more detail refer this link
To get a perfect circle shape using a card view, corner radius should be 1/2 of width or height (taking into consideration that it is a square). also, I have noticed that you are using card_view params, don't.
<android.support.v7.widget.CardView
android:layout_width="38dp"
android:layout_height="38dp"
app:cardCornerRadius="19dp"
app:cardElevation="6dp"
android:layout_marginBottom="10dp"
android:layout_marginRight="10dp"
android:id="#+id/fab"
android:background="#color/blue"
>
use
shape = "ring"
use same layout_height and layout_weight
and
app:cardCornerRadius= half of layout_height or layout_weight
example
<android.support.v7.widget.CardView
android:id="#+id/cardview"
android:layout_width="110dp"
android:layout_height="110dp"
android:shape="ring"
app:cardCornerRadius="55dp">
</android.support.v7.widget.CardView>
<androidx.cardview.widget.CardView
android:layout_width="60dp"
android:layout_marginStart="150dp"
app:cardCornerRadius="360dp"
android:layout_height="60dp">
I came up with simple Solution of Using a Drawable and it looks amazing!
Get Drawable here
https://drive.google.com/drive/folders/0B4Vo_ku-aIKzUFFnUjYxYVRLaGc?resourcekey=0-RiH8lUO0i1kwnZsqquqjnQ&usp=sharing
I tried your code and found out that the Cards were less round with respect to the increase in the card elevation value.Try setting it to zero and this at least makes it look better.
card_view:cardElevation="0dp";
But a probably better option would be to use the FloatingActionButton for the round button
<android.support.design.widget.FloatingActionButton
android:src="#drawable/your_drawble_name"
app:fabSize="normal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
add this line to the CardView which sets the cardCornerRadius to the Circle diameter.
app:cardCornerRadius="360dp"
Yes, I have achieved it by reducing half of the CardCornerRadius to its View's Height.
card_layout.xml
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_view"
android:layout_gravity="center"
android:layout_width="250dp"
android:layout_height="200dp">
<ImageView
android:id="#+id/card_thumbnail_image"
android:layout_height="match_parent"
android:layout_width="match_parent"
style="#style/card_thumbnail_image"/>
</android.support.v7.widget.CardView>
MainActivity.java
ImageView imageView = (ImageView) findViewById(R.id.card_thumbnail_image);
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.rose);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
//Default
imageView.setBackgroundResource(R.drawable.rose);
} else {
//RoundCorners
RoundCornersDrawable round = new RoundCornersDrawable(mBitmap,
getResources().getDimension(R.dimen.cardview_default_radius), 0); //or your custom radius
CardView cardView = (CardView) findViewById(R.id.card_view);
cardView.setPreventCornerOverlap(false); //it is very important
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
imageView.setBackground(round);
else
imageView.setBackgroundDrawable(round);
}
RoundCornersDrawable.java
public class RoundCornersDrawable extends Drawable {
private final float mCornerRadius;
private final RectF mRect = new RectF();
//private final RectF mRectBottomR = new RectF();
//private final RectF mRectBottomL = new RectF();
private final BitmapShader mBitmapShader;
private final Paint mPaint;
private final int mMargin;
public RoundCornersDrawable(Bitmap bitmap, float cornerRadius, int margin) {
mCornerRadius = cornerRadius;
mBitmapShader = new BitmapShader(bitmap,
Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setShader(mBitmapShader);
mMargin = margin;
}
#Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mRect.set(mMargin, mMargin, bounds.width() - mMargin, bounds.height() - mMargin);
//mRectBottomR.set( (bounds.width() -mMargin) / 2, (bounds.height() -mMargin)/ 2,bounds.width() - mMargin, bounds.height() - mMargin);
// mRectBottomL.set( 0, (bounds.height() -mMargin) / 2, (bounds.width() -mMargin)/ 2, bounds.height() - mMargin);
}
#Override
public void draw(Canvas canvas) {
canvas.drawRoundRect(mRect, mCornerRadius, mCornerRadius, mPaint);
//canvas.drawRect(mRectBottomR, mPaint); //only bottom-right corner not rounded
//canvas.drawRect(mRectBottomL, mPaint); //only bottom-left corner not rounded
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
#Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter cf) {
mPaint.setColorFilter(cf);
}
}
first import the drawbleToolBox library in your project.
with this library, you can create drawable dynamically.
for make your cardview circle your radius must be half of its height/widht.
int radius = cardView.getHeight()/2;
Drawable drawable = new DrawableBuilder()
.rectangle()
.solidColor(0xffffffff)
.topRightRadius(radius) // in pixels
.bottomRightRadius(radius)
//otherplaces
.build();
holder.cardView.setBackground(drawable);
if you are using cardview in your recycleview, getting the cardview widths doesn't work
becuse it doesn't create yet. so you should do as below
holder.cardView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
{
#Override
public boolean onPreDraw()
{
//codes here.
}
}
Using CardView to obtain circular background with shadow can be quiet troublesome intead use layer-list in drawable to get the desired output.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<!--shadow color you want-->
<solid android:color="#C3C1C1"/>
</shape>
</item>
<item
android:left="0dp"
android:right="0dp"
android:top="0dp"
android:bottom="2dp">
<shape android:shape="oval">
<solid android:color="#color/white"/>
</shape>
</item>
</layer-list>

Button Layout with Profile Picture Alignment

I want to create buttons that look like in the picture. Inside the circle (which is transparent in the png) I want to place the profile picture of players. There should also be text on the blue bar.
I've got it working but it just seems way too complicated. I think it is easier to understand what I have done without giving code but if you need it I can add it. Here is the layout:
RelativeLayout
LinearLayout (horizontal orientation)
Empty view with weight 0.7
Profile Picture with weight 0.2
Empty view with weight 0.1
the overlay picture that I posted below
LinearLayout (horizontal orientation)
RelativeLayout with weight 0.7 (space where all the text can go)
empty view with weigh 0.3
By the way: to the right of the circle, the png isn't transparent but white!
This works well but there must be a better way! All these empty views just to align the picture to the right position is kind of ugly. And the fact that the overlay picture must go inbetween the profile picture and the text makes it even uglier.
I'd prefer to do it without a png as overlay but with simple shapes (so that it looks good on every screen) but I wouldn't know how to do that. Would you recommend that? And if yes, how could that be done?
Or do you have an idea how to improve the xml layout or how to do it otherwise.
Thanks very much
You can do it without any image:
Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:weightSum="1.0">
<TextView
android:layout_weight="0.7"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="New Text"
android:id="#+id/textView"
android:background="#0073ff"/>
<ImageView
android:layout_weight="0.2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="#drawable/half_round_drawable"
android:src="#drawable/profile"/>
</LinearLayout>
</LinearLayout>
half_round_drawable:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="oval">
<corners android:radius="16dp" />
<solid android:color="#0073ff" />
</shape>
</item>
<item
android:bottom="0dp"
android:right="32dp"> <!-- radius *2 -->
<shape>
<solid android:color="#0073ff" />
</shape>
</item>
</layer-list>
To make the profile-image round you should use something like this:
How to create a circular ImageView in Android?
You can use a simple LinearLayout if you confine the background image to the profile area at the right side. You can define the content area in the image itself if you use a nine-patch drawable, as follows:
Extract the profile portion from your background image file.
Create a nine patch drawable from it, defining all the area as stretchable (left and top border lines), and the empty circle as the content area (right and bottom lines).
Since you should ideally have the image at the foreground layer to ensure that the photo isn't drawn outside of the circle, you can use a FrameLayout with a foreground drawable to contain your profile photo's ImageView. There would also need to be another dummy child view to work around a bug in FrameLayout that causes a single child with match_parent dimensions to be layout incorrectly.
This is how the layout should look like at the end:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#00f" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:foreground="#drawable/profile_bg">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="#+id/photo"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</LinearLayout>
Now I am ready to present my answer.
Portret:
Landscape:
Layout.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:shape="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<!--This is the CustomView which include -->
<!--own attributes: -->
<!--circle_radius is the radius of image, -->
<!--content_padding is the padding,-->
<!--and background_color is the color of shape.-->
<CustomShape
android:layout_width="match_parent"
android:layout_height="wrap_content"
shape:circle_radius="40dp"
shape:content_padding="8dp"
shape:background_color="#FF983493">
<!--There must be two Views:-->
<!--TextView and ImageView and only in this order.-->
<!--Set-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--to bot of them, because in CustomShape it will be-->
<!--resized for you. There also don`t need to set -->
<!--any kind of margin or location attributes.-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/txt"
android:padding="5dp"
android:textColor="#android:color/white"
android:text="sdsfkjsdkfhsdk flsdkfjkls asdfasd fklasdjl fkjasdklfjasd k "
android:background="#android:color/transparent"/>
<!--For RoundImage I use custom class which round the drawable,-->
<!--not a View. Look down.-->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/img"
android:src="#drawable/img"
android:scaleType="fitCenter"
android:background="#android:color/transparent" />
</CustomShape>
</RelativeLayout>
CustomShape class:
public class CustomShape extends RelativeLayout {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
int circleRadius; // image radius
int diameter; // image diameter
int contentPadding;
int semiPadding;
int rectRightSide;
int backgroundColor;
int viewWidth; // width of parent(CustomShape layout)
public CustomShape(Context context) {
super(context);
this.setWillNotDraw(false);
}
public CustomShape(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomShape, 0, 0);
try {
this.circleRadius = (int) ta.getDimension(R.styleable.CustomShape_circle_radius, 40);
this.contentPadding = (int) ta.getDimension(R.styleable.CustomShape_content_padding, 8);
this.backgroundColor = ta.getColor(R.styleable.CustomShape_background_color, 0);
this.semiPadding = contentPadding / 2;
this.diameter = circleRadius * 2;
} finally {
ta.recycle();
}
this.setWillNotDraw(false);
}
public CustomShape(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.setWillNotDraw(false);
}
#Override
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld) {
super.onSizeChanged(xNew, yNew, xOld, yOld);
viewWidth = xNew;
this.rectRightSide = viewWidth - circleRadius - (circleRadius / 2); // get position for image
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
ImageView img = (ImageView) this.getChildAt(1);
RelativeLayout.LayoutParams imgParams = new LayoutParams(diameter - contentPadding, diameter - contentPadding);
imgParams.leftMargin = rectRightSide - circleRadius + semiPadding;
imgParams.topMargin = semiPadding;
img.setLayoutParams(imgParams);
//Create custom RoundImage and set to image
try {
Drawable drawable = img.getDrawable();
Bitmap bm = ((BitmapDrawable) drawable).getBitmap();
RoundImage resultImage = new RoundImage(bm);
img.setImageDrawable(resultImage);
} catch (ClassCastException e) {
}
//Positioning and resizing TextView
View txt = this.getChildAt(0);
RelativeLayout.LayoutParams txtParams = new LayoutParams(rectRightSide - circleRadius - semiPadding, diameter - contentPadding);
txtParams.topMargin = semiPadding;
txtParams.leftMargin = semiPadding;
txt.setLayoutParams(txtParams);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
this.setMeasuredDimension(parentWidth, diameter); // set correct height
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(backgroundColor);
canvas.drawRect(0, 0, rectRightSide, diameter, paint);
//Draw circle
paint.setDither(true);
canvas.drawCircle(rectRightSide, circleRadius, circleRadius, paint);
}
}
Attr.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomShape">
<attr name="circle_radius" format="dimension" />
<attr name="content_padding" format="dimension" />
<attr name="background_color" format="color" />
</declare-styleable>
</resources>
RoundImage class:
public class RoundImage extends Drawable {
private final Bitmap mBitmap;
private final Paint mPaint;
private final RectF mRectF;
private final int mBitmapWidth;
private final int mBitmapHeight;
public RoundImage(Bitmap bitmap) {
mBitmap = bitmap;
mRectF = new RectF();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
final BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(shader);
mBitmapWidth = mBitmap.getWidth();
mBitmapHeight = mBitmap.getHeight();
}
#Override
public void draw(Canvas canvas) {
canvas.drawOval(mRectF, mPaint);
}
#Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mRectF.set(bounds);
}
#Override
public void setAlpha(int alpha) {
if (mPaint.getAlpha() != alpha) {
mPaint.setAlpha(alpha);
invalidateSelf();
}
}
#Override
public void setColorFilter(ColorFilter cf) {
mPaint.setColorFilter(cf);
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
#Override
public int getIntrinsicWidth() {
return mBitmapWidth;
}
#Override
public int getIntrinsicHeight() {
return mBitmapHeight;
}
public void setAntiAlias(boolean aa) {
mPaint.setAntiAlias(aa);
invalidateSelf();
}
#Override
public void setFilterBitmap(boolean filter) {
mPaint.setFilterBitmap(filter);
invalidateSelf();
}
#Override
public void setDither(boolean dither) {
mPaint.setDither(dither);
invalidateSelf();
}
public Bitmap getBitmap() {
return mBitmap;
}
}
Hope it will help you.

Drawing background shape with one corner and two cutting edges - Android

I want to draw a shape to set it as background. the shape has one corner and two cutting edges.
Here is the rough diagram of the shape I want with one round corner and two corners joined with straight line. I am using and to draw it. Could you help on this ?
A 9-patch bitmap (as per UDI's answer) is probably the easiest, but if you want to do it in code, create a custom Shape:
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.shapes.Shape;
import android.graphics.RectF;
public class WeirdShape extends Shape {
private static final int COLOUR = Color.RED;
private static final float STROKE_WIDTH = 1.0f;
private static final float CORNER = 10.0f;
private final Paint border = new Paint();
private final Path path;
public WeirdShape() {
path = new Path();
border.setColor (COLOUR);
border.setStyle (Paint.Style.STROKE);
border.setStrokeWidth(STROKE_WIDTH);
border.setAntiAlias (true);
border.setDither (true);
border.setStrokeJoin (Paint.Join.ROUND);
border.setStrokeCap (Paint.Cap.ROUND);
}
#Override
protected void onResize(float width, float height) {
super.onResize(width, height);
float dx = STROKE_WIDTH/2.0f;
float dy = STROKE_WIDTH/2.0f;
float x = dx;
float y = dy;
float w = width - dx;
float h = height - dy;
RectF arc = new RectF(x,h-2*CORNER,x+2*CORNER,h);
path.reset();
path.moveTo(x + CORNER,y);
path.lineTo(w - CORNER,y);
path.lineTo(w,y + CORNER);
path.lineTo(w, h);
path.lineTo(x + CORNER,h);
path.arcTo (arc,90.0f,90.0f);
path.lineTo(dx,h - CORNER);
path.lineTo(dx,y + CORNER);
path.close();
}
#Override
public void draw(Canvas canvas, Paint paint) {
canvas.drawPath(path,border);
}
}
and then use the custom Shape in a ShapeDrawable as the background Drawable:
view.setBackground(new ShapeDrawable(new WeirdShape()));
Which looks something like:
There is no facility in ShapeDrawables for cutting the corner of a square like you have proposed. There is a 'radius' component.
You could try creating multiple images and stacking them on top of each other (using a LayeredList Drawable), but this is likely complicated, and will for sure cause overdraw (ie. bad drawing performance).
Your other alternative is to use the Paint API to create whatever image you want, which can then be cached, and used however.
put this in drawable like rounded_edittext.xml -->
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" android:padding="10dp">
<solid android:color="#FFFFFF"/>
<corners
android:bottomRightRadius="0dp"
android:bottomLeftRadius="15dp"
android:topLeftRadius="10dp"
android:topRightRadius="5dp"/>
</shape>
call drawable as edittext background
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dip"
android:background="#drawable/rounded_edittext" />
</LinearLayout>
I would say use photoshop to get the aspects right and use it as png drawable

Custom shape does not appear in RelativeLayout

I have the following problem with my application: I have created a custom View Class:
private class MyCustomPanel extends View {
private int width;
private int height;
public MyCustomPanel(Context context,int width,int height)
{
super(context);
this.height=height;
this.width=width;
}
#Override
public void draw(Canvas canvas) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(getResources().getColor(R.color.pending));
float radius=(height)/2;
float center_x = (width)/2;
float center_y = (height)/2;
Log.d("DEBUG","R="+radius+" cx="+center_x+" cy="+center_y);
final RectF oval = new RectF();
oval.set(center_x- radius,
center_y - radius,
center_x + radius,
center_y + radius);
//Draw a left semicircle
canvas.drawArc(oval, 90, 180, false, paint);
}
}
This class is an inner class and I am trying to add in it a RelativeLayout in front of a Button.
I have successfully tried to add it to another layout, so it is added and drawn correctly (see here screenshot).
In the previous case the draw function is called and the semicircle is drawn.
In the following though the draw function is not called..
I use this code:
ViewGroup p=(ViewGroup)button.getParent();
MyCustomPanel c=new MyCustomPanel(p.getContext(),p.getWidth(),p.getHeight());
((ViewGroup)p.findViewById(R.id.semicircleFrame)).addView(c);
and the XML in of the RelatedLayout is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/button_selector"
android:id="#+id/frame">
<Button
android:id="#+id/button"
android:layout_gravity="center"
android:textColor="#FFFFFF"
android:background="#drawable/calendar_button_selector"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
</Button>
<RelativeLayout
android:id="#+id/semicircleFrame"
android:layout_width="match_parent"
android:layout_height="fill_parent"
>
</RelativeLayout>
</RelativeLayout>
The hierarchy viewer shows the following:
screenshot
I have also try to add it directly to the parent frame but the same.
Please Help me
I also had problems with a view in Relative layout thatwas dependent on the Relative layout's size.
I solved this problem problematically by updating the inner view size
private void updateViewSize()
if(rootContainer == null || rootContainer.getLayoutParams() == null)
return;
rootContainer.measure(View.MeasureSpec.makeMeasureSpec(ScalingUtil.getScreenSize().getWidth(), View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT, View.MeasureSpec.EXACTLY));
RelativeLayout.LayoutParams oldLayoutParams = (RelativeLayout.LayoutParams) rootContainer.findViewById(R.id.deals_card_center_bg).getLayoutParams();
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(rootContainer.getMeasuredWidth(), rootContainer.getMeasuredHeight());
layoutParams.setMargins(oldLayoutParams.leftMargin, oldLayoutParams.topMargin, oldLayoutParams.rightMargin, oldLayoutParams.bottomMargin);
rootContainer.findViewById(R.id.deals_card_center_bg).setLayoutParams(layoutParams);

Is there a way to implement rounded corners to a Mapfragment?

I want to give the map a nice looking rounded corners as the two boxes below it have.
I can't do it with the map fragment it self because there is not a background property to a
fragment.
setting the map inside a layout and setting it background to a rounded shape didn't help me
as well and this is the result:
I could merge the map but this would make it smaller and i would like to avoid it.
EDIT:
#Ryan this is the new result #2:
I guess this is not bad, no even close to the corners on the other boxes,
but still not bad with a little more work a could get somewhere close i just dont have a normal image editor.
but one thing that still bothers me now is the separation between the "Location" Textview and the map it's self. could i painted the patch in other way so that there was now distance? this is how i did it:
Well I have finally figured this out:
this is what i used for the patch:
Thanks.
I know it's an old post, but you can try using Cards like so:
<android.support.v7.widget.CardView
android:layout_width="300dp"
android:layout_height="350dp"
android:layout_gravity="center_horizontal|center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
app:cardCornerRadius="12dp"
app:cardElevation="12dp">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v7.widget.CardView>
I haven't tried this, but I'd put a view with rounded corners and a transparent middle on top of the mapView / mapFragment.
That is, put the mapFragment and the rounded corner view in a FrameLayout with both filling the FrameLayout, then make the middle of the rounded corner view transparent.
For further clarification, you could do it in a layout as follows:-
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="#+id/mapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/rounded_background"
android:orientation="vertical" >
</LinearLayout>
</FrameLayout>
The rounded_background is a 9-patch with rounded corners and a transparent middle. E.g.
Hope that helps,
Ryan
The easiest way is to wrap the map fragment inside a FrameLayout along with an ImageView. The Imageview would display a rounded rectangle on top of the map fragment. In its simplest form you will see the map fragment inside the rounded rectangle with its corners sticking out of the rounded rectangle because the map view itself is not rounded. To overcome this visual oddity simply apply a layout_margin value on map fragment. The value should be equal to the rectangle's border width.
<FrameLayout
android:id="#+id/map_container"
android:layout_width="wrap_content"
android:layout_height="340dp" >
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="3dp"
android:name="com.google.android.gms.maps.SupportMapFragment"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/map_bg_box" />
</FrameLayout>
The rectangle drawable is defined as an xml shape as below
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="3dp"
android:color="#ff000000" />
<corners android:bottomRightRadius="7dp" android:bottomLeftRadius="7dp"
android:topLeftRadius="7dp" android:topRightRadius="7dp"/>
</shape>
Notice the stroke width of the rectangle is 3dp that is exactly the same value we applied to the layout_margin property of the map fragment. The result is a nicely round cornered map fragment as shown in the screenshot below
Wrap the map fragment in this layout:
package com.example.yourpackage;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
/**
* Just extend any Layout you like/need
*/
public class RoundedLayout extends RelativeLayout {
private Path mPathCorners = new Path();
private Path mPathCircle = new Path();
private float mCornerRadius;
/**
* border path
*/
private Path mPathCornersBorder = new Path();
private Path mPathCircleBorder = new Path();
private int mBorderWidth = 0;
private int mBorderHalf;
private boolean mShowBorder = false;
private int mBorderColor = 0xFFFF7700;
private float mDensity = 1.0f;
/**
* Rounded corners or circle shape
*/
private boolean mIsCircleShape = false;
private Paint mPaint = new Paint();
private float dpFromPx(final float px) {
return px / mDensity;
}
private float pxFromDp(final float dp) {
return dp * mDensity;
}
public RoundedLayout(Context context) {
this(context, null);
}
public RoundedLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundedLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDensity = getResources().getDisplayMetrics().density;
// just a default for corner radius
mCornerRadius = pxFromDp(25f);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(mBorderColor);
setBorderWidth(Math.round(pxFromDp(2f)));
}
/**
* Switch to circle or rectangle shape
*
* #param useCircle
*/
public void setShapeCircle(boolean useCircle) {
mIsCircleShape = useCircle;
invalidate();
}
/**
* change corner radius
*
* #param radius
*/
public void setCornerRadius(int radius) {
mCornerRadius = radius;
invalidate();
}
public void showBorder(boolean show) {
mShowBorder = show;
invalidate();
}
public void setBorderWidth(int width) {
mBorderWidth = width;
mBorderHalf = Math.round(mBorderWidth / 2);
if (mBorderHalf == 0) {
mBorderHalf = 1;
}
mPaint.setStrokeWidth(mBorderWidth);
updateCircleBorder();
updateRectangleBorder();
invalidate();
}
public void setBorderColor(int color) {
mBorderColor = color;
mPaint.setColor(color);
invalidate();
}
// helper reusable vars, just IGNORE
private float halfWidth, halfHeight, centerX, centerY;
private RectF rect = new RectF(0, 0, 0, 0);
private RectF rectBorder = new RectF(0, 0, 0, 0);
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// just calculate both shapes, is not heavy
// rounded corners path
rect.left = 0;
rect.top = 0;
rect.right = w;
rect.bottom = h;
mPathCorners.reset();
mPathCorners.addRoundRect(rect, mCornerRadius, mCornerRadius, Path.Direction.CW);
mPathCorners.close();
// circle path
halfWidth = w / 2f;
halfHeight = h / 2f;
centerX = halfWidth;
centerY = halfHeight;
mPathCircle.reset();
mPathCircle.addCircle(centerX, centerY, Math.min(halfWidth, halfHeight), Path.Direction.CW);
mPathCircle.close();
updateRectangleBorder();
updateCircleBorder();
}
// helper reusable var, just IGNORE
private int save;
#Override
protected void dispatchDraw(Canvas canvas) {
save = canvas.save();
canvas.clipPath(mIsCircleShape ? mPathCircle : mPathCorners);
super.dispatchDraw(canvas);
canvas.restoreToCount(save);
if (mShowBorder) {
canvas.drawPath(mIsCircleShape ? mPathCircleBorder : mPathCornersBorder, mPaint);
}
}
private void updateCircleBorder() {
// border path for circle
mPathCircleBorder.reset();
mPathCircleBorder.addCircle(centerX, centerY, Math.min(halfWidth - mBorderHalf,
halfHeight - mBorderHalf), Path.Direction.CW);
mPathCircleBorder.close();
}
private void updateRectangleBorder() {
// border path for rectangle
rectBorder.left = rect.left + mBorderHalf;
rectBorder.top = rect.top + mBorderHalf;
rectBorder.right = rect.right - mBorderHalf;
rectBorder.bottom = rect.bottom - mBorderHalf;
mPathCornersBorder.reset();
mPathCornersBorder.addRoundRect(rectBorder, mCornerRadius - mBorderHalf, mCornerRadius -
mBorderHalf, Path.Direction.CW);
mPathCornersBorder.close();
}
}
In layout will be like this:
<com.example.yourpackage.RoundedLayout
android:id="#+id/maplayout"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_margin="20dp">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="200dp"
tools:context="com.example.yourpackage.MapsMarkerActivity"/>
</com.example.yourpackage.RoundedLayout>
In code can be like this for a round shape with border:
RoundedLayout rl = (RoundedLayout) findViewById(R.id.maplayout);
rl.setShapeCircle(true);
rl.showBorder(true);
rl.setBorderWidth(2);
This layout can be used to shape any view.
It's incredible how google is incapable of making competent (usable) complete demos for it's android API.
For other people looking into this, I just tackled this using GoogleMap.snapshot and manipulating the bitmap result with this stack over flow answer:
How to make an ImageView with rounded corners?
Mind you this is only valid if you are going to have a static map that is not going to be interacted with.
Make sure you take the snap shot after the map is loaded.
I updated the image view helper code to draw with path to support rounding only some corners. ie. If you want to round only 2 of the corners.
You just need the path round rect function that takes a float[]
I show a progress bar until I get a callback from GoogleMap loaded listener than I take the snapshot.
If you take your snapshot too early you will get can't create bitmap with 0 width and height error.
Hope this helps someone looking for rounded corners or other weird shape in static map snapshot.
If you are only trying to target API 21 (Lollipop) and higher
This is the easiest way possible.
parentView.setClipToOutline(true);
Result
Following #Nouman_Hanif post I ended up with a solution that looks quite good.
map_rounded_corner_overlay.xml:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="1dp"
android:color="#color/white" />
<corners android:radius="<your_desired_view_corner_radius>"/>
</shape>
My map xml file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_margin="1dp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/map_rounded_corner_overlay" />
</RelativeLayout>

Categories

Resources