How to make a view with rounded corners? - android
I am trying to make a view in android with rounded edges. The solution I found so far is to define a shape with rounded corners and use it as the background of that view.
Here is what I did, define a drawable as given below:
<padding
android:top="2dp"
android:bottom="2dp"/>
<corners android:bottomRightRadius="20dp"
android:bottomLeftRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp"/>
Now I used this as the background for my layout as below:
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:clipChildren="true"
android:background="#drawable/rounded_corner">
This works perfectly fine, I can see that the view has rounded edges.
But my layout has got many other child views in it, say an ImageView or a MapView. When I place an ImageView inside the above layout, the corners of image are not clipped/cropped, instead it appears full.
I have seen other workarounds to make it work like the one explained here.
But is there a method to set rounded corners for a view and all its
child views are contained within that main view that has rounded
corners?
Another approach is to make a custom layout class like the one below. This layout first draws its contents to an offscreen bitmap, masks the offscreen bitmap with a rounded rect and then draws the offscreen bitmap on the actual canvas.
I tried it and it seems to work (at least for my simple testcase). It will of course affect performance compared to a regular layout.
package com.example;
import android.content.Context;
import android.graphics.*;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.widget.FrameLayout;
public class RoundedCornerLayout extends FrameLayout {
private final static float CORNER_RADIUS = 40.0f;
private Bitmap maskBitmap;
private Paint paint, maskPaint;
private float cornerRadius;
public RoundedCornerLayout(Context context) {
super(context);
init(context, null, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
setWillNotDraw(false);
}
#Override
public void draw(Canvas canvas) {
Bitmap offscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
Canvas offscreenCanvas = new Canvas(offscreenBitmap);
super.draw(offscreenCanvas);
if (maskBitmap == null) {
maskBitmap = createMask(canvas.getWidth(), canvas.getHeight());
}
offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, maskPaint);
canvas.drawBitmap(offscreenBitmap, 0f, 0f, paint);
}
private Bitmap createMask(int width, int height) {
Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
Canvas canvas = new Canvas(mask);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
canvas.drawRect(0, 0, width, height, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, paint);
return mask;
}
}
Use this like a normal layout:
<com.example.RoundedCornerLayout
android:layout_width="200dp"
android:layout_height="200dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/test"/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#ff0000"
/>
</com.example.RoundedCornerLayout>
Or you can use a android.support.v7.widget.CardView like so:
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="#color/white"
card_view:cardCornerRadius="4dp">
<!--YOUR CONTENT-->
</android.support.v7.widget.CardView>
shape.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#f6eef1" />
<stroke
android:width="2dp"
android:color="#000000" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
<corners android:radius="5dp" />
</shape>
and inside you layout
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:clipChildren="true"
android:background="#drawable/shape">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/your image"
android:background="#drawable/shape">
</LinearLayout>
Jaap van Hengstum's answer works great however I think it is expensive and if we apply this method on a Button for example, the touch effect is lost since the view is rendered as a bitmap.
For me the best method and the simplest one consists in applying a mask on the view, like that:
#Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
float cornerRadius = <whatever_you_want>;
this.path = new Path();
this.path.addRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, Path.Direction.CW);
}
#Override
protected void dispatchDraw(Canvas canvas) {
if (this.path != null) {
canvas.clipPath(this.path);
}
super.dispatchDraw(canvas);
}
Create a xml file called round.xml in the drawable folder and paste this content:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#FFFFFF" />
<stroke android:width=".05dp" android:color="#d2d2d2" />
<corners android:topLeftRadius="5dp" android:topRightRadius="5dp" android:bottomRightRadius="5dp" android:bottomLeftRadius="5dp"/>
</shape>
then use the round.xml as background to any item. Then it will give you rounded corners.
If you are having problem while adding touch listeners to the layout. Use this layout as parent layout.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.widget.FrameLayout;
public class RoundedCornerLayout extends FrameLayout {
private final static float CORNER_RADIUS = 6.0f;
private float cornerRadius;
public RoundedCornerLayout(Context context) {
super(context);
init(context, null, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
#Override
protected void dispatchDraw(Canvas canvas) {
int count = canvas.save();
final Path path = new Path();
path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), cornerRadius, cornerRadius, Path.Direction.CW);
canvas.clipPath(path, Region.Op.REPLACE);
canvas.clipPath(path);
super.dispatchDraw(canvas);
canvas.restoreToCount(count);
}
}
as
<?xml version="1.0" encoding="utf-8"?>
<com.example.view.RoundedCornerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/patentItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingRight="20dp">
... your child goes here
</RelativeLayout>
</com.example.view.RoundedCornerLayout>
In case you want to round some specific corner.
fun setCorners() {
val mOutlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
val left = 0
val top = 0;
val right = view.width
val bottom = view.height
val cornerRadiusDP = 16f
val cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, cornerRadiusDP, resources.displayMetrics).toInt()
// all corners
outline.setRoundRect(left, top, right, bottom, cornerRadius.toFloat())
/* top corners
outline.setRoundRect(left, top, right, bottom+cornerRadius, cornerRadius.toFloat())*/
/* bottom corners
outline.setRoundRect(left, top - cornerRadius, right, bottom, cornerRadius.toFloat())*/
/* left corners
outline.setRoundRect(left, top, right + cornerRadius, bottom, cornerRadius.toFloat())*/
/* right corners
outline.setRoundRect(left - cornerRadius, top, right, bottom, cornerRadius.toFloat())*/
/* top left corner
outline.setRoundRect(left , top, right+ cornerRadius, bottom + cornerRadius, cornerRadius.toFloat())*/
/* top right corner
outline.setRoundRect(left - cornerRadius , top, right, bottom + cornerRadius, cornerRadius.toFloat())*/
/* bottom left corner
outline.setRoundRect(left, top - cornerRadius, right + cornerRadius, bottom, cornerRadius.toFloat())*/
/* bottom right corner
outline.setRoundRect(left - cornerRadius, top - cornerRadius, right, bottom, cornerRadius.toFloat())*/
}
}
myView.apply {
outlineProvider = mOutlineProvider
clipToOutline = true
}
}
Can be used on a LinearLayout with children that looks like this:
to this:
With the Material Components Library the best way to make a View with rounded corners is to use the MaterialShapeDrawable.
Create a ShapeAppearanceModel with custom rounded corners:
ShapeAppearanceModel shapeAppearanceModelLL1 = new ShapeAppearanceModel()
.toBuilder()
.setAllCorners(CornerFamily.ROUNDED,radius16)
.build();
Create a MaterialShapeDrawable:
MaterialShapeDrawable shapeDrawableLL1 = new MaterialShapeDrawable(shapeAppearanceModeLL1);
If you want to apply also an elevationOverlay for the dark theme use this:
MaterialShapeDrawable shapeDrawableLL1 = MaterialShapeDrawable.createWithElevationOverlay(this, 4.0f);
shapeDrawableLL1.setShapeAppearanceModel(shapeAppearanceModelLL1);
Optional: apply to the shapeDrawable a background color and a stroke
shapeDrawableLL1.setFillColor(
ContextCompat.getColorStateList(this,R.color...));
shapeDrawableLL1.setStrokeWidth(2.0f);
shapeDrawableLL1.setStrokeColor(
ContextCompat.getColorStateList(this,R.color...));
Finally apply the shapeDrawable as background in your LinearLayout (or other view):
LinearLayout linearLayout1= findViewById(R.id.ll_1);
ViewCompat.setBackground(linearLayout1,shapeDrawableLL1);
In Android L you will be able to just use View.setClipToOutline to get that effect. In previous versions there is no way to just clip the contents of a random ViewGroup in a certain shape.
You will have to think of something that would give you a similar effect:
If you only need rounded corners in the ImageView, you can use a shader to 'paint' the image over the shape you are using as background. Take a look at this library for an example.
If you really need every children to be clipped, maybe you can another view over your layout? One with a background of whatever color you are using, and a round 'hole' in the middle? You could actually create a custom ViewGroup that draws that shape over every children overriding the onDraw method.
Create a xml file under your drawable folder with following code. (The name of the file I created is rounded_corner.xml)
rounded_corner.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- view background color -->
<solid
android:color="#a9c5ac" >
</solid>
<!-- view border color and width -->
<stroke
android:width="3dp"
android:color="#1c1b20" >
</stroke>
<!-- If you want to add some padding -->
<padding
android:left="4dp"
android:top="4dp"
android:right="4dp"
android:bottom="4dp" >
</padding>
<!-- Here is the corner radius -->
<corners
android:radius="10dp" >
</corners>
</shape>
And keep this drawable as background for the view to which you want to keep rounded corner border. Let’s keep it for a LinearLayout
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/rounded_corner"
android:layout_centerInParent="true">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hi, This layout has rounded corner borders ..."
android:gravity="center"
android:padding="5dp"/>
</LinearLayout>
The CardView worked for me in API 27 in Android Studio 3.0.1. The colorPrimary was referenced in the res/values/colors.xml file and is just an example. For the layout_width of 0dp it will stretch to the width of the parent. You'll have to configure the constraints and width/height to your needs.
<android.support.v7.widget.CardView
android:id="#+id/cardView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
app:cardBackgroundColor="#color/colorPrimary">
<!-- put your content here -->
</android.support.v7.widget.CardView>
You can use an androidx.cardview.widget.CardView like so:
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="#dimen/dimen_4"
app:cardElevation="#dimen/dimen_4"
app:contentPadding="#dimen/dimen_10">
...
</androidx.cardview.widget.CardView>
OR
shape.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#f6eef1" />
<stroke
android:width="2dp"
android:color="#000000" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
<corners android:radius="5dp" />
</shape>
and inside you layout
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/shape">
...
</LinearLayout>
To create round corner image using com.google.android.material:material:1.2.0-beta01
float radius = context.getResources().getDimension(R.dimen.border_radius_hug);
shapeAppearanceModel = new ShapeAppearanceModel()
.toBuilder()
.setAllCorners(CornerFamily.ROUNDED,radius)
.build();
imageView.setShapeAppearanceModel(shapeAppearanceModel)
or if you want to use it in xml file:
<com.google.android.material.imageview.ShapeableImageView
android:id="#+id/thumb"
android:layout_width="80dp"
android:layout_height="60dp"
app:shapeAppearanceOverlay="#style/circleImageView"
/>
in style.xml add this:
<style name="circleImageView" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">10%</item>
</style>
follow this tutorial and all the discussion beneath it -
http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/
according to this post written by Guy Romain, one of the leading developers of the entire Android UI toolkit, it is possible to make a container (and all his child views) with rounded corners, but he explained that it too expensive (from performances of rendering issues).
I'll recommend you to go according to his post, and if you want rounded corners, then implement rounded corners ImageView according to this post. then, you could place it inside a container with any background, and you'll get the affect you wish.
that's what I did also also eventually.
public class RoundedCornerLayout extends FrameLayout {
private double mCornerRadius;
public RoundedCornerLayout(Context context) {
this(context, null, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
public double getCornerRadius() {
return mCornerRadius;
}
public void setCornerRadius(double cornerRadius) {
mCornerRadius = cornerRadius;
}
#Override
public void draw(Canvas canvas) {
int count = canvas.save();
final Path path = new Path();
path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), (float) mCornerRadius, (float) mCornerRadius, Path.Direction.CW);
canvas.clipPath(path, Region.Op.REPLACE);
canvas.clipPath(path);
super.draw(canvas);
canvas.restoreToCount(count);
}
}
Difference from Jaap van Hengstum's answer:
Use BitmapShader instead of mask bitmap.
Create bitmap only once.
public class RoundedFrameLayout extends FrameLayout {
private Bitmap mOffscreenBitmap;
private Canvas mOffscreenCanvas;
private BitmapShader mBitmapShader;
private Paint mPaint;
private RectF mRectF;
public RoundedFrameLayout(Context context) {
super(context);
init();
}
public RoundedFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundedFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setWillNotDraw(false);
}
#Override
public void draw(Canvas canvas) {
if (mOffscreenBitmap == null) {
mOffscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
mOffscreenCanvas = new Canvas(mOffscreenBitmap);
mBitmapShader = new BitmapShader(mOffscreenBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setShader(mBitmapShader);
mRectF = new RectF(0f, 0f, canvas.getWidth(), canvas.getHeight());
}
super.draw(mOffscreenCanvas);
canvas.drawRoundRect(mRectF, 8, 8, mPaint);
}
}
The tutorial link you provided seems to suggest that you need to set the layout_width and layout_height properties, of your child elements to match_parent.
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent">
try this property with your linear layout it will help
tools:context=".youractivity"
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
Bitmap roundedBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap
.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(roundedBitmap);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
final float roundPx = pixels;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return roundedBitmap;
}
I have seen many solutions, but most of them are useless with Image
View unless you change Image View to other design components, and I do
not recommend them because they may not be compatible with some
**
solution using:
**
Width and color of stroke in drawable
And Margin for the picture
versions. Here is the quick solution.
The first step:
<RelativeLayout
android:layout_width="90dp"
android:layout_height="90dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:scaleType="centerCrop"
android:src="#drawable/a" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/card_helh" />
</RelativeLayout>
design shape
The second step:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="#dimen/_10dp"/>
<stroke android:color="#color/white" android:width="5dp"/>
</shape>
**
A note
** about setting the night mode, set the color stroke color to the color of the container's night so that it appears more homogeneous This
solution works 100%
This solution is mine and I am currently using it
Use shape in xml with rectangle.set the property of bottom or upper radius as want.then apply that xml as background to ur view....or...use gradients to do it from code.
Related
Change background image but keep drawable to a view android xml
I have a Framelayout which has some rounded corners through a drawable xml file <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <!-- View background color --> <solid android:color="#color/colorPrimary" > </solid> <!-- The radius makes the corners rounded --> <corners android:topLeftRadius="20dp" android:bottomRightRadius="20dp" > </corners> </shape> Inside the FrameLayout i have 2 TextViews and an imageView which gets loaded with a bitmap programmatically. The problem is that i have tried everything to give the ImageView same rounded corners as the FrameLayout so i decided to replace the ImageView with another simple View (as FrameLayout or smth) and set the bitmap image as a background of the view. This didn't work either. So is there any way in a view to set the drawable with the corners in the xml, and when later programmatically change the background with a bitmap to keep somehow the rounded corners with the new image loaded? Thank you
Solution Step 1. Go to res/values folder, create a xml file named attrs.xml <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="RoundedImageView"> <attr name="topLeftCorner" format="dimension" /> <attr name="topRightCorner" format="dimension" /> <attr name="bottomRightCorner" format="dimension" /> <attr name="bottomLeftCorner" format="dimension" /> </declare-styleable> </resources> Step 2. Create a class that extends from AppCompatImageView, named RoundedImageView public class RoundedImageView extends AppCompatImageView { private final Path path = new Path(); private final float[] radii = new float[8]; private final RectF rect = new RectF(); public RoundedImageView(#NonNull Context context) { this(context, null); } public RoundedImageView(#NonNull Context context, #Nullable AttributeSet attrs) { super(context, attrs); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundedImageView); try { int topLeftCorner = a.getDimensionPixelSize(R.styleable.RoundedImageView_topLeftCorner, 0); int topRightCorner = a.getDimensionPixelSize(R.styleable.RoundedImageView_topRightCorner, 0); int bottomRightCorner = a.getDimensionPixelSize(R.styleable.RoundedImageView_bottomRightCorner, 0); int bottomLeftCorner = a.getDimensionPixelSize(R.styleable.RoundedImageView_bottomLeftCorner, 0); radii[0] = topLeftCorner; radii[1] = topLeftCorner; radii[2] = topRightCorner; radii[3] = topRightCorner; radii[4] = bottomRightCorner; radii[5] = bottomRightCorner; radii[6] = bottomLeftCorner; radii[7] = bottomLeftCorner; } finally { a.recycle(); } } #Override protected void onDraw(Canvas canvas) { rect.left = 0; rect.top = 0; rect.right = getWidth(); rect.bottom = getHeight(); path.rewind(); path.addRoundRect(rect, radii, Path.Direction.CW); canvas.clipPath(path); super.onDraw(canvas); } } Step 3. Use it from layout file. <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#F00" android:gravity="center"> <com.example.roundedimageview.RoundedImageView android:id="#+id/imageView" android:layout_width="240dp" android:layout_height="240dp" android:layout_gravity="center" android:scaleType="centerCrop" android:src="#drawable/ic_android" app:bottomRightCorner="20dp" app:topLeftCorner="20dp" /> </FrameLayout> Result Benefit You can set the corner radius for top-left, top-right, bottom-right, bottom-left. Work with Glide, Picasso library Limitations The ScaleType is either CENTER_CROP or FIT_XY
You can use libraries to achieve it easily. But there is an other way to do. You can use your image within CardView. When you set cardCornerRadius feature the image corners which overlaying the cardview's corners will be rounded too. Or try this ImageView yourImageView = findViewById(R.id.yourImageView); Bitmap bitmap =((BitmapDrawable) ResourcesCompat.getDrawable(R.drawable.anyPicture)).getBitmap(); Bitmap roundedImageBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); Canvas canvas=new Canvas(roundedImageBitmap); Paint paint = new Paint(); paint.setAntiAlias(true); paint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); canvas.drawRoundRect((new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight())), 100, 100, paint); // You can adjust the roundness here yourimageView.setImageBitmap(roundedImageBitmap);
Children of ListView doesn't respect parents border radius [duplicate]
I am trying to make a view in android with rounded edges. The solution I found so far is to define a shape with rounded corners and use it as the background of that view. Here is what I did, define a drawable as given below: <padding android:top="2dp" android:bottom="2dp"/> <corners android:bottomRightRadius="20dp" android:bottomLeftRadius="20dp" android:topLeftRadius="20dp" android:topRightRadius="20dp"/> Now I used this as the background for my layout as below: <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginBottom="10dp" android:clipChildren="true" android:background="#drawable/rounded_corner"> This works perfectly fine, I can see that the view has rounded edges. But my layout has got many other child views in it, say an ImageView or a MapView. When I place an ImageView inside the above layout, the corners of image are not clipped/cropped, instead it appears full. I have seen other workarounds to make it work like the one explained here. But is there a method to set rounded corners for a view and all its child views are contained within that main view that has rounded corners?
Another approach is to make a custom layout class like the one below. This layout first draws its contents to an offscreen bitmap, masks the offscreen bitmap with a rounded rect and then draws the offscreen bitmap on the actual canvas. I tried it and it seems to work (at least for my simple testcase). It will of course affect performance compared to a regular layout. package com.example; import android.content.Context; import android.graphics.*; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.widget.FrameLayout; public class RoundedCornerLayout extends FrameLayout { private final static float CORNER_RADIUS = 40.0f; private Bitmap maskBitmap; private Paint paint, maskPaint; private float cornerRadius; public RoundedCornerLayout(Context context) { super(context); init(context, null, 0); } public RoundedCornerLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs, 0); } public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs, defStyle); } private void init(Context context, AttributeSet attrs, int defStyle) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics); paint = new Paint(Paint.ANTI_ALIAS_FLAG); maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); setWillNotDraw(false); } #Override public void draw(Canvas canvas) { Bitmap offscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); Canvas offscreenCanvas = new Canvas(offscreenBitmap); super.draw(offscreenCanvas); if (maskBitmap == null) { maskBitmap = createMask(canvas.getWidth(), canvas.getHeight()); } offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, maskPaint); canvas.drawBitmap(offscreenBitmap, 0f, 0f, paint); } private Bitmap createMask(int width, int height) { Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8); Canvas canvas = new Canvas(mask); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.WHITE); canvas.drawRect(0, 0, width, height, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, paint); return mask; } } Use this like a normal layout: <com.example.RoundedCornerLayout android:layout_width="200dp" android:layout_height="200dp"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="#drawable/test"/> <View android:layout_width="match_parent" android:layout_height="100dp" android:background="#ff0000" /> </com.example.RoundedCornerLayout>
Or you can use a android.support.v7.widget.CardView like so: <android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content" card_view:cardBackgroundColor="#color/white" card_view:cardCornerRadius="4dp"> <!--YOUR CONTENT--> </android.support.v7.widget.CardView>
shape.xml <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#f6eef1" /> <stroke android:width="2dp" android:color="#000000" /> <padding android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp" /> <corners android:radius="5dp" /> </shape> and inside you layout <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginBottom="10dp" android:clipChildren="true" android:background="#drawable/shape"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="#drawable/your image" android:background="#drawable/shape"> </LinearLayout>
Jaap van Hengstum's answer works great however I think it is expensive and if we apply this method on a Button for example, the touch effect is lost since the view is rendered as a bitmap. For me the best method and the simplest one consists in applying a mask on the view, like that: #Override protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) { super.onSizeChanged(width, height, oldWidth, oldHeight); float cornerRadius = <whatever_you_want>; this.path = new Path(); this.path.addRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, Path.Direction.CW); } #Override protected void dispatchDraw(Canvas canvas) { if (this.path != null) { canvas.clipPath(this.path); } super.dispatchDraw(canvas); }
Create a xml file called round.xml in the drawable folder and paste this content: <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#FFFFFF" /> <stroke android:width=".05dp" android:color="#d2d2d2" /> <corners android:topLeftRadius="5dp" android:topRightRadius="5dp" android:bottomRightRadius="5dp" android:bottomLeftRadius="5dp"/> </shape> then use the round.xml as background to any item. Then it will give you rounded corners.
If you are having problem while adding touch listeners to the layout. Use this layout as parent layout. import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.graphics.Region; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.View; import android.widget.FrameLayout; public class RoundedCornerLayout extends FrameLayout { private final static float CORNER_RADIUS = 6.0f; private float cornerRadius; public RoundedCornerLayout(Context context) { super(context); init(context, null, 0); } public RoundedCornerLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs, 0); } public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs, defStyle); } private void init(Context context, AttributeSet attrs, int defStyle) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics); setLayerType(View.LAYER_TYPE_SOFTWARE, null); } #Override protected void dispatchDraw(Canvas canvas) { int count = canvas.save(); final Path path = new Path(); path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), cornerRadius, cornerRadius, Path.Direction.CW); canvas.clipPath(path, Region.Op.REPLACE); canvas.clipPath(path); super.dispatchDraw(canvas); canvas.restoreToCount(count); } } as <?xml version="1.0" encoding="utf-8"?> <com.example.view.RoundedCornerLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:id="#+id/patentItem" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingRight="20dp"> ... your child goes here </RelativeLayout> </com.example.view.RoundedCornerLayout>
In case you want to round some specific corner. fun setCorners() { val mOutlineProvider = object : ViewOutlineProvider() { override fun getOutline(view: View, outline: Outline) { val left = 0 val top = 0; val right = view.width val bottom = view.height val cornerRadiusDP = 16f val cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, cornerRadiusDP, resources.displayMetrics).toInt() // all corners outline.setRoundRect(left, top, right, bottom, cornerRadius.toFloat()) /* top corners outline.setRoundRect(left, top, right, bottom+cornerRadius, cornerRadius.toFloat())*/ /* bottom corners outline.setRoundRect(left, top - cornerRadius, right, bottom, cornerRadius.toFloat())*/ /* left corners outline.setRoundRect(left, top, right + cornerRadius, bottom, cornerRadius.toFloat())*/ /* right corners outline.setRoundRect(left - cornerRadius, top, right, bottom, cornerRadius.toFloat())*/ /* top left corner outline.setRoundRect(left , top, right+ cornerRadius, bottom + cornerRadius, cornerRadius.toFloat())*/ /* top right corner outline.setRoundRect(left - cornerRadius , top, right, bottom + cornerRadius, cornerRadius.toFloat())*/ /* bottom left corner outline.setRoundRect(left, top - cornerRadius, right + cornerRadius, bottom, cornerRadius.toFloat())*/ /* bottom right corner outline.setRoundRect(left - cornerRadius, top - cornerRadius, right, bottom, cornerRadius.toFloat())*/ } } myView.apply { outlineProvider = mOutlineProvider clipToOutline = true } } Can be used on a LinearLayout with children that looks like this: to this:
With the Material Components Library the best way to make a View with rounded corners is to use the MaterialShapeDrawable. Create a ShapeAppearanceModel with custom rounded corners: ShapeAppearanceModel shapeAppearanceModelLL1 = new ShapeAppearanceModel() .toBuilder() .setAllCorners(CornerFamily.ROUNDED,radius16) .build(); Create a MaterialShapeDrawable: MaterialShapeDrawable shapeDrawableLL1 = new MaterialShapeDrawable(shapeAppearanceModeLL1); If you want to apply also an elevationOverlay for the dark theme use this: MaterialShapeDrawable shapeDrawableLL1 = MaterialShapeDrawable.createWithElevationOverlay(this, 4.0f); shapeDrawableLL1.setShapeAppearanceModel(shapeAppearanceModelLL1); Optional: apply to the shapeDrawable a background color and a stroke shapeDrawableLL1.setFillColor( ContextCompat.getColorStateList(this,R.color...)); shapeDrawableLL1.setStrokeWidth(2.0f); shapeDrawableLL1.setStrokeColor( ContextCompat.getColorStateList(this,R.color...)); Finally apply the shapeDrawable as background in your LinearLayout (or other view): LinearLayout linearLayout1= findViewById(R.id.ll_1); ViewCompat.setBackground(linearLayout1,shapeDrawableLL1);
In Android L you will be able to just use View.setClipToOutline to get that effect. In previous versions there is no way to just clip the contents of a random ViewGroup in a certain shape. You will have to think of something that would give you a similar effect: If you only need rounded corners in the ImageView, you can use a shader to 'paint' the image over the shape you are using as background. Take a look at this library for an example. If you really need every children to be clipped, maybe you can another view over your layout? One with a background of whatever color you are using, and a round 'hole' in the middle? You could actually create a custom ViewGroup that draws that shape over every children overriding the onDraw method.
Create a xml file under your drawable folder with following code. (The name of the file I created is rounded_corner.xml) rounded_corner.xml <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <!-- view background color --> <solid android:color="#a9c5ac" > </solid> <!-- view border color and width --> <stroke android:width="3dp" android:color="#1c1b20" > </stroke> <!-- If you want to add some padding --> <padding android:left="4dp" android:top="4dp" android:right="4dp" android:bottom="4dp" > </padding> <!-- Here is the corner radius --> <corners android:radius="10dp" > </corners> </shape> And keep this drawable as background for the view to which you want to keep rounded corner border. Let’s keep it for a LinearLayout <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#drawable/rounded_corner" android:layout_centerInParent="true"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Hi, This layout has rounded corner borders ..." android:gravity="center" android:padding="5dp"/> </LinearLayout>
The CardView worked for me in API 27 in Android Studio 3.0.1. The colorPrimary was referenced in the res/values/colors.xml file and is just an example. For the layout_width of 0dp it will stretch to the width of the parent. You'll have to configure the constraints and width/height to your needs. <android.support.v7.widget.CardView android:id="#+id/cardView" android:layout_width="wrap_content" android:layout_height="wrap_content" app:cardCornerRadius="4dp" app:cardBackgroundColor="#color/colorPrimary"> <!-- put your content here --> </android.support.v7.widget.CardView>
You can use an androidx.cardview.widget.CardView like so: <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" app:cardCornerRadius="#dimen/dimen_4" app:cardElevation="#dimen/dimen_4" app:contentPadding="#dimen/dimen_10"> ... </androidx.cardview.widget.CardView> OR shape.xml <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#f6eef1" /> <stroke android:width="2dp" android:color="#000000" /> <padding android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp" /> <corners android:radius="5dp" /> </shape> and inside you layout <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#drawable/shape"> ... </LinearLayout>
To create round corner image using com.google.android.material:material:1.2.0-beta01 float radius = context.getResources().getDimension(R.dimen.border_radius_hug); shapeAppearanceModel = new ShapeAppearanceModel() .toBuilder() .setAllCorners(CornerFamily.ROUNDED,radius) .build(); imageView.setShapeAppearanceModel(shapeAppearanceModel) or if you want to use it in xml file: <com.google.android.material.imageview.ShapeableImageView android:id="#+id/thumb" android:layout_width="80dp" android:layout_height="60dp" app:shapeAppearanceOverlay="#style/circleImageView" /> in style.xml add this: <style name="circleImageView" parent=""> <item name="cornerFamily">rounded</item> <item name="cornerSize">10%</item> </style>
follow this tutorial and all the discussion beneath it - http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/ according to this post written by Guy Romain, one of the leading developers of the entire Android UI toolkit, it is possible to make a container (and all his child views) with rounded corners, but he explained that it too expensive (from performances of rendering issues). I'll recommend you to go according to his post, and if you want rounded corners, then implement rounded corners ImageView according to this post. then, you could place it inside a container with any background, and you'll get the affect you wish. that's what I did also also eventually.
public class RoundedCornerLayout extends FrameLayout { private double mCornerRadius; public RoundedCornerLayout(Context context) { this(context, null, 0); } public RoundedCornerLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs, defStyle); } private void init(Context context, AttributeSet attrs, int defStyle) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); setLayerType(View.LAYER_TYPE_SOFTWARE, null); } public double getCornerRadius() { return mCornerRadius; } public void setCornerRadius(double cornerRadius) { mCornerRadius = cornerRadius; } #Override public void draw(Canvas canvas) { int count = canvas.save(); final Path path = new Path(); path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), (float) mCornerRadius, (float) mCornerRadius, Path.Direction.CW); canvas.clipPath(path, Region.Op.REPLACE); canvas.clipPath(path); super.draw(canvas); canvas.restoreToCount(count); } }
Difference from Jaap van Hengstum's answer: Use BitmapShader instead of mask bitmap. Create bitmap only once. public class RoundedFrameLayout extends FrameLayout { private Bitmap mOffscreenBitmap; private Canvas mOffscreenCanvas; private BitmapShader mBitmapShader; private Paint mPaint; private RectF mRectF; public RoundedFrameLayout(Context context) { super(context); init(); } public RoundedFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public RoundedFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { setWillNotDraw(false); } #Override public void draw(Canvas canvas) { if (mOffscreenBitmap == null) { mOffscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); mOffscreenCanvas = new Canvas(mOffscreenBitmap); mBitmapShader = new BitmapShader(mOffscreenBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setShader(mBitmapShader); mRectF = new RectF(0f, 0f, canvas.getWidth(), canvas.getHeight()); } super.draw(mOffscreenCanvas); canvas.drawRoundRect(mRectF, 8, 8, mPaint); } }
The tutorial link you provided seems to suggest that you need to set the layout_width and layout_height properties, of your child elements to match_parent. <ImageView android:layout_width="match_parent" android:layout_height="match_parent">
try this property with your linear layout it will help tools:context=".youractivity"
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) { Bitmap roundedBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap .getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(roundedBitmap); final int color = 0xff424242; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); final RectF rectF = new RectF(rect); final float roundPx = pixels; paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); return roundedBitmap; }
I have seen many solutions, but most of them are useless with Image View unless you change Image View to other design components, and I do not recommend them because they may not be compatible with some ** solution using: ** Width and color of stroke in drawable And Margin for the picture versions. Here is the quick solution. The first step: <RelativeLayout android:layout_width="90dp" android:layout_height="90dp"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="5dp" android:scaleType="centerCrop" android:src="#drawable/a" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="#drawable/card_helh" /> </RelativeLayout> design shape The second step: <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="#dimen/_10dp"/> <stroke android:color="#color/white" android:width="5dp"/> </shape> ** A note ** about setting the night mode, set the color stroke color to the color of the container's night so that it appears more homogeneous This solution works 100% This solution is mine and I am currently using it
Use shape in xml with rectangle.set the property of bottom or upper radius as want.then apply that xml as background to ur view....or...use gradients to do it from code.
How to draw segment of circle at the bottom of view [android]?
My activity should look like this: I'm not sure what's the best way to show the segment of the circle between top and bottom views. I'd like to avoid saving the segment as image. Is there a way to show it using drawable xml (I've tried to achieve this using oval, but I don't know how to make is so "flat")? Maybe drawing on canvas?
I think option 3 is the best, you can control exactly what you're drawing but you don't loose OOP karma points OPTION 1 You can create a custom View for your top View and implement the drawing yourself like this, I'm subclassing RelativeLayout here but you can subclass whatever View you want public class CurveBgRelativeLayout extends RelativeLayout { public CurveBgRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); } private Path path; private Paint paint; #Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setStyle(Paint.Style.FILL); paint.setColor(0xffff0000); path = new Path(); float horizontalOffset = w * .8f; float top = -h * .8f; float bottom = h; RectF ovalRect = new RectF(-horizontalOffset, top, w + horizontalOffset, bottom); path.lineTo(ovalRect.left, top); path.arcTo(ovalRect, 0, 180, false); path.setFillType(Path.FillType.INVERSE_EVEN_ODD); } #Override protected void onDraw(Canvas canvas) { if (path != null) canvas.drawPath(path, paint); super.onDraw(canvas); } } and then in your xml 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"> <com.example.CurveBgRelativeLayout android:layout_width="match_parent" android:background="#ffffffff" android:layout_height="0dp" android:layout_weight="1"/> <View android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="#ffff0000" /> </LinearLayout> OPTION 2 You can create an xml drawable as a background for your top View, the only problem here is that the horizontal stretch of the circle is given with a size in dp, so it's not relative to the View's size <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:height="40dp" android:gravity="bottom"> <shape android:shape="rectangle"> <solid android:color="#ffff0000" /> </shape> </item> <item android:width="500dp" android:height="60dp" android:gravity="bottom|center_horizontal" android:top="-40dp"> <shape android:shape="oval"> <solid android:color="#ffffffff" /> </shape> </item> <item android:height="30dp" android:bottom="30dp" android:gravity="bottom"> <shape android:shape="rectangle"> <solid android:color="#ffffffff" /> </shape> </item> </layer-list> OPTION 3 public class CurveBottomDrawable extends Drawable { private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private Path path = new Path(); public CurveBottomDrawable(int color) { paint.setStyle(Paint.Style.FILL); paint.setColor(color); } #Override public void draw(#NonNull Canvas canvas) { paint.setStyle(Paint.Style.FILL); paint.setColor(0xffff0000); path.reset(); Rect bounds = getBounds(); float horizontalOffset = bounds.width() * .8f; float top = -bounds.height() * .8f; float bottom = bounds.height(); RectF ovalRect = new RectF(-horizontalOffset, top, bounds.width() + horizontalOffset, bottom); path.lineTo(ovalRect.left, top); path.arcTo(ovalRect, 0, 180, false); path.setFillType(Path.FillType.INVERSE_EVEN_ODD); canvas.drawPath(path, paint); } #Override public void setAlpha(#IntRange(from = 0, to = 255) int alpha) { paint.setAlpha(alpha); } #Override public void setColorFilter(#Nullable ColorFilter colorFilter) { paint.setColorFilter(colorFilter); } #Override public int getOpacity() { return PixelFormat.TRANSPARENT; } } and then set it programmatically myView.setBackground(new CurveBottomDrawable(0xffff0000));
Change color of shape in xml drawable file through layout
So I created this drawable xml file called rounded_rect. I initially set its color to red. However I want to be able to change this color in my layout file. rounded_rect.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="#ffff1900"/> <corners android:bottomRightRadius="15dp" android:bottomLeftRadius="15dp" android:topLeftRadius="15dp" android:topRightRadius="15dp"/> <stroke android:width="4dp" android:color="#000000"/> </shape> My layout file contains a custom View called ItemView. One of my custom attributes is background color. <custonview.android.example.com.customview.ItemView android:layout_width="wrap_content" android:layout_height="wrap_content" custom:imagePath="#drawable/yes" custom:text="Yes" custom:backgroundColor="#000000" android:layout_row="0" android:layout_column="0" android:background="#drawable/rounded_rect_green" android:layout_margin="30dp" /> The goal is to be able to change the color in my drawable file to the color I assigned in my layout file. Here is my ItemView.java file public class ItemView extends View { //attributes of item view private Drawable drawable; private String text; private int backgroundColor; private int width, height; private Paint paint; public ItemView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ItemView, 0, 0); try { text = a.getString(R.styleable.ItemView_text); backgroundColor = a.getInteger(R.styleable.ItemView_backgroundColor, 0); drawable = a.getDrawable(R.styleable.ItemView_imagePath); } finally { } paint = new Paint(); width = drawable.getMinimumWidth() / 2; height = drawable.getMinimumHeight() / 2; } #Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(width, height); } #Override protected void onDraw(Canvas canvas) { //positions the image in the middle horizontally and a little above the text below drawable.setBounds(width / 4, height / 4 - 50, width - (width / 4), height - (height / 4) - 50); drawable.draw(canvas); paint.setTextSize(100); paint.setColor(Color.BLACK); canvas.drawText(text, width / 2 - paint.measureText(text, 0, text.length()) / 2, height - 50, paint); } } Maybe I am over contemplating it. Free free to be creative in your answers. Thank you in advance
Try the below code- GradientDrawable bgShape = (GradientDrawable)yourview.getBackground(); bgShape.setColor(Color.MAGENTA);
You'll have to create separate drawables for each colour, as there is no way to set those attributes in runtime - because the application would have to compile them.
How to get canvas of separate View
I would like to use some custom views in layout like is shown on picture. Red rectangle it's just border of view. There are could be different things inside. For that I created custom View: public class CustomView extends View { public CustomView(Context context) { super(context); } public CustomView(Context context, AttributeSet attrs) { super(context, attrs); } #Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.WHITE); paint.setStyle(Paint.Style.FILL); canvas.drawCircle(5, 5, 5, paint); canvas.save(); } } and then somewhere in onCreate() method I add some views to layout: layout.addView(new CustomView(this)); layout.addView(new CustomView(this)); As result circle is drawn on the top left side of layout (black rectangle on the picture). I thought that onDraw() method containt Canvas of separate view. How to draw something in scope of separate view but not of all layout?
You can do this in xml. You can create a drawable resource(called red_border.xml)... <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape android:shape="rectangle"> <stroke android:width="1dp" android:color="#android:color/holo_red_light"/> <size android:width="25dp" android:height="25dp"/> </shape> </item> </selector> and assign that to a particular view. <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#drawable/red_border"> </LinearLayout> This will work for more views than just layouts(TextView, EditText, etc...). Hope this helps.