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);
Related
I have a card and want to add content to it. How should I add images and also Text to the card? Here is my xml code:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="ml.vedantk.app.god.MainActivity">
<android.support.v7.widget.CardView
android:id="#+id/card1"
android:layout_width="364dp"
android:layout_height="389dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="64dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
Here is the java file:
package ml.vedantk.app.god;
import android.support.annotation.ColorInt;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.CardView;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CardView card1 = (CardView)findViewById(R.id.card1);
card1.setCardBackgroundColor(100);
}
}
The card1.setCardBackgroundColor(100); also did not change the background color. So can anybody help me add an image?
Image can't be set as Background Image For a Card View.But You can Use Background Color using setCardBackgroundColor(ContextCompat.getColor(this, R.color.colorPrimary))
If you want to set a background Image Inside Cardview Use Another Layout such as LinearLayout, RelativeLayout or any other Inside The CardView. And Add Background for that Layout. This is one of the easy way to set BackgroundImage for CardView
You can do this without losing your cardcorner radius.
Here's my XML :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:background="#drawable/zoneback"
android:layout_height="match_parent"
tools:context=".kidzone">
<android.support.v7.widget.CardView
android:layout_marginTop="75dp"
android:id="#+id/quizcard"
android:elevation="15dp"
app:cardPreventCornerOverlap="false"
android:layout_width="match_parent"
app:cardCornerRadius="50dp"
android:layout_marginHorizontal="50dp"
android:layout_height="250dp">
<ImageView
android:layout_width="match_parent"
android:id="#+id/quizimage"
android:layout_height="match_parent" />
</android.support.v7.widget.CardView>
</LinearLayout>
You will have to create a custom Drawable :
public class RoundCornerDrawable 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 RoundCornerDrawable(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);
}
}
Finally, here's my activity code :
RoundCornerDrawable round = new RoundCornerDrawable(BitmapFactory.decodeResource(getResources(),R.drawable.quizcardback),
getResources().getDimension(R.dimen.cardview_radius), 0);
ImageView imageView=root.findViewById(R.id.quizimage);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
imageView.setBackground(round);
else
imageView.setBackgroundDrawable(round);
I am using the card background drawable as following.
<androidx.cardview.widget.CardView
android:layout_width="100dp"
android:layout_height="75dp"
android:layout_margin="8dp"
android:elevation="8dp"
app:cardCornerRadius="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/event"></LinearLayout>
</androidx.cardview.widget.CardView>
In order to set background image of card, we have to add relative or LinearLayout.
Add RelativeLayout after Cardview declarations such that you can able to move elements within the cards.
3.Add the following code/Sample is as Follows
android:layout_width="match_parent"
android:layout_height="489dp"
android:layout_margin="10dp"
android:orientation="vertical"
app:cardBackgroundColor="#color/cardview"
app:cardCornerRadius="7dp"
app:cardElevation="4dp"
app:cardPreventCornerOverlap="false">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#drawable/background">
4.Where android:background="#drawable/background"> is my image name.
Did you try this?
card1.setBackgroundResource(R.drawable.yourimage);
I know its to late for answer but i have easy and smart way for you
make a card view and then make another viewgroup in it
then add backgroundTint for your card view and put the opacity to 0
and then set background image for your other layout you just define in your card view.
I want to make the design like image and also display same in phone and 7 inch tab.
I am using Linear layout by dividing the view in 5 part of the screen with using Framlayout draw a line but not possible to achieve like this image.
What's the other option like using canvas or any other better option.
First Image is displing expected result.
and other two are getting result.
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<gradient
android:angle="360.0"
android:endColor="#A29AA4"
android:startColor="#A29AA4" />
</shape>
Below layout
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="5">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<View
android:id="#+id/mView_circle1"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="#drawable/circleshape" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<View
android:id="#+id/mView_circle2"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="#drawable/circleshape" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<View
android:id="#+id/mView_circle3"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="#drawable/circleshape" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<View
android:id="#+id/mView_circle4"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="#drawable/circleshape" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<View
android:id="#+id/mView_circle5"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="#drawable/circleshape" />
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="center_vertical"
android:background="#A29AA4">
</RelativeLayout>
</FrameLayout>
This is easier and cleaner in canvas. Here is how you would do the first one.. You can replicate this with slight modifications for the other two.
Create a Canvas View:
public class CanvasView extends View {
Paint bPaint;
RectF coordbounds;
public CanvasView(Context context) {
super(context);
}
private void init()
{
bPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bPaint.setStyle(Paint.Style.FILL_AND_STROKE);
bPaint.setColor(Color.BLACK);
}
#Override
public void onDraw(android.graphics.Canvas canvas)
{
super.onDraw(canvas);
canvas.drawLine(coordbounds.left,coordbounds.centerY(),
coordbounds.right,coordbounds.centerY(),bPaint);
int circledia=20;
//Divide the line into four segments and subtract 2 * half the radii
float actualspan = (coordbounds.right - coordbounds.left) - (2 * circledia/2);
//Segment the line into 3 parts
float interlinesegments = actualspan/(4-1);
for(int i=0; i<4;i++)
{
canvas.drawCircle(coordbounds.left + circledia/2 +
(i*interlinesegments),
coordbounds.centerY(),10,bPaint);
}
}
}
Create a layout to hold the view and call this view in your activity:
LinearLayout layout = (LinearLayout) findViewById(R.id.root);
CanvasView view = new CanvasView(this);
layout.addView(view);
oops, I forgot . :-) Please add this method in CanvasView class to declare the bounding box and set the layout:
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
float xpad = (float) (getPaddingLeft() + getPaddingRight());
float ypad = (float) (getPaddingTop() + getPaddingBottom());
float coww = 0.0f, cohh = 0.0f, coll = 0.0f;
init();
coww = (float) w - xpad;
cohh = (float) h - ypad;
// Create a bounding box
coordbounds = new RectF(0.0f,0.0f,
coww,cohh);
}
EDIT : Change the above methods for bitmap
private void init()
{
bPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bPaint.setStyle(Paint.Style.FILL_AND_STROKE);
bPaint.setColor(Color.BLACK);
bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.button);
}
Change onDraw as follows:
#Override
public void onDraw(android.graphics.Canvas canvas)
{
super.onDraw(canvas);
canvas.drawLine(coordbounds.left,coordbounds.centerY(),
coordbounds.right,coordbounds.centerY(),bPaint);
int rectwidth=bitmap.getWidth();
int rectheight=bitmap.getHeight();
//Divide the line into four segments and subtract 2 * half the radii
float actualspan = (coordbounds.right - coordbounds.left) - (2 * rectwidth/2);
//Segment the line into 3 parts
float interlinesegments = actualspan/(4-1);
for(int i=0; i<4;i++)
{
float left= coordbounds.left + (i * interlinesegments);
float top= coordbounds.centerY()-rectheight/2;
float right = coordbounds.left+(i * interlinesegments)+rectwidth;
float bottom= coordbounds.centerY()+ rectheight/2;
canvas.drawBitmap(bitmap,null,new RectF(left,top,right,bottom),null);
}
}
With the help of above code and previous code I made this Combination of circle shape and bitmap.
#Override
public void onDraw(android.graphics.Canvas canvas)
{
super.onDraw(canvas);
canvas.drawLine(coordbounds.left, coordbounds.centerY(),
coordbounds.right, coordbounds.centerY(), bPaint);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_myprofile);
int rectwidth=bitmap.getWidth();
int rectheight=bitmap.getHeight();
//Divide the line into four segments and subtract 2 * half the radii
float actualspan_image = (coordbounds.right - coordbounds.left) - (2 * rectwidth/2);
//Segment the line into 3 parts
float interlinesegments_bitmap = actualspan_image / (4 - 1);
int circledia = 20;
//Divide the line into four segments and subtract 2 * half the radii
float actualspan = (coordbounds.right - coordbounds.left) - (2 * circledia/2);
//Segment the line into 3 parts
float interlinesegments = actualspan/(4-1);
for(int i=0; i<4;i++)
{
float left= coordbounds.left + (i * interlinesegments_bitmap);
float top= coordbounds.centerY()-rectheight/2;
float right = coordbounds.left+(i * interlinesegments_bitmap)+rectwidth;
float bottom= coordbounds.centerY()+ rectheight/2;
if(i==1){
canvas.drawBitmap(bitmap,null,new RectF(left,top,right,bottom),null);
}else{
canvas.drawCircle(coordbounds.left + circledia / 2 +
(i * interlinesegments),
coordbounds.centerY(), 10, bPaint);
}
}
}
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>
I want to draw dynamically a circle on top of a drawable. So i created this class:
public class CustomTextViewDrawable extends LayerDrawable {
private Paint mPaint;
private View mParent;
public CustomTextViewDrawable(View parent, Drawable[] layers) {
super(layers);
mParent = parent;
mPaint = new Paint();
mPaint.setAntiAlias(true);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
float radius = 5;
// Top-left corner
float centerX = 0;
float centerY = 0;
// Draw circle
mPaint.setColor(Color.RED);
mPaint.setStyle(Style.FILL_AND_STROKE);
canvas.drawCircle(centerX, centerY, radius, mPaint);
}
#Override
public boolean isStateful() {
return false;
}
}
And my usage is the following:
// Get the drawable set in XML file ...
Drawable[] layers = new Drawable[] { imageView.getDrawable() };
Drawable d = new CustomTextViewDrawable(imageView, layers);
// ... and replace it
imageView.setImageDrawable(d);
What i wanted to get is 1/4 of a circle with center in top-left corner, but what i get is the following (with "show layout bounds" options enabled in my device):
Can someone tell me why the point (0, 0) is there? Shouldn't it be placed on top-left corner?
Edit
Here is the XML layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp" >
<!-- Some views here ... -->
<ImageButton
android:id="#+id/questions_answers"
android:layout_width="wrap_content"
android:src="#drawable/ic_action_help"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="#id/..."
android:contentDescription="#string/..." />
</RelativeLayout>
<!-- Some other views here ... -->
</LinearLayout>
Try to draw that point in your ImageView or set to your imageView android:scaleType="fitStart". Maybe your imageView creates some padding by default which depends on scaleType.
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>