Android Animation - Scale up and Fade along with Background Transition - android

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);

Related

Android Layout transparent layout background with underline

I am trying to have a layout background drawable, which will be only gradient underline with 1-2 dp height and rest is transparent, so the upper part will have the parent's background.
Here is what I have.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android>
<!-- underline color -->
<item>
<shape>
<gradient
android:startColor="#color/colorPrimaryDark"
android:endColor="#FFFFFFFF"
android:centerY="0.5"
android:angle="0"/>
</shape>
</item>
<!-- main color -->
<item android:bottom="2.5dp">
<shape android:shape="rectangle">
<solid android:color="#color/white" />
<padding
android:top="4dp"
android:bottom="4dp" />
</shape>
</item>
If I change the solid color in "main color" to transparent, whole background will be using "underline color" settings.
The technique you use to create a line on the bottom of the view works if the color of the layer overlaying the gradient layer is opaque. What you are trying to do is to apply a transparent layer that replaces (erases) the underlying gradient. That is not how it works: A transparent overlay leaves the underlying color, here a gradient, untouched.
Here is an alternate layer-list drawable that you can use for API 23+:
underline_drawable.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:gravity="bottom">
<shape>
<size android:height="2dp" />
<gradient
android:angle="0"
android:centerY="0.5"
android:endColor="#FFFFFFFF"
android:startColor="#color/colorPrimaryDark" />
</shape>
</item>
</layer-list>
Here is what it looks like:
Prior to API 23, you can use the following custom drawable, but it must be set in code.
GradientUnderline.java
public class GradientUnderline extends Drawable {
private Shader mShader;
private final Paint mPaint;
private int mHeight = -1;
private int mStartColor = Color.BLACK;
private int mEndColor = Color.WHITE;
private int mLastWidth;
public GradientUnderline() {
mPaint = new Paint();
}
public GradientUnderline(int lineHeight, int startColor, int endColor) {
mPaint = new Paint();
mHeight = lineHeight;
mStartColor = startColor;
mEndColor = endColor;
}
#Override
public void draw(#NonNull Canvas canvas) {
if (mShader == null || getBounds().width() != mLastWidth) {
mLastWidth = getBounds().width();
mShader = new LinearGradient(0, 0, getBounds().width(), mHeight, mStartColor,
mEndColor, Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
}
canvas.drawRect(0, getBounds().height() - mHeight, getBounds().width(),
getBounds().height(), mPaint);
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(#Nullable ColorFilter colorFilter) {
}
#Override
public int getOpacity() {
return PixelFormat.OPAQUE;
}
}
I missed the availability of android:gravity initially because it is not mentioned on the "Drawable Resources" page. It is mentioned, however, in the LayerDrawable documentation.
Why problem occurs: Shape at first item will draw the gradient in entire region. After setting colour to second item will hide the top item region except ay 2.5dp at bottom. So whenever you set transparent colour to second item it automatically show the top level item that is gradient region..
Here i suggest the way to use but you can set to fixed height in view.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:top="47dp">
<shape>
<gradient
android:startColor="#color/colorPrimaryDark"
android:endColor="#FFFFFFFF"
android:centerY="0.5"
android:angle="0"/>
</shape>
</item>
</layer-list>
View.xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#drawable/bottom_line">
</RelativeLayout>
Change size according to your needs..!
OUTPUT

Animate layout's background color change

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();

How to programmatically create or alter a drawable made of lines of different colors

I have to draw a 3dp line to represent a level completion in a quizz game.
This line must be of 2 colors. For example, if user has completed 40% of the level, the line will be red for the first 40% of the line, the other 60% being grey.
I have managed to do that with a drawable :
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="line" >
<size android:height="3dp" android:width="40dp"/>
<stroke
android:width="1dp"
android:color="#FFFC10" />
</shape>
</item>
<item android:left="40dp">
<shape android:shape="line" >
<size android:height="3dp" android:width="60dp" />
<stroke
android:width="1dp"
android:color="#DDDDDD" />
</shape>
</item>
</layer-list>
And then I display it with an ImageView :
<ImageView
android:id="#+id/row_completion_bar"
android:src="#drawable/completion_bar"
android:layout_width="100dp"
android:layout_height="3dp" />
... but now, I must of course be able to change this 40%/60% ration depending of the actuel user completion.
First question: what is the best most efficient way to do it ? Change the drawable at runtime ? or create a new drawable at runtime in Java ?
Second question: how to do it ? I tried both ways (recreate this drawable in java code / alter the xml drawable at runtime) and didn't succeeded :-(
Any help will be greatly appreciated.
so this is a custom Drawable you can use:
class LineDrawable extends Drawable {
private Paint mPaint;
public LineDrawable() {
mPaint = new Paint();
mPaint.setStrokeWidth(3);
}
#Override
public void draw(Canvas canvas) {
int lvl = getLevel();
Rect b = getBounds();
float x = b.width() * lvl / 10000.0f;
float y = (b.height() - mPaint.getStrokeWidth()) / 2;
mPaint.setColor(0xffff0000);
canvas.drawLine(0, y, x, y, mPaint);
mPaint.setColor(0xff00ff00);
canvas.drawLine(x, y, b.width(), y, mPaint);
}
#Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter cf) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
and the test code:
View v = new View(this);
final LineDrawable d = new LineDrawable();
d.setLevel(4000);
v.setBackgroundDrawable(d);
setContentView(v);
OnTouchListener l = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int lvl = (int) (10000 * event.getX() / v.getWidth());
d.setLevel(lvl);
return true;
}
};
v.setOnTouchListener(l);
How about using a progress bar? The style of the done and to-do markers can be set either programatically or via xml files.
Your code will also be more readable/maintainable because you'll be using the right widget for the job. Your layout will contain:
<ProgressBar
android:id="#+id/progressBar"
android:layout_height="3dip"
android:layout_width="match_parent"
android:progressDrawable="#drawable/progress_bar" />
You can update the bar from your code using e.g.:
ProgressBar bar = (ProgressBar)findViewById(R.id.progressBar);
bar.setProgress(40);
This example overrides the style of the bar (as directed by the progressDrawable attribute), using a res/drawable/progress_bar.xml file - contents below. This one has extra niceness like gradient shading and rounded corners; adjust as you see fit:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#android:id/background">
<shape>
<corners android:radius="5dip" />
<gradient
android:angle="270"
android:centerColor="#ff5a5d5a"
android:centerY="0.5"
android:endColor="#ff747674"
android:startColor="#ff9d9e9d" />
</shape>
</item>
<item android:id="#android:id/progress">
<clip>
<shape>
<corners android:radius="5dip" />
<gradient
android:angle="0"
android:endColor="#ff009900"
android:startColor="#ff000099" />
</shape>
</clip>
</item>
</layer-list>
Credit to http://www.tiemenschut.com/how-to-customize-android-progress-bars/, which gives much more detail on how to customise progress bars.
I found a way to do this. Don't know if it's the most efficient way, but here it is:
I used a RelativeLayout to superpose ImageViews with background color.
in layout.xml:
<RelativeLayout style="#style/CompletionBar">
<ImageView
android:id="#+id/row_completion_bar_0"
style="#style/CompletionBar0" />
<ImageView
android:id="#+id/row_completion_bar_1"
style="#style/CompletionBar1" />
</RelativeLayout>
in styles.xml:
<!-- Completion Bar (Relative Layout) -->
<style name="CompletionBar">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
<!-- Completion Bar 0 (ImageView) -->
<style name="CompletionBar0">
<item name="android:layout_width">100dp</item>
<item name="android:layout_height">2dp</item>
<item name="android:background">#CCCCCC</item>
</style>
<!-- Completion Bar 1 (ImageView) -->
<style name="CompletionBar1">
<item name="android:layout_width">40dp</item>
<item name="android:layout_height">2dp</item>
<item name="android:background">#555555</item>
</style>
in java file:
ImageView cb1 = (ImageView)row.findViewById(R.id.row_completion_bar_1);
cb1.getLayoutParams().width = 40; /* Value in pixels, must convert to dp */
This snippet will work for all api
Use this:
Drawable drawable = editText.getBackground();
drawable.setColorFilter(editTextColor, PorterDuff.Mode.SRC_ATOP);
if(Build.VERSION.SDK_INT > 16) {
editText.setBackground(drawable);
}else{
editText.setBackgroundDrawable(drawable);
}

Rectangle shape with two solid colors

I'd like to create a rectangle shape with two solid colors (horizontally) to achieve something like this:
I heard about layer-list, i though i could use it to contains two rectangle with a different color but it seems that it only lays shapes vertically.
Is there a way to achieve this using lalyer-list or should i use something totally different? I'd like to keep it simple with ability to change the shape colors at runtime.
Thanks.
this will surely draw the shape as per your Requirement :
Adjust size of <item> as you need !
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:left="50dip">
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#0000FF" />
</shape>
</item>
<item android:right="50dip">
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#ff0000" />
</shape>
</item>
</layer-list>
You can create custom drawable for this. Just extend Drawable class.
Here is a sample code which draws a rectangle like you wanted, you can provide any number of colors.
public class ColorBarDrawable extends Drawable {
private int[] themeColors;
public ColorBarDrawable(int[] themeColors) {
this.themeColors = themeColors;
}
#Override
public void draw(Canvas canvas) {
// get drawable dimensions
Rect bounds = getBounds();
int width = bounds.right - bounds.left;
int height = bounds.bottom - bounds.top;
// draw background gradient
Paint backgroundPaint = new Paint();
int barWidth = width / themeColors.length;
int barWidthRemainder = width % themeColors.length;
for (int i = 0; i < themeColors.length; i++) {
backgroundPaint.setColor(themeColors[i]);
canvas.drawRect(i * barWidth, 0, (i + 1) * barWidth, height, backgroundPaint);
}
// draw remainder, if exists
if (barWidthRemainder > 0) {
canvas.drawRect(themeColors.length * barWidth, 0, themeColors.length * barWidth + barWidthRemainder, height, backgroundPaint);
}
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter cf) {
}
#Override
public int getOpacity() {
return PixelFormat.OPAQUE;
}
}
This will give you two colors half and half vertically. Put this code in a drawable resource.
<item
android:top="320dip">
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#color/red" />
</shape>
</item>
<item android:bottom="320dip">
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#color/yellow" />
</shape>
</item>

How do I create a ListView with rounded corners in Android?

How do I create a ListView with rounded corners in Android?
Here is one way of doing it (Thanks to Android Documentation though!):
Add the following into a file (say customshape.xml) and then place it in (res/drawable/customshape.xml)
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#SomeGradientBeginColor"
android:endColor="#SomeGradientEndColor"
android:angle="270"/>
<corners
android:bottomRightRadius="7dp"
android:bottomLeftRadius="7dp"
android:topLeftRadius="7dp"
android:topRightRadius="7dp"/>
</shape>
Once you are done with creating this file, just set the background in one of the following ways:
Through Code:
listView.setBackgroundResource(R.drawable.customshape);
Through XML, just add the following attribute to the container (ex: LinearLayout or to any fields):
android:background="#drawable/customshape"
Hope someone finds it useful...
Although that did work, it took out the entire background colour as well. I was looking for a way to do just the border and just replace that XML layout code with this one and I was good to go!
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="4dp" android:color="#FF00FF00" />
<padding android:left="7dp" android:top="7dp"
android:right="7dp" android:bottom="7dp" />
<corners android:radius="4dp" />
</shape>
#kris-van-bael
For those having issues with selection highlight for the top and bottom row where the background rectangle shows up on selection you need to set the selector for your listview to transparent color.
listView.setSelector(R.color.transparent);
In color.xml just add the following -
<color name="transparent">#00000000</color>
Update
The solution these days is to use a CardView with support for rounded corners built in.
Original answer*
Another way I found was to mask out your layout by drawing an image over the top of the layout. It might help you. Check out Android XML rounded clipped corners
The other answers are very useful, thanks to the authors!
But I could not see how to customise the rectangle when highlighting an item upon selection rather than disabling the highlighting #alvins #bharat dojeha.
The following works for me to create a rounded list view item container with no outline and a lighter grey when selected of the same shape:
Your xml needs to contain a selector such as e.g. ( in res/drawable/customshape.xml):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true" >
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke android:width="8dp" android:color="#android:color/transparent" />
<padding android:left="14dp" android:top="14dp"
android:right="14dp" android:bottom="14dp" />
<corners android:radius="10dp" />
<gradient
android:startColor="#android:color/background_light"
android:endColor="#android:color/transparent"
android:angle="225"/>
</shape>
</item>
<item android:state_pressed="false">
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke android:width="8dp" android:color="#android:color/transparent" />
<padding android:left="14dp" android:top="14dp"
android:right="14dp" android:bottom="14dp" />
<corners android:radius="10dp" />
<gradient
android:startColor="#android:color/darker_gray"
android:endColor="#android:color/transparent"
android:angle="225"/>
</shape>
</item>
Then you need to implement a list adapter and override the getView method to set the custom selector as background
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//snip
convertView.setBackgroundResource(R.drawable.customshape);
//snip
}
and need to also 'hide' the default selector rectangle e.g in onCreate (I also hide my thin grey divider line between the items):
listView.setSelector(android.R.color.transparent);
listview.setDivider(null);
This approach solves a general solution for drawables, not just ListViewItem with various selection states.
Yet another solution to selection highlight problems with first, and last items in the list:
Add padding to the top and bottom of your list background equal to or greater than the radius. This ensures the selection highlighting doesn't overlap with your corner curves.
This is the easiest solution when you need non-transparent selection highlighting.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#color/listbg" />
<stroke
android:width="2dip"
android:color="#D5D5D5" />
<corners android:radius="10dip" />
<!-- Make sure bottom and top padding match corner radius -->
<padding
android:bottom="10dip"
android:left="2dip"
android:right="2dip"
android:top="10dip" />
</shape>
actually, i think the best solution is described on this link:
http://blog.synyx.de/2011/11/android-listview-with-rounded-corners/
in short, it uses a different background for the top, middle and bottom items, so that the top and bottom ones would be rounded.
This was incredibly handy to me. I would like to suggest another workaround to perfectly highlight the rounded corners if you are using your own CustomAdapter.
Defining XML Files
First of all, go inside your drawable folder and create 4 different shapes:
shape_top
<gradient
android:startColor="#ffffff"
android:endColor="#ffffff"
android:angle="270"/>
<corners
android:topLeftRadius="10dp"
android:topRightRadius="10dp"/>
shape_normal
<gradient
android:startColor="#ffffff"
android:endColor="#ffffff"
android:angle="270"/>
<corners
android:topLeftRadius="10dp"
android:topRightRadius="10dp"/>
shape_bottom
<gradient
android:startColor="#ffffff"
android:endColor="#ffffff"
android:angle="270"/>
<corners
android:bottomRightRadius="10dp"
android:bottomRightRadius="10dp"/>
shape_rounded
<gradient
android:startColor="#ffffff"
android:endColor="#ffffff"
android:angle="270"/>
<corners
android:topLeftRadius="10dp"
android:topRightRadius="10dp"
android:bottomRightRadius="10dp"
android:bottomRightRadius="10dp"/>
Now, create a different row layout for each shape, i.e. for shape_top :
You can also do this programatically changing the background.
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="20dp"
android:layout_marginRight="10dp"
android:fontFamily="sans-serif-light"
android:text="TextView"
android:textSize="22dp" />
<TextView
android:id="#+id/txtValue1"
android:layout_width="match_parent"
android:layout_height="48dp"
android:textSize="22dp"
android:layout_gravity="right|center"
android:gravity="center|right"
android:layout_marginLeft="20dp"
android:layout_marginRight="35dp"
android:text="Fix"
android:scaleType="fitEnd" />
And define a selector for each shaped-list, i.e. for shape_top:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Selected Item -->
<item android:state_selected="true"
android:drawable="#drawable/shape_top" />
<item android:state_activated="true"
android:drawable="#drawable/shape_top" />
<!-- Default Item -->
<item android:state_selected="false"
android:drawable="#android:color/transparent" />
</selector>
Change your CustomAdapter
Finally, define the layout options inside your CustomAdapter:
if(position==0)
{
convertView = mInflater.inflate(R.layout.list_layout_top, null);
}
else
{
convertView = mInflater.inflate(R.layout.list_layout_normal, null);
}
if(position==getCount()-1)
{
convertView = mInflater.inflate(R.layout.list_layout_bottom, null);
}
if(getCount()==1)
{
convertView = mInflater.inflate(R.layout.list_layout_unique, null);
}
And that's done!
to make border u have to make another xml file with property of solid and corners in the drawable folder and calls it in background
I'm using a custom view that I layout on top of the other ones and that just draws the 4 small corners in the same color as the background. This works whatever the view contents are and does not allocate much memory.
public class RoundedCornersView extends View {
private float mRadius;
private int mColor = Color.WHITE;
private Paint mPaint;
private Path mPath;
public RoundedCornersView(Context context) {
super(context);
init();
}
public RoundedCornersView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.RoundedCornersView,
0, 0);
try {
setRadius(a.getDimension(R.styleable.RoundedCornersView_radius, 0));
setColor(a.getColor(R.styleable.RoundedCornersView_cornersColor, Color.WHITE));
} finally {
a.recycle();
}
}
private void init() {
setColor(mColor);
setRadius(mRadius);
}
private void setColor(int color) {
mColor = color;
mPaint = new Paint();
mPaint.setColor(mColor);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
invalidate();
}
private void setRadius(float radius) {
mRadius = radius;
RectF r = new RectF(0, 0, 2 * mRadius, 2 * mRadius);
mPath = new Path();
mPath.moveTo(0,0);
mPath.lineTo(0, mRadius);
mPath.arcTo(r, 180, 90);
mPath.lineTo(0,0);
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
/*Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawRect(0, 0, mRadius, mRadius, paint);*/
int w = getWidth();
int h = getHeight();
canvas.drawPath(mPath, mPaint);
canvas.save();
canvas.translate(w, 0);
canvas.rotate(90);
canvas.drawPath(mPath, mPaint);
canvas.restore();
canvas.save();
canvas.translate(w, h);
canvas.rotate(180);
canvas.drawPath(mPath, mPaint);
canvas.restore();
canvas.translate(0, h);
canvas.rotate(270);
canvas.drawPath(mPath, mPaint);
}
}
There are different ways to achieve it. The latest approach is using CardView for each ListItem component.
Here are some steps.
Create a layout resource file; let's name it "listitem.xml
Copy and paste the under enclosed Listitem.xml layout body into it.
Create RowItem class for each listitem data; later you will instantiate this to assign values for each list item. Check Code below, RowItem.class.
Create a custom ListAdapter; let's name it ListAdapter.class, and inflate this (#1) list item layout for each list item (Check the second code snippet for this one)
Set this adapter (#3) the way you set default adapters inside an activity the listview belongs to. maybe the only difference would be you first have to instantiate RowItem class with values and add RowItem object to your adapter then notify your adapter that the data is changed.
**listitem.xml**
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="vertical">
<GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alignmentMode="alignMargins"
android:columnCount="1"
android:columnOrderPreserved="false"
android:rowCount="1">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:layout_margin="6dp"
app:cardCornerRadius="8dp"
app:cardElevation="6dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="#+id/sampleiconimageID"
android:layout_width="60dp"
android:layout_height="60dp"
android:padding="5dp"/>
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/titleoflistview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Main Heading"
android:textStyle="bold" />
<TextView
android:id="#+id/samplesubtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sub Heading"
/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</GridLayout>
</LinearLayout>
RowItem.Class
public class RowItem {
private String heading;
private String subHeading;
private int smallImageName;
private String datetime;
private int count;
public void setHeading( String theHeading ) {
this.heading = theHeading;
}
public String getHeading() {
return this.heading;
}
public void setSubHeading( String theSubHeading ) {
this.subHeading = theSubHeading;
}
public String getSubHeading( ) {
return this.subHeading;
}
public void setSmallImageName(int smallName) {
this.smallImageName = smallName;
}
public int getSmallImageName() {
return this.smallImageName;
}
public void setDate(String datetime) {
this.datetime = datetime;
}
public String getDate() {
return this.datetime;
}
public void setCount(int count) {
this.count = count;
}
public int getCount() {
return this.count;
}
}
Sample ListAdapter
public class ListAdapter extends BaseAdapter {
private ArrayList<RowItem> singleRow;
private LayoutInflater thisInflater;
public ListAdapter(Context context, ArrayList<RowItem> aRow){
this.singleRow = aRow;
thisInflater = ( LayoutInflater.from(context) );
}
#Override
public int getCount() {
return singleRow.size(); }
#Override
public Object getItem(int position) {
return singleRow.get( position ); }
#Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
view = thisInflater.inflate( R.layout.mylist2, parent, false );
//set listview objects here
//example
TextView titleText = (TextView) view.findViewById(R.id.titleoflistview);
RowItem currentRow = (RowItem) getItem(position);
titleText.setText( currentRow.getHeading() );
}
return view;
// LayoutInflater inflater=.getLayoutInflater();
// View rowView=inflater.inflate(R.layout.mylist, null,true);
//
// titleText.setText(maintitle[position]);
// subtitleText.setText(subtitle[position]);
// return null;
};
}

Categories

Resources