Animate layout's background color change - android

I have a RelativeLayout to which I have set a background from drawable.I was able to change the background of RelativeLayout to another when the RadioButton is checked. But how do I give an animation to it when it changes?
Code:
activity_main.xml:
<RelativeLayout
android:layout_width="80dp"
android:layout_height="50dp"
android:gravity="center"
android:background="#drawable/original"
android:id="#+id/rel1">
<RadioButton
android:id="#+id/radio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"/>
</RelativeLayout>
original.xml(drawable):
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="#ffffff">
</solid>
<corners
android:radius="50dp">
</corners>
</shape>
pressed.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="#2196F3">
</solid>
<corners
android:radius="50dp">
</corners>
</shape>
Java Class:
radio.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if(b){
relativeLayout.setBackgroundResource(R.drawable.pressed);
}
}
});

The problem boils down to having somehow clipped corners and animating the layout background. So, in theory, we can set a foreground drawable to the layout and animate background drawable using ArgbEvaluator.
Moving to practice.
Take a look at this answer, where the author shares a mask drawable, which can be handy for your problem:
Apply that drawable as a foreground of your layout:
<RelativeLayout
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="300dp"
android:foreground="#drawable/frame"
android:background="#color/colorAccent" />
In the code, whenever needed to perform animation:
final int from = ContextCompat.getColor(this, R.color.colorAccent);
final int to = ContextCompat.getColor(this, R.color.colorPrimary);
ValueAnimator anim = new ValueAnimator();
anim.setIntValues(from, to);
anim.setEvaluator(new ArgbEvaluator());
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
view.setBackgroundColor((Integer)valueAnimator.getAnimatedValue());
}
});
anim.setDuration(1000);
anim.start();
Here's what you'll get on output:
If you want to change frame drawable's color, you can wrap it into an xml and apply android:tint.
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item >
<bitmap android:src="#drawable/frame" android:tint="#ccaaff"/>
</item>
</layer-list>
Now set this drawable as the foreground of your layout.

The same effect can be achieved entirely in Code
Create Background with Corner of Rectangle Programmatically
//Background
backgroundDrawable = GradientDrawable()
backgroundDrawable.cornerRadius = rectangleCornerRadius
backgroundDrawable.shape = GradientDrawable.RECTANGLE
backgroundDrawable.setColor(rectangleColor)
background = backgroundDrawable
Animate Color Change
val objectAnimator = ObjectAnimator.ofObject(backgroundDrawable, "color",
ArgbEvaluator(),
Color.parseColor("#FFFFFFFF"),
Color.parseColor("#FF78c5f9"))
objectAnimator .setDuration(1000);
objectAnimator .start();

Related

Android Animation - Scale up and Fade along with Background Transition

I am trying to do something like this.. Can someone point me in the right direction?
Right now, i am using a Scale Animation and FadeOut Animation. It looks like this..
How do i add background colour to this.. Also please keep in mind that i want this to work from ICS/Jellybean
My code till now...
fade_out_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.1"
android:duration="100" />
</set>
scale_up_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="100"
android:fromXScale="0.1"
android:fromYScale="0.1"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1"
android:toYScale="1" />
</set>
activity_main.xml - just the relevant part
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<TextView
android:id="#+id/textView4"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:layout_margin="8dp"
android:background="#drawable/shape_circle"
android:gravity="center"
android:text="004"
android:textColor="#color/light_gray"
android:textSize="18sp" />
<View
android:id="#+id/outer_view"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_centerInParent="true"
android:visibility="invisible"
android:background="#drawable/shape_circle_yellow"/>
</RelativeLayout>
shape_circle.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="false" android:state_pressed="false" android:state_selected="false">
<shape android:shape="oval">
<solid android:color="#color/ash" /> <!-- Fill color -->
<stroke android:width="4dp" android:color="#color/medium_gray" /> <!-- Outerline color -->
</shape>
</item>
<item android:state_selected="true">
<shape android:shape="oval">
<solid android:color="#color/ash" /> <!-- Fill color -->
<stroke android:width="4dp" android:color="#color/yellow" /> <!-- Outerline color -->
</shape>
</item>
<item android:state_focused="true">
<shape android:shape="oval">
<solid android:color="#color/ash" /> <!-- Fill color -->
<stroke android:width="4dp" android:color="#color/yellow" /> <!-- Outerline color -->
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="oval">
<solid android:color="#color/ash" /> <!-- Fill color -->
<stroke android:width="4dp" android:color="#color/yellow" /> <!-- Outerline color -->
</shape>
</item>
</selector>
shape_circle_yellow.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:shape="oval">
<stroke android:color="#color/yellow"
android:width="4dp" />
</shape>
Java code:
textView4.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final View view2 = findViewById(R.id.outer_view);
Animation scale_up_animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.scale_up_animation);
final Animation fade_out_animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.fade_out_animation);
scale_up_animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
view2.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {
view2.startAnimation(fade_out_animation);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
fade_out_animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
view2.setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
view2.startAnimation(scale_up_animation);
}
});
The most simple way to reach this effect on Android is to create few custom views.
For example we can divide animation into two views (according to divide to conquer rule). First view let's name CircleButton. It will be button which can be in two states - default and selected.
Second view let's name CircularRippleEffect and it will be container for animation during state changing.
When we combine this views together we will obtain effect like this:
So, The question is how to create CircleButton and CircularRippleEffect classes ;)
The first one is simple. We should extend View class and Override onDraw method. In onDraw method we have to draw two circles (first is representing button background and second is yellow border).
Our onDraw method will look like this:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, backgroundPaint);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, borderPaint);
drawCenter(canvas, textPaint, text);
}
We have to remember that our backgroundPaintshould have set style up as FILL by using method backgroundPaint.setStyle(FILL); and our borderPaint should have style STROKE. I set also proper colors for this Paint objects. The last thing we should do in onDraw method is drawing text on the center of the View.
I've created drawCenter() method for this implementation, that can be found in this answer from stackoverflow https://stackoverflow.com/a/32081250/1722808
And that is all we should know about CircleButton class. Everything else is similar to every custom view.
The CircularRippleEffect class is more complicated. We also draw two circles, but we have to animate them smoothly. That is why the size of every shape depends on a progress value.
OnDraw method from this class looks like this:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
tempCanvas.drawColor(Color.WHITE, PorterDuff.Mode.CLEAR);
tempCanvas.drawCircle(getWidth() / 2, getHeight() / 2, outerCircleRadiusProgress * maxCircleSize, circlePaint);
tempCanvas.drawCircle(getWidth() / 2, getHeight() / 2, innerCircleRadiusProgress
* (maxCircleSize + ADDITIONAL_SIZE_TO_CLEAR_ANTIALIASING), maskPaint);
canvas.drawBitmap(tempBitmap, 0, 0, null);
}
Implementing this is a little tricky. I've used
tempCanvas.drawColor(Color.WHITE, PorterDuff.Mode.CLEAR);
because I wanted to obtain circle with transparent area inside. And to reach this effect we have to create tempCanvas and tempBitmap.
Similar implementation here: Android canvas: draw transparent circle on image
The last step is combining this views together (we can do it in FrameLayout) and change state of this views in the same time when user clicks it.
The whole source code you can find on my github account https://github.com/ljarka/CircleAnimation
Have a look at this,
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.textView4:
((TextView)findViewById(R.id.textView4)).setBackground(getResources().getDrawable(R.drawable.shape_circle));
((TextView)findViewById(R.id.textView4)).setTextColor(getResources().getColor(R.color.lightgrey));
scale_up_animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
view2.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {
view2.startAnimation(fade_out_animation);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
fade_out_animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
view2.setVisibility(View.INVISIBLE);
((TextView) findViewById(R.id.textView4)).setBackground(getResources().getDrawable(R.drawable.circle_yellow));
((TextView) findViewById(R.id.textView4)).setTextColor(getResources().getColor(R.color.yellow_600));
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
view2.startAnimation(scale_up_animation);
break;
circle_yellow.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
android:tint="#color/yellow_100">
<stroke
android:width="3dp"
android:color="#color/yellow_600" />
<solid android:color="#color/grey_500" />
</shape>
To set background to the TextView, change your selector android:state_selected like below.
<item android:state_selected="true">
<shape android:shape="oval">
<solid android:color="#81fde980" /> <!-- Fill color -->
<stroke android:width="2dp" android:color="#color/yellow" /> <!-- Outerline color -->
</shape>
</item>
Now update onAnimationEnd() of scale_up_animation as
#Override
public void onAnimationEnd(Animation animation) {
view2.startAnimation(fade_out_animation);
if(textView4.isSelected()) {
textView4.setSelected(false);
textView4.setTextColor(getResources().getColor(R.color.light_gray));
} else {
textView4.setSelected(true);
textView4.setTextColor(getResources().getColor(R.color.yellow));
}
}
Implement the code in your activity to make some animation
private View mContentView;
private View mLoadingView;
private int mShortAnimationDuration;
...
private void crossfade() {
// Set the content view to 0% opacity but visible, so that it is visible
// (but fully transparent) during the animation.
mContentView.setAlpha(0f);
mContentView.setVisibility(View.VISIBLE);
// Animate the content view to 100% opacity, and clear any animation
// listener set on the view.
mContentView.animate()
.alpha(1f)
.setDuration(mShortAnimationDuration)
.setListener(null);
// Animate the loading view to 0% opacity. After the animation ends,
// set its visibility to GONE as an optimization step (it won't
// participate in layout passes, etc.)
mLoadingView.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mLoadingView.setVisibility(View.GONE);
}
});
}
Use this code for any components to fade in xml
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<fade>
<targets>
<target android:targetClass="android.widget.TextView" />
<target android:targetClass="android.widget.FrameLayout" />
<target android:targetClass="android.widget.LinearLayout" />
<target android:targetClass="android.widget.ImageView" />
</targets>
</fade>
</transitionSet>
Cute view animation collection:
https://github.com/daimajia/AndroidViewAnimations
you can use an animation like TakingOffAnimator or ZoomOutAnimator on custom shape or views with white background, and with a delay play same animation on a gray view that positioned in center of the first shape or view.
Try this;
Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setDuration(1000);
AnimationSet animation = new AnimationSet(true);
animation.addAnimation(sizingAnimation);
animation.addAnimation(fadeOut);
this.setAnimation(animation);

How to give Color changing animation to a custom shape?

I have a round custom shape and I want it to change its color, but I get the shape as a square not round as I want
Here is my shape:
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="#666666"/>
<size
android:width="120dp"
android:height="120dp"/>
in my layout:
<ImageView
android:id="#+id/rgb_led"
android:visibility="gone"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="#drawable/round_led"
android:layout_centerHorizontal="true" />
in code:
ledImageView.setVisibility(View.VISIBLE);
int colorFrom = getResources().getColor(colorFromId);
int colorTo = getResources().getColor(colorToId);
colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.setDuration(duration);
colorAnimation.setRepeatCount(ValueAnimator.INFINITE);
colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animator) {
ledImageView.setBackgroundColor((int) animator.getAnimatedValue());
}
});
colorAnimation.start();
but I get a flashing square not a round shape!?
EDIT:
I actually would like to animate a round image to get an effect of a flashing colored light that can change colors and flashing duration.
Cheers.
Try this code, I use it in my application to show a round animation cycle:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="5"
android:toDegrees="360" >
<!-- Duration = 1 means that the rotation will be done in 1 second
increase duration if you want to speed up the rotation-->
<shape
android:innerRadiusRatio="30"
android:shape="ring"
android:thicknessRatio="80"
android:useLevel="false">
<size
android:height="80dp"
android:width="80dp" />
<gradient
android:centerColor="#android:color/transparent"
android:centerY="0.50"
android:endColor="#E6E6E6"
android:startColor="#BEBEBE"
android:type="sweep"
android:useLevel="false" />
</shape>
</rotate>
Edit 1:
You can use ProgressBar, much easier to implement and to control via code:
in your xml file:
<ProgressBar
android:id="#+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="bottom|center_horizontal"
android:visibility="gone"
android:indeterminate="true" >
</ProgressBar>
in your *.java file
ProgressBar progress = (ProgressBar) findViewById(R.id.progressBar);
// Control the size
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(80,80);
// Control position
params.gravity = Gravity.CENTER_VERTICAL| Gravity.CENTER_HORIZONTAL;
// Set new parameters and visibility
progress.setLayoutParams(params);
progress.setVisibility(View.VISIBLE);
// Set Color
progress.getIndeterminateDrawable().setColorFilter(0xFFFF0000,android.graphics.PorterDuff.Mode.MULTIPLY);

Programmatically assign color to shape

I have a layout like this:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/user_color">
<shape android:shape="rectangle">
<solid android:color="#000000" />
</shape>
</item>
<item android:right="25dp">
<shape android:shape="rectangle">
<solid android:color="#color/user_background" />
</shape>
</item>
</layer-list>
How I'm calling the shape:
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/shape">
How can I programmatically change the color of the rectangle shape with id user_color?
int colorToPaint = getResources().getColor(android.R.color.white);// any color you want
Drawable tempDrawable = getResources().getDrawable(R.drawable.xml_layout);
LayerDrawable bubble = (LayerDrawable) tempDrawable; //cast to root element in xml
GradientDrawable solidColor = (GradientDrawable) bubble.findDrawableByLayerId(R.id.user_color);
solidColor.setColor(colorToPaint);
#user5262809
// add id to your linear layout
<LinearLayout
android:id="#+id/linearLayout"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/shape">
// then in code do this :
LinearLayout linearView = (LinearLayout) findViewById(R.id.linearLayout);
// added Anitha's code here
int colorToPaint = getResources().getColor(android.R.color.white);// any color you want
Drawable tempDrawable = getResources().getDrawable(R.drawable.xml_layout);
LayerDrawable bubble = (LayerDrawable) tempDrawable; //cast to root element in xml
GradientDrawable solidColor = (GradientDrawable) bubble.findDrawableByLayerId(R.id.user_color);
solidColor.setColor(colorToPaint);
// and then do this
linearView.setBackground(tempDrawable);
// hope this helps you :)
Try the below code:
GradientDrawable bgShape = (GradientDrawable)notesLayout.getBackground();
bgShape.setColor(Color.BLACK);
An Alternative to Anitha's answer would be-
If the LayerDrawable is already set to your ImageView use below code.
LinearLayout mLinearLayout = (LinearLayout)findViewById(R.id.my_linear_layout);
((LayerDrawable)mLinearLayout.getBackground()).findDrawableByLayerId(R.id.user_color).setColorFilter(getResources().getColor(R.color.white),PorterDuff.Mode.SRC_IN);
This way, if you already have a reference to your LinearLayout you do the whole color change in just a single line. And you don't even need to call setBackground() for the change to show!

Get a textView background color with ShapeDrawable

I have a textview with the background defined in a xml file.
<TextView
android:id="#+id/event_tvColor"
android:layout_width="40dip"
android:layout_height="40dip"
android:text=" "
android:background="#drawable/et_style_color_service_edit"
android:clickable="true"
/>
xml file : et_style_color_service_edit.xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#color/eventColor"/>
<stroke android:width="0sp" android:color="#FFFFFF" />
<size android:width="20dp"
android:height="20dp"/>
</shape>
And i need to get the color that the view have in a one time.
ShapeDrawable sc = (ShapeDrawable)tvColor.getBackground();
...............
Note that i need to use ShapeDrawable and not GradientDrawable.
Thank you for your help and time.
Solution........
Solution The xml loads into the app as a gradientdrawable and not as a shapedrawable. We have to define the shapeDrawable in java
ShapeDrawable sd = new ShapeDrawable(new RectShape);
sd.getPaint().setColor(0xFF0000FF);
if anyone have a better solution can tell.
After further research, there currently is no way of getting the xml loaded ShapeDrawable's color. What you have to do is just track your color changes so you know what color you are setting it to, ie:
int currentColor = Color.WHITE; //this is the default color (color set in xml)
public void changeColor() {
if (currentColor == Color.WHITE) {
currentColor = Color.BLUE;
} else {
currentColor = Color.WHITE;
}
GradientDrawable gd = (GradientDrawable)tvColor.getBackground();
gd.setColor(currentColor);
}

How to make layout with rounded corners..?

How can I make a layout with rounded corners? I want to apply rounded corners to my LinearLayout.
1: Define layout_bg.xml in drawables:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF"/>
<stroke android:width="3dp" android:color="#B1BCBE" />
<corners android:radius="10dp"/>
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
</shape>
2: Add layout_bg.xml as background to your layout
android:background="#drawable/layout_bg"
For API 21+, Use Clip Views
Rounded outline clipping was added to the View class in API 21. See this training doc or this reference for more info.
This in-built feature makes rounded corners very easy to implement. It works on any view or layout and supports proper clipping.
Here's What To Do:
Create a rounded shape drawable and set it as your view's background:
android:background="#drawable/round_outline"
Clip to outline in code: setClipToOutline(true)
The documentation used to say that you can set android:clipToOutline="true" the XML, but this bug is now finally resolved and the documentation now correctly states that you can only do this in code.
What It Looks Like:
Special Note About ImageViews
setClipToOutline() only works when the View's background is set to a shape drawable. If this background shape exists, View treats the background's outline as the borders for clipping and shadowing purposes.
This means that if you want to round the corners on an ImageView with setClipToOutline(), your image must come from android:src instead of android:background (since background is used for the rounded shape). If you MUST use background to set your image instead of src, you can use this nested views workaround:
Create an outer layout with its background set to your shape drawable
Wrap that layout around your ImageView (with no padding)
The ImageView (including anything else in the layout) will now be clipped to the outer layout's rounded shape.
Here's a copy of a XML file to create a drawable with a white background, black border and rounded corners:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ffffffff"/>
<stroke android:width="3dp"
android:color="#ff000000"
/>
<padding android:left="1dp"
android:top="1dp"
android:right="1dp"
android:bottom="1dp"
/>
<corners android:bottomRightRadius="7dp" android:bottomLeftRadius="7dp"
android:topLeftRadius="7dp" android:topRightRadius="7dp"/>
</shape>
save it as a xml file in the drawable directory,
Use it like you would use any drawable background(icon or resource file) using its resource name (R.drawable.your_xml_name)
Use CardView in android v7 support library.
Though it's a bit heavy, it solves all problem, and easy enough.
Not like the set drawable background method, it could clip subviews successfully.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="#android:color/transparent"
card_view:cardCornerRadius="5dp"
card_view:cardElevation="0dp"
card_view:contentPadding="0dp">
<YOUR_LINEARLAYOUT_HERE>
</android.support.v7.widget.CardView>
I have done this way:
Check Screenshot:
Create drawable file named with custom_rectangle.xml in drawable folder:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#android:color/white" />
<corners android:radius="10dip" />
<stroke
android:width="1dp"
android:color="#android:color/white" />
</shape>
Now apply Rectangle background on View:
mView.setBackground(R.drawlable.custom_rectangle);
Done
I think a better way to do it is to merge 2 things:
make a bitmap of the layout, as shown here.
make a rounded drawable from the bitmap, as shown here
set the drawable on an imageView.
This will handle cases that other solutions have failed to solve, such as having content that has corners.
I think it's also a bit more GPU-friendly, as it shows a single layer instead of 2 .
The only better way is to make a totally customized view, but that's a lot of code and might take a lot of time. I think that what I suggested here is the best of both worlds.
Here's a snippet of how it can be done:
RoundedCornersDrawable.java
/**
* shows a bitmap as if it had rounded corners. based on :
* http://rahulswackyworld.blogspot.co.il/2013/04/android-drawables-with-rounded_7.html
* easy alternative from support library: RoundedBitmapDrawableFactory.create( ...) ;
*/
public class RoundedCornersDrawable extends BitmapDrawable {
private final BitmapShader bitmapShader;
private final Paint p;
private final RectF rect;
private final float borderRadius;
public RoundedCornersDrawable(final Resources resources, final Bitmap bitmap, final float borderRadius) {
super(resources, bitmap);
bitmapShader = new BitmapShader(getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
final Bitmap b = getBitmap();
p = getPaint();
p.setAntiAlias(true);
p.setShader(bitmapShader);
final int w = b.getWidth(), h = b.getHeight();
rect = new RectF(0, 0, w, h);
this.borderRadius = borderRadius < 0 ? 0.15f * Math.min(w, h) : borderRadius;
}
#Override
public void draw(final Canvas canvas) {
canvas.drawRoundRect(rect, borderRadius, borderRadius, p);
}
}
CustomView.java
public class CustomView extends ImageView {
private View mMainContainer;
private boolean mIsDirty=false;
// TODO for each change of views/content, set mIsDirty to true and call invalidate
#Override
protected void onDraw(final Canvas canvas) {
if (mIsDirty) {
mIsDirty = false;
drawContent();
return;
}
super.onDraw(canvas);
}
/**
* draws the view's content to a bitmap. code based on :
* http://nadavfima.com/android-snippet-inflate-a-layout-draw-to-a-bitmap/
*/
public static Bitmap drawToBitmap(final View viewToDrawFrom, final int width, final int height) {
// Create a new bitmap and a new canvas using that bitmap
final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bmp);
viewToDrawFrom.setDrawingCacheEnabled(true);
// Supply measurements
viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(canvas.getWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(canvas.getHeight(), MeasureSpec.EXACTLY));
// Apply the measures so the layout would resize before drawing.
viewToDrawFrom.layout(0, 0, viewToDrawFrom.getMeasuredWidth(), viewToDrawFrom.getMeasuredHeight());
// and now the bmp object will actually contain the requested layout
canvas.drawBitmap(viewToDrawFrom.getDrawingCache(), 0, 0, new Paint());
return bmp;
}
private void drawContent() {
if (getMeasuredWidth() <= 0 || getMeasuredHeight() <= 0)
return;
final Bitmap bitmap = drawToBitmap(mMainContainer, getMeasuredWidth(), getMeasuredHeight());
final RoundedCornersDrawable drawable = new RoundedCornersDrawable(getResources(), bitmap, 15);
setImageDrawable(drawable);
}
}
EDIT: found a nice alternative, based on "RoundKornersLayouts" library. Have a class that will be used for all of the layout classes you wish to extend, to be rounded:
//based on https://github.com/JcMinarro/RoundKornerLayouts
class CanvasRounder(cornerRadius: Float, cornerStrokeColor: Int = 0, cornerStrokeWidth: Float = 0F) {
private val path = android.graphics.Path()
private lateinit var rectF: RectF
private var strokePaint: Paint?
var cornerRadius: Float = cornerRadius
set(value) {
field = value
resetPath()
}
init {
if (cornerStrokeWidth <= 0)
strokePaint = null
else {
strokePaint = Paint()
strokePaint!!.style = Paint.Style.STROKE
strokePaint!!.isAntiAlias = true
strokePaint!!.color = cornerStrokeColor
strokePaint!!.strokeWidth = cornerStrokeWidth
}
}
fun round(canvas: Canvas, drawFunction: (Canvas) -> Unit) {
val save = canvas.save()
canvas.clipPath(path)
drawFunction(canvas)
if (strokePaint != null)
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, strokePaint)
canvas.restoreToCount(save)
}
fun updateSize(currentWidth: Int, currentHeight: Int) {
rectF = android.graphics.RectF(0f, 0f, currentWidth.toFloat(), currentHeight.toFloat())
resetPath()
}
private fun resetPath() {
path.reset()
path.addRoundRect(rectF, cornerRadius, cornerRadius, Path.Direction.CW)
path.close()
}
}
Then, in each of your customized layout classes, add code similar to this one:
class RoundedConstraintLayout : ConstraintLayout {
private lateinit var canvasRounder: CanvasRounder
constructor(context: Context) : super(context) {
init(context, null, 0)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs, 0)
}
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
init(context, attrs, defStyle)
}
private fun init(context: Context, attrs: AttributeSet?, defStyle: Int) {
val array = context.obtainStyledAttributes(attrs, R.styleable.RoundedCornersView, 0, 0)
val cornerRadius = array.getDimension(R.styleable.RoundedCornersView_corner_radius, 0f)
val cornerStrokeColor = array.getColor(R.styleable.RoundedCornersView_corner_stroke_color, 0)
val cornerStrokeWidth = array.getDimension(R.styleable.RoundedCornersView_corner_stroke_width, 0f)
array.recycle()
canvasRounder = CanvasRounder(cornerRadius,cornerStrokeColor,cornerStrokeWidth)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
setLayerType(FrameLayout.LAYER_TYPE_SOFTWARE, null)
}
}
override fun onSizeChanged(currentWidth: Int, currentHeight: Int, oldWidth: Int, oldheight: Int) {
super.onSizeChanged(currentWidth, currentHeight, oldWidth, oldheight)
canvasRounder.updateSize(currentWidth, currentHeight)
}
override fun draw(canvas: Canvas) = canvasRounder.round(canvas) { super.draw(canvas) }
override fun dispatchDraw(canvas: Canvas) = canvasRounder.round(canvas) { super.dispatchDraw(canvas) }
}
If you wish to support attributes, use this as written on the library:
<resources>
<declare-styleable name="RoundedCornersView">
<attr name="corner_radius" format="dimension"/>
<attr name="corner_stroke_width" format="dimension"/>
<attr name="corner_stroke_color" format="color"/>
</declare-styleable>
</resources>
Another alternative, which might be easier for most uses: use MaterialCardView . It allows customizing the rounded corners, stroke color and width, and elevation.
Example:
<FrameLayout
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" android:clipChildren="false" android:clipToPadding="false"
tools:context=".MainActivity">
<com.google.android.material.card.MaterialCardView
android:layout_width="100dp" android:layout_height="100dp" android:layout_gravity="center"
app:cardCornerRadius="8dp" app:cardElevation="8dp" app:strokeColor="#f00" app:strokeWidth="2dp">
<ImageView
android:layout_width="match_parent" android:layout_height="match_parent" android:background="#0f0"/>
</com.google.android.material.card.MaterialCardView>
</FrameLayout>
And the result:
Do note that there is a slight artifacts issue at the edges of the stroke (leaves some pixels of the content there), if you use it. You can notice it if you zoom in. I've reported about this issue here.
EDIT: seems to be fixed, but not on the IDE. Reported here.
Step 1: Define bg_layout.xml in drawables folder, and put the below code in it.
Step 2: Add that bg_layout.xml as background to your layout, Done.
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid
android:color="#EEEEEE"/> <!--your desired colour for solid-->
<stroke
android:width="3dp"
android:color="#EEEEEE" /> <!--your desired colour for border-->
<corners
android:radius="50dp"/> <!--shape rounded value-->
</shape>
If you would like to make your layout rounded, it is best to use the CardView, it provided many features to make the design beautiful.
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".3"
android:text="#string/quote_code"
android:textColor="#color/white"
android:textSize="#dimen/text_head_size" />
</LinearLayout>
</android.support.v7.widget.CardView>
With this card_view:cardCornerRadius="5dp", you can change the radius.
Try this...
1.create drawable xml(custom_layout.xml):
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#FFFFFF" />
<stroke
android:width="2dp"
android:color="#FF785C" />
<corners android:radius="10dp" />
</shape>
2.add your view background
android:background="#drawable/custom_layout"
With the Material Components Library you can use the MaterialShapeDrawable to draw custom shapes.
Just put the LinearLayout in your xml layout:
<LinearLayout
android:id="#+id/linear_rounded"
android:layout_width="match_parent"
android:layout_height="wrap_content"
..>
<!-- content ..... -->
</LinearLayout>
Then in your code you can apply a ShapeAppearanceModel. Something like:
float radius = getResources().getDimension(R.dimen.default_corner_radius);
LinearLayout linearLayout= findViewById(R.id.linear_rounded);
ShapeAppearanceModel shapeAppearanceModel = new ShapeAppearanceModel()
.toBuilder()
.setAllCorners(CornerFamily.ROUNDED,radius)
.build();
MaterialShapeDrawable shapeDrawable = new MaterialShapeDrawable(shapeAppearanceModel);
//Fill the LinearLayout with your color
shapeDrawable.setFillColor(ContextCompat.getColorStateList(this,R.color.secondaryLightColor));
ViewCompat.setBackground(linearLayout,shapeDrawable);
Note:: it requires the version 1.1.0 of the material components library.
The best and simplest method would be to make use of card_background drawable in your layout. This also follows Google's material design guidelines. Just include this in you LinearLayout:
android:background="#drawable/card_background"
Add this to your drawable directory and name it card_background.xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#BDBDBD"/>
<corners android:radius="5dp"/>
</shape>
</item>
<item
android:left="0dp"
android:right="0dp"
android:top="0dp"
android:bottom="2dp">
<shape android:shape="rectangle">
<solid android:color="#ffffff"/>
<corners android:radius="5dp"/>
</shape>
</item>
</layer-list>
Function for set corner radius programmatically
static void setCornerRadius(GradientDrawable drawable, float topLeft,
float topRight, float bottomRight, float bottomLeft) {
drawable.setCornerRadii(new float[] { topLeft, topLeft, topRight, topRight,
bottomRight, bottomRight, bottomLeft, bottomLeft });
}
static void setCornerRadius(GradientDrawable drawable, float radius) {
drawable.setCornerRadius(radius);
}
Using
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.GREEN);
setCornerRadius(gradientDrawable, 20f);
//or setCornerRadius(gradientDrawable, 20f, 40f, 60f, 80f);
view.setBackground(gradientDrawable);
Use CardView to get rounded edges for any layouts.
Use card_view:cardCornerRadius="5dp" for cardview to get rounded layout edges.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="15dp"
android:weightSum="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".3"
android:text="#string/quote_code"
android:textColor="#color/white"
android:textSize="#dimen/text_head_size" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".7"
android:text="#string/quote_details"
android:textColor="#color/white"
android:textSize="#dimen/text_head_size" />
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
A better way to do it would be:
background_activity.xml
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:gravity="fill">
<color android:color="#color/black"/>
</item>
<item>
<shape android:gravity="fill">
<solid android:color="#color/white"/>
<corners android:radius="10dip"/>
<padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" />
</shape>
</item>
</layer-list>
This will work below API 21 also, and give you something like this:
If you are willing to make a little more effort more better control, then use android.support.v7.widget.CardView with its cardCornerRadius attribute (and set elevation attribute to 0dp to get rid of any accompanying drop shadow with the cardView). Also, this will work from API level as low as 15.
Create your xml in drawable, layout_background.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#color/your_colour" />
<stroke
android:width="2dp"
android:color="#color/your_colour" />
<corners android:radius="10dp" />
</shape>
<--width, color, radius should be as per your requirement-->
and then, add this in your layout.xml
android:background="#drawable/layout_background"
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF"/>
<stroke android:width="3dip" android:color="#B1BCBE" />
<corners android:radius="10dip"/>
<padding android:left="3dip" android:top="3dip" android:right="3dip" android:bottom="3dip" />
</shape>
#David, just put padding same value as stroke, so border can be visible, regardeless image size
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="#dimen/_10sdp"
android:shape="rectangle">
<solid android:color="#color/header" />
<corners
android:bottomLeftRadius="#dimen/_5sdp"
android:bottomRightRadius="#dimen/_5sdp"
android:topLeftRadius="#dimen/_5sdp"
android:topRightRadius="#dimen/_5sdp" />
I've taken #gauravsapiens answer with my comments inside to give you a reasonable apprehension of what the parameters will effect.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Background color -->
<solid android:color="#color/white" />
<!-- Stroke around the background, width and color -->
<stroke android:width="4dp" android:color="#color/drop_shadow"/>
<!-- The corners of the shape -->
<corners android:radius="4dp"/>
<!-- Padding for the background, e.g the Text inside a TextView will be
located differently -->
<padding android:left="10dp" android:right="10dp"
android:bottom="10dp" android:top="10dp" />
</shape>
If you're just looking to create a shape that rounds the corners, removing the padding and the stroke will do. If you remove the solid as well you will, in effect, have created rounded corners on a transparent background.
For the sake of being lazy I have created a shape underneath, which is just a solid white background with rounded corners - enjoy! :)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Background color -->
<solid android:color="#color/white" />
<!-- The corners of the shape -->
<corners android:radius="4dp"/>
</shape>
I'm a bit late to the party, but this is still a problem. So I wrote a set of OutlineProviders and BindingAdapters for data binding that enables you to clip corners from xml.
NOTE: Clipping with outline does not support corners to be different sizes!
I wrote a detailed response with code on this stackoverflow post
What you will get with code + binding adapter:
<androidx.constraintlayout.widget.ConstraintLayout
clipRadius="#{#dimen/some_radius}"
clipBottomLeft="#{#dimen/some_radius}"
clipBottomRight="#{#dimen/some_radius}"
clipTopLeft="#{#dimen/some_radius}"
clipTopRight="#{#dimen/some_radius}"
clipCircle="#{#bool/clip}"
This enables you to clip the view to a circle, round all corners, round corners in one direction (left, top, right, bottom) or single corners.
If what you want is just a simple rounded rectangle, cut the long story short.
float r=8;
ShapeDrawable shape =
new ShapeDrawable (new RoundRectShape(new float[] { r, r, r, r, r, r, r, r },null,null));
shape.getPaint().setColor(Color.RED);
view.setBackground(shape);
The first two floats are for the top-left corner (remaining pairs correspond clockwise).
for more details read this answer
You can do it with a custom view, like this RoundAppBar and RoundBottomAppBar.
Here a path is used to clipPath the canvas.

Categories

Resources