I am trying to use a ProgressBar as a metering like display. I thought it was going to be an easy task and thought that ProgressBar had a property to set to be vertical, but I'm not seeing anything.
Additionally I'd like to be able to show ruler like indicator along the side of the bar to clearly indicate the current level.
Pointers appreciated - Thanks!
I had recently come across the need for a vertical progress bar but was unable to find a solution using the existing Progress Bar widget. The solutions I came across generally required an extension of the current Progress Bar or a completely new class in it self. I wasn't convinced rolling out a new class to achieve a simple orientation change was necessary.
This article presents a simple, elegant, and most importantly, a no-hack solution to achieving a vertical progress bar.
I'm going to skip the explanation and simply provide a cookie cutter solution. If you require further details feel free to contact me or leave a comment below.
Create an xml in your drawable folder (not drawable-hdpi or drawable-mdpi -- place it in drawable). For this example I call my xml vertical_progress_bar.xml
Here's what to place in the xml file:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ff9d9e9d"
android:centerColor="#ff5a5d5a"
android:centerY="0.75"
android:endColor="#ff747674"
android:angle="180"
/>
</shape>
</item>
<item android:id="#android:id/secondaryProgress">
<clip android:clipOrientation="vertical" android:gravity="bottom">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#80ffd300"
android:centerColor="#80ffb600"
android:centerY="0.75"
android:endColor="#a0ffcb00"
android:angle="180"
/>
</shape>
</clip>
</item>
<item android:id="#android:id/progress">
<clip android:clipOrientation="vertical" android:gravity="bottom">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ffffd300"
android:centerColor="#ffffb600"
android:centerY="0.75"
android:endColor="#ffffcb00"
android:angle="180"
/>
</shape>
</clip>
</item>
</layer-list>
Create an xml file called styles.xml and place it in res/values. If your project already contains styles.xml in res/values then skip this step.
Modify your styles.xml file and append the following code to the end of the file:
<style name="Widget">
</style>
<style name="Widget.ProgressBar">
<item name="android:indeterminateOnly">true</item>
<item name="android:indeterminateBehavior">repeat</item>
<item name="android:indeterminateDuration">3500</item>
<item name="android:minWidth">48dip</item>
<item name="android:maxWidth">48dip</item>
<item name="android:minHeight">48dip</item>
<item name="android:maxHeight">48dip</item>
</style>
<style name="Widget.ProgressBar.Vertical">
<item name="android:indeterminateOnly">false</item>
<item name="android:progressDrawable">#drawable/progress_bar_vertical</item>
<item name="android:indeterminateDrawable">#android:drawable/progress_indeterminate_horizontal</item>
<item name="android:minWidth">1dip</item>
<item name="android:maxWidth">12dip</item>
</style>
Add your new vertical progress bar to your layout. Here's an example:
<ProgressBar
android:id="#+id/vertical_progressbar"
android:layout_width="12dip"
android:layout_height="300dip"
style="#style/Widget.ProgressBar.Vertical"
/>
That should be all you need to do to make use of a vertical progress bar in your project. Optionally, you might have custom drawable nine-patch images that you are using for the progress bar. You should make the appropriate changes in the progress_bar_vertical.xml file.
I hope this helps you out in your project!
You have to create your own custom progressbar.
In your xml add this layout:
<com.example.component.VerticalProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:id="#+id/verticalRatingBar1"
android:layout_width="wrap_content"
android:progress="50"
android:layout_height="fill_parent" />
VerticalProgressBar.java
public class VerticalProgressBar extends ProgressBar{
private int x, y, z, w;
#Override
protected void drawableStateChanged() {
// TODO Auto-generated method stub
super.drawableStateChanged();
}
public VerticalProgressBar(Context context) {
super(context);
}
public VerticalProgressBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
this.x = w;
this.y = h;
this.z = oldw;
this.w = oldh;
}
#Override
protected synchronized void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas c) {
c.rotate(-90);
c.translate(-getHeight(), 0);
super.onDraw(c);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setSelected(true);
setPressed(true);
break;
case MotionEvent.ACTION_MOVE:
setProgress(getMax()
- (int) (getMax() * event.getY() / getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
break;
case MotionEvent.ACTION_UP:
setSelected(false);
setPressed(false);
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
#Override
public synchronized void setProgress(int progress) {
if (progress >= 0)
super.setProgress(progress);
else
super.setProgress(0);
onSizeChanged(x, y, z, w);
}
}
Or :
Jagsaund solution is also being perfect.
I know that it´s an old post but I found a very simple solution to this problem that maybe can help somebody.
First at all create a progress_drawable_vertical.xml like this:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<color android:color="#777" />
</item>
<item android:id="#android:id/progress">
<clip
android:clipOrientation="vertical"
android:gravity="bottom">
<shape>
<gradient
android:startColor="#00FF00"
android:centerColor="#FFFF00"
android:endColor="#FF0000"
android:angle="90" />
</shape>
</clip>
</item>
</layer-list>
Then just use this in your progressBar:
<ProgressBar
android:id="#+id/progress_bar"
style="#android:style/Widget.ProgressBar.Horizontal"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:max="100"
android:progress="33"
android:progressDrawable="#drawable/progress_drawable_vertical" />
I also have created an progress_drawable_horizontal.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<color android:color="#777" />
</item>
<item android:id="#android:id/progress">
<clip
android:clipOrientation="horizontal"
android:gravity="left">
<shape>
<gradient
android:startColor="#00FF00"
android:centerColor="#FFFF00"
android:endColor="#FF0000" />
</shape>
</clip>
</item>
</layer-list>
with the objetive of mantain the same style defined in progress_drawable_vertical.xml
The key here is the correct use of android:clipOrientation and android:gravity.
I found this solution here and the core of the solution is similar to jagsaund but a little bit more simple.
I found the probably best(easiest & most versatile) solution:)
This is an old post, but it was so hard for me to find this so easy solution so I thought I should post it..
Just use a scale-drawable (or a 9-patch if you want), no need for ANY OTHER code.
Example:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background" android:drawable="#color/transparent"/>
<item android:id="#android:id/progress">
<scale android:scaleGravity="bottom" android:scaleWidth="0%" android:scaleHeight="100%">
<shape >
<solid android:color="#color/blue"/>
<corners android:topRightRadius="1dp" android:topLeftRadius="1dp"/>
</shape>
</scale>
</item>
</layer-list>
And of course the normal code:
<ProgressBar
android:id="#+id/progress_bar"
style="#android:style/Widget.ProgressBar.Horizontal"
android:layout_width="24dp"
android:layout_height="match_parent"
android:max="1000"
android:progress="200"
android:progressDrawable="#drawable/progress_scale_drawable" />
Notice the scale-drawable's xml lines (the magic lines):
android:scaleGravity="bottom" //scale from 0 in y axis (default scales from center Y)
android:scaleWidth="0%" //don't scale width (according to 'progress')
android:scaleHeight="100%" //do scale the height of the drawable
This perfectly works
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<shape>
<gradient
android:startColor="#DDDDDD"
android:centerColor="#DDDDDD"
android:centerY="0.75"
android:endColor="#DDDDDD"
android:angle="270"
/>
</shape>
</item>
<item
android:id="#android:id/progress">
<clip
android:clipOrientation="vertical"
android:gravity="top">
<shape>
<gradient
android:angle="0"
android:startColor="#302367"
android:centerColor="#7A5667"
android:endColor="#C86D67"/>
</shape>
</clip>
</item>
</layer-list>
<ProgressBar
android:id="#+id/progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="5dp"
android:layout_height="match_parent"`enter code here`
android:progressDrawable="#drawable/progress_dialog"/>
Creating the progress bar (I converted my code from c# to java so might not be 100% correct)
ProgressBar progBar = new ProgressBar(Context, null, Android.resource.attribute.progressDrawable);
progBar.progressDrawable = ContextCompat.getDrawable(Context, resource.drawable.vertical_progress_bar);
progBar.indeterminate = false;
vertical_progress_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#android:id/background">
<shape>
<solid android:color="#color/grey" />
<corners android:radius="20dip" />
</shape>
</item>
<item android:id="#android:id/progress">
<scale
android:drawable="#drawable/vertical_progress_bar_blue_progress"
android:scaleHeight="100%"
android:scaleGravity="bottom"/>
</item>
</layer-list>
vertical_progress_bar_blue_progress.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<corners
android:radius="20dip" />
<solid android:color="#color/ProgressBarFourth" />
</shape>
What's going to make your bar vertical is the scaleHeight and scaleGravity attributes in vertical_progress_bar.xml.
It ends up looking something like this:
Simple and Easy way:
Just add a view to a LinearLayout and scale it.
<LinearLayout
android:layout_width="4dp"
android:layout_height="300dp"
android:background="#color/md_green_50"
android:orientation="vertical">
<View
android:id="#+id/progressView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="top"
android:layout_weight="1"
android:background="#color/md_green_500"
android:scaleY="0.0" />
</LinearLayout>
Set View's pivotY to zero:
progressView.pivotY = 0F
Now you can fill the progress using scaleY between 0F and 1F:
progressView.scaleY = 0.3F
Bonus:
Animate progress using animate():
progressView.animate().scaleY(0.3F).start()
Here is a simple solution, just rotate your progress bar
android:rotation="270"
Add this to the xml code
android:rotation="90"
android:transformPivotX="0dp"
So this is how your Progress Bar xml should look
<ProgressBar
android:id="#+id/progressBar6"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:rotation="90"
android:transformPivotX="0dp"
tools:layout_editor_absoluteX="101dp"
tools:layout_editor_absoluteY="187dp" />
To utilize the ProgressBar and make it vertical, you would have to create your own custom View extending the ProgressBar view and override the onDraw() method. This will allow you to draw it in a reverse orientation. Take a look at the source code of the ProgressBar.onDraw() (located at the bottom of the link) for help on how to do this. Best case scenario, you'll just have to swap a few x and y variables.
I have the exact problem. Making a custom class (extending ProgressBar) will create code that are hard to maintain. Using a custom style will cause compatibility issue with different theme from new OS (e.g. lollipop)
Eventually, I just apply a rotation animation to an horizontal progress bar. Inspired by Pete.
Create the tag in your layout xml like normal horizontal progress bar.
Make sure that the size and position of the ProgressBar is what you want after rotation. (Perhaps setting negative margin will help). In my code I rotate the view from 0,0.
Use the method below to rotate and set new progress.
Code:
private void setProgress(final ProgressBar progressBar, int progress) {
progressBar.setWillNotDraw(true);
progressBar.setProgress(progress);
progressBar.setWillNotDraw(false);
progressBar.invalidate();
}
private void rotateView(final View v, float degree) {
Animation an = new RotateAnimation(0.0f, degree);
an.setDuration(0);
an.setRepeatCount(0);
an.setFillAfter(true); // keep rotation after animation
v.setAnimation(an);
}
Simple progrebar image view
example
viewHolder.proBarTrueImage.setMaximalValue(147);
viewHolder.proBarTrueImage.setLevel(45);
viewHolder.proBarTrueImage.setColorResource(R.color.corner_blue);
simple class
public class ProgressImageView extends ImageView {
private Context mContext;
private Paint paint;
private RectF rectf;
private int maximalValue = 1;
private int level = 0;
private int width;
private int height;
public ProgressImageView(Context context) {
super(context);
init(context, null, 0);
}
public ProgressImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public ProgressImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr){
mContext = context;
paint = new Paint();
rectf = new RectF();
paint.setColor(Color.GRAY);
paint.setStyle(Paint.Style.FILL);
};
#Override
protected void onDraw(Canvas canvas) {
float dif = (float) height / (float) maximalValue;
int newHeight = height - (int) (dif * level);
rectf.set(0,newHeight, width, height);
canvas.drawRect(rectf, paint);
super.onDraw(canvas);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
this.width = w;
this.height = h;
}
public void setMaximalValue(int maximalValue) {
this.maximalValue = maximalValue;
invalidate();
}
public void setLevel(int level) {
this.level = level;
invalidate();
}
public void setColorResource(int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
color = mContext.getResources().getColor(color,mContext.getTheme());
}else {
color = mContext.getResources().getColor(R.color.corner_blue);
}
setColor(color);
}
public void setColor(int color){
if (paint != null){
paint.setColor(color);
invalidate();
}
}
}
<ProgressBar
android:id="#+id/battery_pb"
android:rotation="270"
android:progress="100"
...
/>
Use android:rotation="270" to 100% be like bottom to top or android:rotation="90" to 100% be like top to bottom
enter link description here
**Check this link out, I was trying to use a similar thing and also you can use stepper for your requirement, few projects are available on Github about HOW TO USE STEPPER IN ANDROID STUDIO **
For making a vertical ProgressBar, The way that I solved it was first rotating it by 90 degrees, then scaling it with a value entered by hand.
scaleX = layout_height/layout_width
Here's an example of my attributes on the ProgressBar
android:layout_width="20dp"
android:layout_height="233dp"
android:rotation="-90"
android:scaleX="11.65"
This can be a little manual, but because they don't have a vertical progress bar by default, this was a pretty good workaround for me. The scaleX could be calculated automatically, but it would have to be after everything is drawn on the screen.
Vertical progress bars are not supported by default.
Related
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);
}
How can I show shadow for my linear layout. I want white colored rounded background with shadow around the linearlayout. I have done this so far.
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#xml/rounded_rect_shape"
android:orientation="vertical"
android:padding="10dp">
<-- My buttons, textviews, Imageviews go here -->
</LinearLayout>
And rounded_rect_shape.xml under xml directory
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#ffffff" />
<corners
android:bottomLeftRadius="3dp"
android:bottomRightRadius="3dp"
android:topLeftRadius="3dp"
android:topRightRadius="3dp" />
</shape>
There is also another solution to the problem by implementing a layer-list that will act as the background for the LinearLayoout.
Add background_with_shadow.xml file to res/drawable. Containing:
<?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="#android:color/darker_gray" />
<corners android:radius="5dp"/>
</shape>
</item>
<item android:right="1dp" android:left="1dp" android:bottom="2dp">
<shape
android:shape="rectangle">
<solid android:color="#android:color/white"/>
<corners android:radius="5dp"/>
</shape>
</item>
</layer-list>
Then add the the layer-list as background in your LinearLayout.
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/background_with_shadow"/>
Well, this is easy to achieve .
Just build a GradientDrawable that comes from black and goes to a transparent color, than use parent relationship to place your shape close to the View that you want to have a shadow, then you just have to give any values to height or width .
Here is an example, this file have to be created inside res/drawable , I name it as shadow.xml :
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#9444"
android:endColor="#0000"
android:type="linear"
android:angle="90"> <!-- Change this value to have the correct shadow angle, must be multiple from 45 -->
</gradient>
</shape>
Place the following code above from a LinearLayout , for example, set the android:layout_width and android:layout_height to fill_parent and 2.3dp, you'll have a nice shadow effect on your LinearLayout .
<View
android:id="#+id/shadow"
android:layout_width="fill_parent"
android:layout_height="2.3dp"
android:layout_above="#+id/id_from_your_LinearLayout"
android:background="#drawable/shadow">
</View>
Note 1: If you increase android:layout_height more shadow will be shown .
Note 2: Use android:layout_above="#+id/id_from_your_LinearLayout" attribute if you are placing this code inside a RelativeLayout, otherwise ignore it.
Hope it help someone.
There is no such attribute in Android, to show a shadow. But possible ways to do it are:
Add a plain LinearLayout with grey color, over which add your actual layout, with margin at bottom and right equal to 1 or 2 dp
Have a 9-patch image with a shadow and set it as the background to your Linear layout
For lollipop and above you can use elevation.
For older versions:
Here is a lazy hack from:
http://odedhb.blogspot.com/2013/05/android-layout-shadow-without-9-patch.html
(toast_frame does not work on KitKat, shadow was removed from toasts)
just use:
android:background="#android:drawable/toast_frame"
or:
android:background="#android:drawable/dialog_frame"
as a background
examples:
<TextView
android:layout_width="fill_parent"
android:text="I am a simple textview with a shadow"
android:layout_height="wrap_content"
android:textSize="18sp"
android:padding="16dp"
android:textColor="#fff"
android:background="#android:drawable/toast_frame"
/>
and with different bg color:
<LinearLayout
android:layout_height="64dp"
android:layout_width="fill_parent"
android:gravity="center"
android:background="#android:drawable/toast_frame"
android:padding="4dp"
>
<Button
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Button shadow"
android:background="#33b5e5"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="#fff"
android:layout_gravity="center|bottom"
/>
</LinearLayout>
Try this.. layout_shadow.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="#CABBBBBB"/>
<corners android:radius="2dp" />
</shape>
</item>
<item
android:left="0dp"
android:right="0dp"
android:top="0dp"
android:bottom="2dp">
<shape android:shape="rectangle">
<solid android:color="#android:color/white"/>
<corners android:radius="2dp" />
</shape>
</item>
</layer-list>
Apply to your layout like this
android:background="#drawable/layout_shadow"
I know this is old, but most of these answers require a ton of extra code.
If you have a light colored background, you can simply use this:
android:elevation="25dp"
Actually I agree with #odedbreiner but I put the dialog_frame inside the first layer and hide the black background under the white layer.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="#android:drawable/dialog_frame"
android:right="2dp" android:left="2dp" android:bottom="2dp" android:top="5dp" >
<shape android:shape="rectangle">
<corners android:radius="5dp"/>
</shape>
</item>
<item>
<shape
android:shape="rectangle">
<solid android:color="#android:color/white"/>
<corners android:radius="5dp"/>
</shape>
</item>
</layer-list>
save this 9.png. (change name it to 9.png)
2.save it in your drawable.
3.set it to your layout.
4.set padding.
For example :
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/shadow"
android:paddingBottom="6dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingTop="6dp"
>
.
.
.
</LinearLayout>
Create a new XML by example named "shadow.xml" at DRAWABLE with the following code (you can modify it or find another better):
<?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="#color/middle_grey"/>
</shape>
</item>
<item android:left="2dp"
android:right="2dp"
android:bottom="2dp">
<shape android:shape="rectangle">
<solid android:color="#color/white"/>
</shape>
</item>
</layer-list>
After creating the XML in the LinearLayout or another Widget you want to create shade, you use the BACKGROUND property to see the efect. It would be something like :
<LinearLayout
android:orientation="horizontal"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingRight="#dimen/margin_med"
android:background="#drawable/shadow"
android:minHeight="?attr/actionBarSize"
android:gravity="center_vertical">
You can use following class for xml tag:
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.os.Build;
import android.support.annotation.FloatRange;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import com.webappmate.weeassure.R;
/**
* Created by GIGAMOLE on 13.04.2016.
*/
public class ShadowLayout extends FrameLayout {
// Default shadow values
private final static float DEFAULT_SHADOW_RADIUS = 30.0F;
private final static float DEFAULT_SHADOW_DISTANCE = 15.0F;
private final static float DEFAULT_SHADOW_ANGLE = 45.0F;
private final static int DEFAULT_SHADOW_COLOR = Color.DKGRAY;
// Shadow bounds values
private final static int MAX_ALPHA = 255;
private final static float MAX_ANGLE = 360.0F;
private final static float MIN_RADIUS = 0.1F;
private final static float MIN_ANGLE = 0.0F;
// Shadow paint
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG) {
{
setDither(true);
setFilterBitmap(true);
}
};
// Shadow bitmap and canvas
private Bitmap mBitmap;
private final Canvas mCanvas = new Canvas();
// View bounds
private final Rect mBounds = new Rect();
// Check whether need to redraw shadow
private boolean mInvalidateShadow = true;
// Detect if shadow is visible
private boolean mIsShadowed;
// Shadow variables
private int mShadowColor;
private int mShadowAlpha;
private float mShadowRadius;
private float mShadowDistance;
private float mShadowAngle;
private float mShadowDx;
private float mShadowDy;
public ShadowLayout(final Context context) {
this(context, null);
}
public ShadowLayout(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public ShadowLayout(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
setWillNotDraw(false);
setLayerType(LAYER_TYPE_HARDWARE, mPaint);
// Retrieve attributes from xml
final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ShadowLayout);
try {
setIsShadowed(typedArray.getBoolean(R.styleable.ShadowLayout_sl_shadowed, true));
setShadowRadius(
typedArray.getDimension(
R.styleable.ShadowLayout_sl_shadow_radius, DEFAULT_SHADOW_RADIUS
)
);
setShadowDistance(
typedArray.getDimension(
R.styleable.ShadowLayout_sl_shadow_distance, DEFAULT_SHADOW_DISTANCE
)
);
setShadowAngle(
typedArray.getInteger(
R.styleable.ShadowLayout_sl_shadow_angle, (int) DEFAULT_SHADOW_ANGLE
)
);
setShadowColor(
typedArray.getColor(
R.styleable.ShadowLayout_sl_shadow_color, DEFAULT_SHADOW_COLOR
)
);
} finally {
typedArray.recycle();
}
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// Clear shadow bitmap
if (mBitmap != null) {
mBitmap.recycle();
mBitmap = null;
}
}
public boolean isShadowed() {
return mIsShadowed;
}
public void setIsShadowed(final boolean isShadowed) {
mIsShadowed = isShadowed;
postInvalidate();
}
public float getShadowDistance() {
return mShadowDistance;
}
public void setShadowDistance(final float shadowDistance) {
mShadowDistance = shadowDistance;
resetShadow();
}
public float getShadowAngle() {
return mShadowAngle;
}
#SuppressLint("SupportAnnotationUsage")
#FloatRange
public void setShadowAngle(#FloatRange(from = MIN_ANGLE, to = MAX_ANGLE) final float shadowAngle) {
mShadowAngle = Math.max(MIN_ANGLE, Math.min(shadowAngle, MAX_ANGLE));
resetShadow();
}
public float getShadowRadius() {
return mShadowRadius;
}
public void setShadowRadius(final float shadowRadius) {
mShadowRadius = Math.max(MIN_RADIUS, shadowRadius);
if (isInEditMode()) return;
// Set blur filter to paint
mPaint.setMaskFilter(new BlurMaskFilter(mShadowRadius, BlurMaskFilter.Blur.NORMAL));
resetShadow();
}
public int getShadowColor() {
return mShadowColor;
}
public void setShadowColor(final int shadowColor) {
mShadowColor = shadowColor;
mShadowAlpha = Color.alpha(shadowColor);
resetShadow();
}
public float getShadowDx() {
return mShadowDx;
}
public float getShadowDy() {
return mShadowDy;
}
// Reset shadow layer
private void resetShadow() {
// Detect shadow axis offset
mShadowDx = (float) ((mShadowDistance) * Math.cos(mShadowAngle / 180.0F * Math.PI));
mShadowDy = (float) ((mShadowDistance) * Math.sin(mShadowAngle / 180.0F * Math.PI));
// Set padding for shadow bitmap
final int padding = (int) (mShadowDistance + mShadowRadius);
setPadding(padding, padding, padding, padding);
requestLayout();
}
private int adjustShadowAlpha(final boolean adjust) {
return Color.argb(
adjust ? MAX_ALPHA : mShadowAlpha,
Color.red(mShadowColor),
Color.green(mShadowColor),
Color.blue(mShadowColor)
);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Set ShadowLayout bounds
mBounds.set(
0, 0, MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)
);
}
#Override
public void requestLayout() {
// Redraw shadow
mInvalidateShadow = true;
super.requestLayout();
}
#Override
protected void dispatchDraw(final Canvas canvas) {
// If is not shadowed, skip
if (mIsShadowed) {
// If need to redraw shadow
if (mInvalidateShadow) {
// If bounds is zero
if (mBounds.width() != 0 && mBounds.height() != 0) {
// Reset bitmap to bounds
mBitmap = Bitmap.createBitmap(
mBounds.width(), mBounds.height(), Bitmap.Config.ARGB_8888
);
// Canvas reset
mCanvas.setBitmap(mBitmap);
// We just redraw
mInvalidateShadow = false;
// Main feature of this lib. We create the local copy of all content, so now
// we can draw bitmap as a bottom layer of natural canvas.
// We draw shadow like blur effect on bitmap, cause of setShadowLayer() method of
// paint does`t draw shadow, it draw another copy of bitmap
super.dispatchDraw(mCanvas);
// Get the alpha bounds of bitmap
final Bitmap extractedAlpha = mBitmap.extractAlpha();
// Clear past content content to draw shadow
mCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
// Draw extracted alpha bounds of our local canvas
mPaint.setColor(adjustShadowAlpha(false));
mCanvas.drawBitmap(extractedAlpha, mShadowDx, mShadowDy, mPaint);
// Recycle and clear extracted alpha
extractedAlpha.recycle();
} else {
// Create placeholder bitmap when size is zero and wait until new size coming up
mBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);
}
}
// Reset alpha to draw child with full alpha
mPaint.setColor(adjustShadowAlpha(true));
// Draw shadow bitmap
if (mCanvas != null && mBitmap != null && !mBitmap.isRecycled())
canvas.drawBitmap(mBitmap, 0.0F, 0.0F, mPaint);
}
// Draw child`s
super.dispatchDraw(canvas);
}
}
use Tag in xml like this:
<yourpackagename.ShadowLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
app:sl_shadow_color="#9e000000"
app:sl_shadow_radius="4dp">
<child views>
</yourpackagename.ShadowLayout>
UPDATE
put the below code in attrs.xml in resource>>values
<declare-styleable name="ShadowLayout">
<attr name="sl_shadowed" format="boolean"/>
<attr name="sl_shadow_distance" format="dimension"/>
<attr name="sl_shadow_angle" format="integer"/>
<attr name="sl_shadow_radius" format="dimension"/>
<attr name="sl_shadow_color" format="color"/>
</declare-styleable>
One possible solution is using nine patch image like this http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch
OR
I have done this in the following way. This is my main layout in which round_corner.xml and drop_shadow.xml used as background resource. round_corner_two is same like round_corner.xml only the color attribute is different. copy the round_corner.xml,drop_shadow.xml and round_conere_two.xml into drawable folder.
<RelativeLayout
android:id="#+id/facebook_id"
android:layout_width="250dp"
android:layout_height="52dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="28dp"
android:background="#drawable/round_corner" >
<LinearLayout
android:id="#+id/shadow_id"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_margin="1dp"
android:background="#drawable/drop_shadow" >
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginBottom="2dp"
android:background="#drawable/round_corner_two"
android:gravity="center"
android:text="#string/fb_butn_text"
android:textColor="#color/white" >
</TextView>
</LinearLayout>
</RelativeLayout>
round_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="#ffffff" >
</solid>
<!-- view border color and width -->
<stroke
android:width="0dp"
android:color="#3b5998" >
</stroke>
<!-- If you want to add some padding -->
<padding
android:left="1dp"
android:top="1dp"
android:right="1dp"
android:bottom="1dp" >
</padding>
<!-- Here is the corner radius -->
<corners
android:radius="10dp" >
</corners>
</shape>
drop_shadow.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="#android:color/darker_gray" />
<corners android:radius="12dp"/>
</shape>
</item>
<item android:right="1dp" android:left="1dp" android:bottom="5dp">
<shape
android:shape="rectangle">
<solid android:color="#android:color/white"/>
<corners android:radius="5dp"/>
</shape>
</item>
</layer-list>
i know this is way too late. but i had the same requirement. i solved like this
<android.support.v7.widget.CardView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardUseCompatPadding="true"
app:cardElevation="4dp"
app:cardCornerRadius="3dp" >
<!-- put whatever you want -->
</android.support.v7.widget.CardView>
you need to add dependency:
compile 'com.android.support:cardview-v7:25.0.1'
set this xml drwable as your background;---
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- Bottom 2dp Shadow -->
<item>
<shape android:shape="rectangle" >
<solid android:color="#d8d8d8" />-->Your shadow color<--
<corners android:radius="15dp" />
</shape>
</item>
<!-- White Top color -->
<item android:bottom="3px" android:left="3px" android:right="3px" android:top="3px">-->here you can customize the shadow size<---
<shape android:shape="rectangle" >
<solid android:color="#FFFFFF" />
<corners android:radius="15dp" />
</shape>
</item>
</layer-list>
I am trying to use a ProgressBar as a metering like display. I thought it was going to be an easy task and thought that ProgressBar had a property to set to be vertical, but I'm not seeing anything.
Additionally I'd like to be able to show ruler like indicator along the side of the bar to clearly indicate the current level.
Pointers appreciated - Thanks!
I had recently come across the need for a vertical progress bar but was unable to find a solution using the existing Progress Bar widget. The solutions I came across generally required an extension of the current Progress Bar or a completely new class in it self. I wasn't convinced rolling out a new class to achieve a simple orientation change was necessary.
This article presents a simple, elegant, and most importantly, a no-hack solution to achieving a vertical progress bar.
I'm going to skip the explanation and simply provide a cookie cutter solution. If you require further details feel free to contact me or leave a comment below.
Create an xml in your drawable folder (not drawable-hdpi or drawable-mdpi -- place it in drawable). For this example I call my xml vertical_progress_bar.xml
Here's what to place in the xml file:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ff9d9e9d"
android:centerColor="#ff5a5d5a"
android:centerY="0.75"
android:endColor="#ff747674"
android:angle="180"
/>
</shape>
</item>
<item android:id="#android:id/secondaryProgress">
<clip android:clipOrientation="vertical" android:gravity="bottom">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#80ffd300"
android:centerColor="#80ffb600"
android:centerY="0.75"
android:endColor="#a0ffcb00"
android:angle="180"
/>
</shape>
</clip>
</item>
<item android:id="#android:id/progress">
<clip android:clipOrientation="vertical" android:gravity="bottom">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ffffd300"
android:centerColor="#ffffb600"
android:centerY="0.75"
android:endColor="#ffffcb00"
android:angle="180"
/>
</shape>
</clip>
</item>
</layer-list>
Create an xml file called styles.xml and place it in res/values. If your project already contains styles.xml in res/values then skip this step.
Modify your styles.xml file and append the following code to the end of the file:
<style name="Widget">
</style>
<style name="Widget.ProgressBar">
<item name="android:indeterminateOnly">true</item>
<item name="android:indeterminateBehavior">repeat</item>
<item name="android:indeterminateDuration">3500</item>
<item name="android:minWidth">48dip</item>
<item name="android:maxWidth">48dip</item>
<item name="android:minHeight">48dip</item>
<item name="android:maxHeight">48dip</item>
</style>
<style name="Widget.ProgressBar.Vertical">
<item name="android:indeterminateOnly">false</item>
<item name="android:progressDrawable">#drawable/progress_bar_vertical</item>
<item name="android:indeterminateDrawable">#android:drawable/progress_indeterminate_horizontal</item>
<item name="android:minWidth">1dip</item>
<item name="android:maxWidth">12dip</item>
</style>
Add your new vertical progress bar to your layout. Here's an example:
<ProgressBar
android:id="#+id/vertical_progressbar"
android:layout_width="12dip"
android:layout_height="300dip"
style="#style/Widget.ProgressBar.Vertical"
/>
That should be all you need to do to make use of a vertical progress bar in your project. Optionally, you might have custom drawable nine-patch images that you are using for the progress bar. You should make the appropriate changes in the progress_bar_vertical.xml file.
I hope this helps you out in your project!
You have to create your own custom progressbar.
In your xml add this layout:
<com.example.component.VerticalProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:id="#+id/verticalRatingBar1"
android:layout_width="wrap_content"
android:progress="50"
android:layout_height="fill_parent" />
VerticalProgressBar.java
public class VerticalProgressBar extends ProgressBar{
private int x, y, z, w;
#Override
protected void drawableStateChanged() {
// TODO Auto-generated method stub
super.drawableStateChanged();
}
public VerticalProgressBar(Context context) {
super(context);
}
public VerticalProgressBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
this.x = w;
this.y = h;
this.z = oldw;
this.w = oldh;
}
#Override
protected synchronized void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas c) {
c.rotate(-90);
c.translate(-getHeight(), 0);
super.onDraw(c);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setSelected(true);
setPressed(true);
break;
case MotionEvent.ACTION_MOVE:
setProgress(getMax()
- (int) (getMax() * event.getY() / getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
break;
case MotionEvent.ACTION_UP:
setSelected(false);
setPressed(false);
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
#Override
public synchronized void setProgress(int progress) {
if (progress >= 0)
super.setProgress(progress);
else
super.setProgress(0);
onSizeChanged(x, y, z, w);
}
}
Or :
Jagsaund solution is also being perfect.
I know that it´s an old post but I found a very simple solution to this problem that maybe can help somebody.
First at all create a progress_drawable_vertical.xml like this:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<color android:color="#777" />
</item>
<item android:id="#android:id/progress">
<clip
android:clipOrientation="vertical"
android:gravity="bottom">
<shape>
<gradient
android:startColor="#00FF00"
android:centerColor="#FFFF00"
android:endColor="#FF0000"
android:angle="90" />
</shape>
</clip>
</item>
</layer-list>
Then just use this in your progressBar:
<ProgressBar
android:id="#+id/progress_bar"
style="#android:style/Widget.ProgressBar.Horizontal"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:max="100"
android:progress="33"
android:progressDrawable="#drawable/progress_drawable_vertical" />
I also have created an progress_drawable_horizontal.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<color android:color="#777" />
</item>
<item android:id="#android:id/progress">
<clip
android:clipOrientation="horizontal"
android:gravity="left">
<shape>
<gradient
android:startColor="#00FF00"
android:centerColor="#FFFF00"
android:endColor="#FF0000" />
</shape>
</clip>
</item>
</layer-list>
with the objetive of mantain the same style defined in progress_drawable_vertical.xml
The key here is the correct use of android:clipOrientation and android:gravity.
I found this solution here and the core of the solution is similar to jagsaund but a little bit more simple.
I found the probably best(easiest & most versatile) solution:)
This is an old post, but it was so hard for me to find this so easy solution so I thought I should post it..
Just use a scale-drawable (or a 9-patch if you want), no need for ANY OTHER code.
Example:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background" android:drawable="#color/transparent"/>
<item android:id="#android:id/progress">
<scale android:scaleGravity="bottom" android:scaleWidth="0%" android:scaleHeight="100%">
<shape >
<solid android:color="#color/blue"/>
<corners android:topRightRadius="1dp" android:topLeftRadius="1dp"/>
</shape>
</scale>
</item>
</layer-list>
And of course the normal code:
<ProgressBar
android:id="#+id/progress_bar"
style="#android:style/Widget.ProgressBar.Horizontal"
android:layout_width="24dp"
android:layout_height="match_parent"
android:max="1000"
android:progress="200"
android:progressDrawable="#drawable/progress_scale_drawable" />
Notice the scale-drawable's xml lines (the magic lines):
android:scaleGravity="bottom" //scale from 0 in y axis (default scales from center Y)
android:scaleWidth="0%" //don't scale width (according to 'progress')
android:scaleHeight="100%" //do scale the height of the drawable
This perfectly works
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<shape>
<gradient
android:startColor="#DDDDDD"
android:centerColor="#DDDDDD"
android:centerY="0.75"
android:endColor="#DDDDDD"
android:angle="270"
/>
</shape>
</item>
<item
android:id="#android:id/progress">
<clip
android:clipOrientation="vertical"
android:gravity="top">
<shape>
<gradient
android:angle="0"
android:startColor="#302367"
android:centerColor="#7A5667"
android:endColor="#C86D67"/>
</shape>
</clip>
</item>
</layer-list>
<ProgressBar
android:id="#+id/progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="5dp"
android:layout_height="match_parent"`enter code here`
android:progressDrawable="#drawable/progress_dialog"/>
Creating the progress bar (I converted my code from c# to java so might not be 100% correct)
ProgressBar progBar = new ProgressBar(Context, null, Android.resource.attribute.progressDrawable);
progBar.progressDrawable = ContextCompat.getDrawable(Context, resource.drawable.vertical_progress_bar);
progBar.indeterminate = false;
vertical_progress_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#android:id/background">
<shape>
<solid android:color="#color/grey" />
<corners android:radius="20dip" />
</shape>
</item>
<item android:id="#android:id/progress">
<scale
android:drawable="#drawable/vertical_progress_bar_blue_progress"
android:scaleHeight="100%"
android:scaleGravity="bottom"/>
</item>
</layer-list>
vertical_progress_bar_blue_progress.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<corners
android:radius="20dip" />
<solid android:color="#color/ProgressBarFourth" />
</shape>
What's going to make your bar vertical is the scaleHeight and scaleGravity attributes in vertical_progress_bar.xml.
It ends up looking something like this:
Simple and Easy way:
Just add a view to a LinearLayout and scale it.
<LinearLayout
android:layout_width="4dp"
android:layout_height="300dp"
android:background="#color/md_green_50"
android:orientation="vertical">
<View
android:id="#+id/progressView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="top"
android:layout_weight="1"
android:background="#color/md_green_500"
android:scaleY="0.0" />
</LinearLayout>
Set View's pivotY to zero:
progressView.pivotY = 0F
Now you can fill the progress using scaleY between 0F and 1F:
progressView.scaleY = 0.3F
Bonus:
Animate progress using animate():
progressView.animate().scaleY(0.3F).start()
Here is a simple solution, just rotate your progress bar
android:rotation="270"
Add this to the xml code
android:rotation="90"
android:transformPivotX="0dp"
So this is how your Progress Bar xml should look
<ProgressBar
android:id="#+id/progressBar6"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:rotation="90"
android:transformPivotX="0dp"
tools:layout_editor_absoluteX="101dp"
tools:layout_editor_absoluteY="187dp" />
To utilize the ProgressBar and make it vertical, you would have to create your own custom View extending the ProgressBar view and override the onDraw() method. This will allow you to draw it in a reverse orientation. Take a look at the source code of the ProgressBar.onDraw() (located at the bottom of the link) for help on how to do this. Best case scenario, you'll just have to swap a few x and y variables.
I have the exact problem. Making a custom class (extending ProgressBar) will create code that are hard to maintain. Using a custom style will cause compatibility issue with different theme from new OS (e.g. lollipop)
Eventually, I just apply a rotation animation to an horizontal progress bar. Inspired by Pete.
Create the tag in your layout xml like normal horizontal progress bar.
Make sure that the size and position of the ProgressBar is what you want after rotation. (Perhaps setting negative margin will help). In my code I rotate the view from 0,0.
Use the method below to rotate and set new progress.
Code:
private void setProgress(final ProgressBar progressBar, int progress) {
progressBar.setWillNotDraw(true);
progressBar.setProgress(progress);
progressBar.setWillNotDraw(false);
progressBar.invalidate();
}
private void rotateView(final View v, float degree) {
Animation an = new RotateAnimation(0.0f, degree);
an.setDuration(0);
an.setRepeatCount(0);
an.setFillAfter(true); // keep rotation after animation
v.setAnimation(an);
}
Simple progrebar image view
example
viewHolder.proBarTrueImage.setMaximalValue(147);
viewHolder.proBarTrueImage.setLevel(45);
viewHolder.proBarTrueImage.setColorResource(R.color.corner_blue);
simple class
public class ProgressImageView extends ImageView {
private Context mContext;
private Paint paint;
private RectF rectf;
private int maximalValue = 1;
private int level = 0;
private int width;
private int height;
public ProgressImageView(Context context) {
super(context);
init(context, null, 0);
}
public ProgressImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public ProgressImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr){
mContext = context;
paint = new Paint();
rectf = new RectF();
paint.setColor(Color.GRAY);
paint.setStyle(Paint.Style.FILL);
};
#Override
protected void onDraw(Canvas canvas) {
float dif = (float) height / (float) maximalValue;
int newHeight = height - (int) (dif * level);
rectf.set(0,newHeight, width, height);
canvas.drawRect(rectf, paint);
super.onDraw(canvas);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
this.width = w;
this.height = h;
}
public void setMaximalValue(int maximalValue) {
this.maximalValue = maximalValue;
invalidate();
}
public void setLevel(int level) {
this.level = level;
invalidate();
}
public void setColorResource(int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
color = mContext.getResources().getColor(color,mContext.getTheme());
}else {
color = mContext.getResources().getColor(R.color.corner_blue);
}
setColor(color);
}
public void setColor(int color){
if (paint != null){
paint.setColor(color);
invalidate();
}
}
}
<ProgressBar
android:id="#+id/battery_pb"
android:rotation="270"
android:progress="100"
...
/>
Use android:rotation="270" to 100% be like bottom to top or android:rotation="90" to 100% be like top to bottom
enter link description here
**Check this link out, I was trying to use a similar thing and also you can use stepper for your requirement, few projects are available on Github about HOW TO USE STEPPER IN ANDROID STUDIO **
For making a vertical ProgressBar, The way that I solved it was first rotating it by 90 degrees, then scaling it with a value entered by hand.
scaleX = layout_height/layout_width
Here's an example of my attributes on the ProgressBar
android:layout_width="20dp"
android:layout_height="233dp"
android:rotation="-90"
android:scaleX="11.65"
This can be a little manual, but because they don't have a vertical progress bar by default, this was a pretty good workaround for me. The scaleX could be calculated automatically, but it would have to be after everything is drawn on the screen.
Vertical progress bars are not supported by default.
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;
};
}
I am trying to create a custom progress bar in android. I have used the following xml file for it (progress_bar_horizontal.xml):
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<shape>
<corners android:radius="8dip" />
<stroke android:width="2dip" android:color="#FFFF"/>
<solid android:color="#FFFF"/>
</shape>
</item>
<item android:id="#android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="8dip" />
<stroke android:width="2dip" android:color="#FFFF"/>
<solid android:color="#FF00"/>
</shape>
</clip>
</item>
<item android:id="#android:id/progress">
<clip>
<shape>
<corners android:radius="8dip" />
<stroke android:width="2dip" android:color="#FFFF"/>
<solid android:color="#FF00"/>
</shape>
</clip>
</item>
</layer-list>
Everything works great apart from the fact I would like to have the progress in my progress bar rounded on both sides. The aforementioned code makes a progress bar to be rounded on the left hand side and simply cut (not rounded) on the right hand side. It is because of the clip tag probably. Could you please help me on that? What should i change to have the progress in my progress bar rounded on both sides?
The full layout goes below:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#drawable/gradient_progress"
android:padding="10dip"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:id="#+id/progress_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:text="Uploading"
/>
<TextView
android:id="#+id/progress_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:text="55%"
android:paddingLeft="10dip"
/>
</LinearLayout>
<ProgressBar
android:id="#+id/progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_gravity="center"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:progressDrawable="#drawable/progress_bar_horizontal"
android:maxHeight="12dip"
android:minHeight="12dip"
android:max="100"
/>
</LinearLayout>
</LinearLayout>
Here is the result of my effort: link text
I would like the red bar to have rounded edges on the right hand side as well.
Thank you so much for your comments.
Here's an updated answer for the times:
The Android source code uses Patch 9 files to achieve the effect:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/frameworks/base/core/res/res/drawable/progress_horizontal_holo_dark.xml/
So start in your layout xml:
<ProgressBar
android:id="#+id/custom_progress_bar"
style="#android:style/Widget.ProgressBar.Horizontal"
android:indeterminateOnly="false"
android:progressDrawable="#drawable/custom_progress_bar_horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="13"
android:progress="33"
android:secondaryProgress="66" />
You can move a lot of this to a style xml but that's beside the point. What we really care about is android:progressDrawable="#drawable/custom_progress_bar_horizontal" - which is going to allow us to specify our own custom progress bars:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background"
android:drawable="#android:drawable/custom_progress_bg" />
<item android:id="#android:id/secondaryProgress">
<scale android:scaleWidth="100%"
android:drawable="#android:drawable/custom_progress_secondary" />
</item>
<item android:id="#android:id/progress">
<scale android:scaleWidth="100%"
android:drawable="#android:drawable/custom_progress_primary" />
</item>
</layer-list>
Or you don't have to use a Patch 9 for your background- for example here's a simple white background with a 1dp border:
<item android:id="#android:id/background">
<shape>
<corners android:radius="6.5dp" />
<solid android:color="#android:color/white" />
<stroke
android:width="1dp"
android:color="#android:color/darker_gray" />
</shape>
</item>
Android Asset Studio has an awesome tool to help you generate Patch 9 files:
http://android-ui-utils.googlecode.com/hg/asset-studio/dist/nine-patches.html
Example primary xdpi png with padding before the tool:
Example secondary xdpi png with padding before the tool:
And the final output:
Just change the label <clip> to <scale> like this:
<scale android:scaleWidth="100%">
As far as I know, this is not possible. Because internally ClipDrawable (i.e. clip tag) cuts the given shape/drawable using canvas.clipRect(). Btw, you can copy the ClipDrawable source from here and clip a particular path based on the progress level.
You can use the LinearProgressIndicator provided by the Material Components Library and the app:trackCornerRadius attribute.
Something like:
<com.google.android.material.progressindicator.LinearProgressIndicator
android:indeterminate="true"
app:indicatorSize="xxdp"
app:trackCornerRadius="xdp"/>
Note: it requires at least the version 1.3.0-alpha04.
In order to solve the problem where the end graphics overlap themselves when the progress is very low, I've written an extension to the ProgressBar class that adds a fixed start offset to the progress bar, while otherwise functioning as normal.
Just call 'setMaxWithPercentOffset()' or 'setMaxWithOffset()' rather than 'setMax()' passing in the value you want to add as a start offset to the progress bar.
If anyone has solved this problem without requiring the start offset let me know!
/**
* This progress bar can be used when the progress bar end graphics are styled in some way.
* In this case, the progress bar must always have a small percentage of progress, otherwise
* the styled ends of the progress overlap each other.
*
*/
public class EndStyledProgressBar extends ProgressBar {
private static final int DEFAULT_START_OFFSET_PERCENT = 5;
private int mStartOffset;
private int mRealMax;
public EndStyledProgressBar(Context context) {
super(context);
commonConstructor();
}
public EndStyledProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
commonConstructor();
}
public EndStyledProgressBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
commonConstructor();
}
private void commonConstructor() {
mRealMax = super.getMax();
mStartOffset = 0;
setMaxWithPercentOffset(DEFAULT_START_OFFSET_PERCENT, mRealMax);
super.setProgress(super.getProgress() + mStartOffset);
super.setSecondaryProgress(super.getSecondaryProgress() + mStartOffset);
}
public void setProgress(int progress) {
super.setProgress(progress + mStartOffset);
}
public void setSecondaryProgress(int secondaryProgress) {
super.setSecondaryProgress(secondaryProgress + mStartOffset);
}
public int getProgress() {
int realProgress = super.getProgress();
return isIndeterminate() ? 0 : (realProgress - mStartOffset);
}
public int getSecondaryProgress() {
int realSecondaryProgress = super.getSecondaryProgress();
return isIndeterminate() ? 0 : (realSecondaryProgress - mStartOffset);
}
public int getMax() {
return mRealMax;
}
/**
* Don't call this, instead call setMaxWithPercentOffset() or setStartOffsetInPercent()
*
* #param max
*/
public void setMax(int max) {
super.setMax(max);
}
/**
* Sets a new max with a start offset (in percent) included.
*
* #param startOffsetInPercent start offset for the progress bar to avoid graphic errors.
*/
public void setMaxWithPercentOffset(int startOffsetInPercent, int max) {
mRealMax = max;
int startOffset = (mRealMax * startOffsetInPercent) / 100;
setMaxWithOffset(startOffset, max);
}
/**
* Sets a new max with a start offset included.
*
* #param startOffset start offset for the progress bar to avoid graphic errors.
*/
public void setMaxWithOffset(int startOffset, int max) {
mRealMax = max;
super.setMax(startOffset + max);
setStartOffset(startOffset);
super.setMax(startOffset + max);
}
/**
* Sets a new start offset different from the default of 5%
*
* #param startOffset start offset for the progress bar to avoid graphic errors.
*/
private void setStartOffset(int startOffset) {
int newStartOffset = startOffset;
// Ensure the start offset is not outside the range of the progress bar
if (newStartOffset < 0) newStartOffset = 0;
if (newStartOffset >= super.getMax()) newStartOffset = super.getMax();
// Apply the start offset difference
if (mStartOffset != newStartOffset) {
int diff = newStartOffset - mStartOffset;
super.setMax(super.getMax() + diff);
super.setProgress(super.getProgress() + diff);
super.setSecondaryProgress(super.getSecondaryProgress() + diff);
mStartOffset = newStartOffset;
}
}
}
Final rounded both sides progress bar without 9-patch is:
android:progressDrawable="#drawable/progress_horizontal_green"
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/progress">
<scale android:scaleWidth="100%">
<shape>
<corners android:radius="5dip"/>
<solid android:color="#33FF33"/>
</shape>
</scale>
</item>