According to the official Design docs for Action Chips, we are supposed to be able to add a progress state to chips. Sadly, the Development docs don't mention this at all. Has anyone managed to figure out how to achieve the effect shown here?
It is possible to implement this behavior using the chipIcon attribute and androidx.swiperefreshlayout.widget.CircularProgressDrawable.
xml
app:chipIconWithProgress="#{viewModel.taskIsStarting ? null : #drawable/ic_play_arrow}"
and BindingAdapter
#BindingAdapter("chipIconWithProgress")
fun Chip.setChipIconWithProgress(item: Drawable?) {
chipIcon = item
?: CircularProgressDrawable(context!!).apply {
setStyle(CircularProgressDrawable.DEFAULT)
start()
}
}
You can use the Material Components Library and the Chip component.
In your layout use:
<com.google.android.material.chip.Chip
android:id="#+id/chip"
style="#style/Widget.MaterialComponents.Chip.Action"
app:iconStartPadding="2dp"
../>
Then use as chipIcon a ProgressIndicator provided by the library:
ProgressIndicatorSpec progressIndicatorSpec = new ProgressIndicatorSpec();
progressIndicatorSpec.loadFromAttributes(
this,
null,
R.style.Widget_MaterialComponents_ProgressIndicator_Circular_Indeterminate);
progressIndicatorSpec.circularInset = 1; // Inset.
progressIndicatorSpec.circularRadius =
(int) dpToPx(this, 8); // Circular radius is 8 dp.
IndeterminateDrawable progressIndicatorDrawable =
new IndeterminateDrawable(
this,
progressIndicatorSpec,
new CircularDrawingDelegate(),
new CircularIndeterminateAnimatorDelegate());
Chip chip = findViewById(R.id.chip);
chip.setChipIcon(progressIndicatorDrawable);
with this util method:
public static float dpToPx(#NonNull Context context, #Dimension(unit = Dimension.DP) int dp) {
Resources r = context.getResources();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics());
}
You can customize the colors and all other attributes:
progressIndicatorSpec.indicatorColors = getResources().getIntArray(R.array.progress_colors);
progressIndicatorSpec.growMode = GROW_MODE_OUTGOING;
Note: this requires at least the version 1.3.0-alpha02.
Related
I was looking at material design website when I got to this page about circular progressbar and more precisely this video
I'd like to create a button like the one in the video but I don't see any documentation about this, and I don't know where to start
I've managed to simply use:
val progress = CircularProgressDrawable(context).apply {
setStyle(CircularProgressDrawable.DEFAULT)
// do use setBounds if you need to
start()
}
myMaterialButton.setCompoundDrawablesWithIntrinsicBounds(null, progress, null, null)
// Do your stuff
//replace the image by the one you want
myMaterialButton.setCompoundDrawablesWithIntrinsicBounds(null, myDrawable, null, null)
Reference: setCompoundDrawablesWithIntrinsicBounds
You could also use IndeterminateDrawable from material progress indicator. I see the CircularProgressDrawable animation breaks in API level 25
private val progressDrawableBackward by lazy {
val progressIndicatorSpec = CircularProgressIndicatorSpec(
context,
null,
0,
R.style.Widget_MaterialComponents_CircularProgressIndicator_ExtraSmall
)
progressIndicatorSpec.indicatorColors =
intArrayOf(progressColor)
IndeterminateDrawable.createCircularDrawable(context, progressIndicatorSpec).apply {
val size = (DRAWABLE_CENTER_RADIUS + DRAWABLE_STROKE_WIDTH ).toInt() * 2
setBounds(0, 0, size, size)
setVisible(true, true)
}
}
I'm trying to set my color for the outline of my button, but I don't get it to work
I'm using material button and when I use
button.setStrokeColorResource(Color.parseColor(#e4dcd4))
is not working and tells me this
Expected a color resource id (R.color.) but received an RGB integer
I tried almost everything I could found about in stack, but I can't get it to set this strokeColor programmatically
Edit
Almost all setColors use #ColorInt , but this strokeColor uses #ColorRes, which is not working for me, also there is setStrokeColor
public void setStrokeColor(#Nullable ColorStateList strokeColor) {
if (isUsingOriginalBackground()) {
materialButtonHelper.setStrokeColor(strokeColor);
}
}
But I can't get it to work either.
It worked like this
val colorInt = Color.parseColor("#e4dcd4")
val csl = ColorStateList.valueOf(colorInt)
my_button.strokeColor = csl
You might try this
button.setStrokeColor(ContextCompat.getColor(this, R.color.your_color_xml));
Other way you can do is
ShapeDrawable gradientDrawable = (ShapeDrawable)button.getBackground();
gradientDrawable.setStroke(2, your_color);
Also as #Gabriele said you can get an int as a color as :
//From RGB
int colorRGB = Color.rgb(255,0,0);
//From HEX String
int colorHEX = Color.parseColor("#FF11AA");
You have to set the width of the stroke because the default value is 0.
<Button
app:strokeWidth="2dp"
../>
button.strokeColor = ColorStateList.valueOf(Color.parseColor("#e4dcd4"))
or
// if color define in color.xml
button.strokeColor = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.yourColorCOde))
// if you have different state and you want to set programmatically then do as :-
var states = arrayOf(
intArrayOf(R.attr.state_enabled),
intArrayOf(-R.attr.state_enabled),
intArrayOf(-R.attr.state_checked),
intArrayOf(R.attr.state_pressed)
)
// Color list define respect of state
var colors = intArrayOf(
Color.BLACK,
Color.RED,
Color.GREEN,
Color.BLUE
)
// Set stroke color
button.strokeColor = ColorStateList(states, colors)
I would like to make a graph like this :
The problem is I don't know how to set a gradient color like this using MPAndroidChart. Maybe I should use an other library ?
Maybe it's better to use progressbar with transparent color (and gradient background) ?
This is my code :
val entries = ArrayList<BarEntry>()
entries.add(BarEntry(1.toFloat(), 43.toFloat()))
entries.add(BarEntry(2.toFloat(), 3.toFloat()))
entries.add(BarEntry(3.toFloat(), 13.toFloat()))
entries.add(BarEntry(4.toFloat(), 41.toFloat()))
entries.add(BarEntry(5.toFloat(), 22.toFloat()))
entries.add(BarEntry(6.toFloat(), 11.toFloat()))
entries.add(BarEntry(7.toFloat(), 13.toFloat()))
entries.add(BarEntry(8.toFloat(), 99.toFloat()))
entries.add(BarEntry(9.toFloat(), 67.toFloat()))
entries.add(BarEntry(10.toFloat(), 3.toFloat()))
entries.add(BarEntry(11.toFloat(), 56.toFloat()))
entries.add(BarEntry(12.toFloat(), 88.toFloat()))
val dataSet = BarDataSet(entries, "Label")
chart.data = BarData(dataSet)
This worked for me:
dataset.setGradientColor(Color.parseColor("#00FF5722"),Color.parseColor("#FFFF5722"));
You can use setGradientFill() method which will accept n number of color.
int[] colors = { getResources().getColor(R.color.menu_text),
getResources().getColor(android.R.color.white) };
float[] index = { 0, 1 };
dataset.setGradientFill(colors, index);
for more you can refer this. Hope it will help you!!
I have this issue on my EditText and Button views, where I have a nice padding for them to space away from the text, but when I change the background with setBackgroundDrawable or setBackgroundResource that padding is lost forever.
What I found was adding a 9 patch as a background resource reset the padding - although interestingly if I added a color, or non-9 patch image, it didn't. The solution was to save the padding values before the background gets added, then set them again afterwards.
private EditText value = (EditText) findViewById(R.id.value);
int pL = value.getPaddingLeft();
int pT = value.getPaddingTop();
int pR = value.getPaddingRight();
int pB = value.getPaddingBottom();
value.setBackgroundResource(R.drawable.bkg);
value.setPadding(pL, pT, pR, pB);
I was able to wrap the element inside another layout, in this case, a FrameLayout. That enabled me to change the background on the FrameLayout without destroying the padding, which is on the contained RelativeLayout.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/commentCell"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/comment_cell_bg_single" >
<RelativeLayout android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="20dp" >
<ImageView android:id="#+id/sourcePic"
android:layout_height="75dp"
android:layout_width="75dp"
android:padding="5dp"
android:background="#drawable/photoframe"
/>
...
The other option is to set it programmatically after setting the background Drawable as suggested above. Just make sure to calculate the pixels to correct for the resolution of the device.
I had this problem in a TextView, so I subclassed TextView and made an Override method of the TextView.setBackgroundResource(int resid) method. Like this:
#Override
public void setBackgroundResource(int resid) {
int pl = getPaddingLeft();
int pt = getPaddingTop();
int pr = getPaddingRight();
int pb = getPaddingBottom();
super.setBackgroundResource(resid);
this.setPadding(pl, pt, pr, pb);
}
This way, it gets the padding of the item before it sets the resource, but doesn't actually mess with the original functionality of the method, other than keeping the padding.
Haven't tested this super thoroughly, but this method might be of use:
/**
* Sets the background for a view while preserving its current padding. If the background drawable
* has its own padding, that padding will be added to the current padding.
*
* #param view View to receive the new background.
* #param backgroundDrawable Drawable to set as new background.
*/
public static void setBackgroundAndKeepPadding(View view, Drawable backgroundDrawable) {
Rect drawablePadding = new Rect();
backgroundDrawable.getPadding(drawablePadding);
int top = view.getPaddingTop() + drawablePadding.top;
int left = view.getPaddingLeft() + drawablePadding.left;
int right = view.getPaddingRight() + drawablePadding.right;
int bottom = view.getPaddingBottom() + drawablePadding.bottom;
view.setBackgroundDrawable(backgroundDrawable);
view.setPadding(left, top, right, bottom);
}
Use this instead of view.setBackgroundDrawable(Drawable).
Just to explain what's happening :
It's actually a feature. Layout drawables you might use as backgrounds can define a padding this way :
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingRight="8dp"
>
...
</layer-list>
This padding will be set along with the new drawable background. When there's no padding, the default value is 0.
More info from an email written by Romain Guy:
https://www.mail-archive.com/android-developers#googlegroups.com/msg09595.html
Backward compatable version of cottonBallPaws's answer
/**
* Sets the background for a view while preserving its current padding. If the background drawable
* has its own padding, that padding will be added to the current padding.
*
* #param view View to receive the new background.
* #param backgroundDrawable Drawable to set as new background.
*/
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#SuppressWarnings("deprecation")
public static void setBackgroundAndKeepPadding(View view, Drawable backgroundDrawable) {
Rect drawablePadding = new Rect();
backgroundDrawable.getPadding(drawablePadding);
int top = view.getPaddingTop() + drawablePadding.top;
int left = view.getPaddingLeft() + drawablePadding.left;
int right = view.getPaddingRight() + drawablePadding.right;
int bottom = view.getPaddingBottom() + drawablePadding.bottom;
int sdk = android.os.Build.VERSION.SDK_INT;
if(sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
view.setBackgroundDrawable(backgroundDrawable);
} else {
view.setBackground(backgroundDrawable);
}
view.setPadding(left, top, right, bottom);
}
You can give some padding by using 9-patch images and defining the content area in the drawable.
Check this
You can also set the padding in your layout from xml or programatically
xml padding tags
android:padding
android:paddingLeft
android:paddingRight
android:paddingTop
android:paddingBottom
You can try setting the padding manually from the code after you call the setBackgroundDrawable by calling setPadding on your EditText or Button Views
For common searcher,
just add setPadding after setBackgroudDrawable. When you change your drawable, you have to call setPadding again.
Like:
view.setBackgroundDrawable(backgroundDrawable);
view.setPadding(x, x, x, x);
The cleanest way is define your paddings inside a xml-drawable which points to the drawable-image-file
Greatings
My solution was to extend the view (in my case an EditText) and override setBackgroundDrawable() and setBackgroundResource() methods:
// Stores padding to avoid padding removed on background change issue
public void storePadding(){
mPaddingLeft = getPaddingLeft();
mPaddingBottom = getPaddingTop();
mPaddingRight = getPaddingRight();
mPaddingTop = getPaddingBottom();
}
// Restores padding to avoid padding removed on background change issue
private void restorePadding() {
this.setPadding(mPaddingLeft, mPaddingTop, mPaddingRight, mPaddingBottom);
}
#Override
public void setBackgroundResource(#DrawableRes int resId) {
storePadding();
super.setBackgroundResource(resId);
restorePadding();
}
#Override
public void setBackgroundDrawable(Drawable background) {
storePadding();
super.setBackgroundDrawable(background);
restorePadding();
}
Combining the solutions of all, I wrote one in Kotlin:
fun View.setViewBackgroundWithoutResettingPadding(#DrawableRes backgroundResId: Int) {
val paddingBottom = this.paddingBottom
val paddingStart = ViewCompat.getPaddingStart(this)
val paddingEnd = ViewCompat.getPaddingEnd(this)
val paddingTop = this.paddingTop
setBackgroundResource(backgroundResId)
ViewCompat.setPaddingRelative(this, paddingStart, paddingTop, paddingEnd, paddingBottom)
}
fun View.setViewBackgroundWithoutResettingPadding(background: Drawable?) {
val paddingBottom = this.paddingBottom
val paddingStart = ViewCompat.getPaddingStart(this)
val paddingEnd = ViewCompat.getPaddingEnd(this)
val paddingTop = this.paddingTop
ViewCompat.setBackground(this, background)
ViewCompat.setPaddingRelative(this, paddingStart, paddingTop, paddingEnd, paddingBottom)
}
just change lib to v7:22.1.0 in android studio like this
compile 'com.android.support:appcompat-v7:22.1.0'
Most of answers are correct but should handle the background setting correctly.
First get the padding of your view
//Here my view has the same padding in all directions so I need to get just 1 padding
int padding = myView.getPaddingTop();
Then set the background
//If your are supporting lower OS versions make sure to verify the version
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
//getDrawable was deprecated so use ContextCompat
myView.setBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.bg_accent_underlined_white));
} else {
myView.setBackground(ContextCompat.getDrawable(context, R.drawable.bg_accent_underlined_white));
}
Then set the padding the view had before the background change
myView.setPadding(padding, padding, padding, padding);
I found another solution.
I was facing the similar problem with Buttons.
Eventually, i added:
android:scaleX= "0.85"
android:scaleY= "0.85"
it worked for me. The default padding is almost the same.
In my case I had a drawable and was so stupid I didn't see the paddings were all set to 0 in the xml.
maybe it will be relevant for someone
small hack using drawable in selector doesn't remove padding
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/anything" />
</selector>
Here an improved version of cottonBallPaws' setBackgroundAndKeepPadding. This maintains the padding even if you call the method multiple times:
/**
* Sets the background for a view while preserving its current padding. If the background drawable
* has its own padding, that padding will be added to the current padding.
*/
public static void setBackgroundAndKeepPadding(View view, Drawable backgroundDrawable) {
Rect drawablePadding = new Rect();
backgroundDrawable.getPadding(drawablePadding);
// Add background padding to view padding and subtract any previous background padding
Rect prevBackgroundPadding = (Rect) view.getTag(R.id.prev_background_padding);
int left = view.getPaddingLeft() + drawablePadding.left -
(prevBackgroundPadding == null ? 0 : prevBackgroundPadding.left);
int top = view.getPaddingTop() + drawablePadding.top -
(prevBackgroundPadding == null ? 0 : prevBackgroundPadding.top);
int right = view.getPaddingRight() + drawablePadding.right -
(prevBackgroundPadding == null ? 0 : prevBackgroundPadding.right);
int bottom = view.getPaddingBottom() + drawablePadding.bottom -
(prevBackgroundPadding == null ? 0 : prevBackgroundPadding.bottom);
view.setTag(R.id.prev_background_padding, drawablePadding);
view.setBackgroundDrawable(backgroundDrawable);
view.setPadding(left, top, right, bottom);
}
You need to define a resource id via values/ids.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="prev_background_padding" type="id"/>
</resources>
I use this pretty easy workaround I define a accentColor in my style.xml like below
<item name="colorAccent">#0288D1</item>
and then I use the either of following styles in my Button tags
style="#style/Base.Widget.AppCompat.Button.Colored"
style="#style/Base.Widget.AppCompat.Button.Small"
for Example :
<Button
android:id="#+id/btnLink"
style="#style/Base.Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/tvDescription"
android:textColor="#color/textColorPrimary"
android:text="Visit Website" />
<Button
android:id="#+id/btnSave"
style="#style/Base.Widget.AppCompat.Button.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/tvDescription"
android:layout_toRightOf="#id/btnLink"
android:textColor="#color/textColorPrimaryInverse"
android:text="Save" />
I need to know the exact size of ActionBar in pixels so to apply correct background image.
To retrieve the height of the ActionBar in XML, just use
?android:attr/actionBarSize
or if you're an ActionBarSherlock or AppCompat user, use this
?attr/actionBarSize
If you need this value at runtime, use this
final TypedArray styledAttributes = getContext().getTheme().obtainStyledAttributes(
new int[] { android.R.attr.actionBarSize });
mActionBarSize = (int) styledAttributes.getDimension(0, 0);
styledAttributes.recycle();
If you need to understand where this is defined:
The attribute name itself is defined in the platform's /res/values/attrs.xml
The platform's themes.xml picks this attribute and assigns a value to it.
The value assigned in step 2 depends on different device sizes, which are defined in various dimens.xml files in the platform, ie. core/res/res/values-sw600dp/dimens.xml
From the de-compiled sources of Android 3.2's framework-res.apk, res/values/styles.xml contains:
<style name="Theme.Holo">
<!-- ... -->
<item name="actionBarSize">56.0dip</item>
<!-- ... -->
</style>
3.0 and 3.1 seem to be the same (at least from AOSP)...
To get the actual height of the Actionbar, you have to resolve the attribute actionBarSize at runtime.
TypedValue tv = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
int actionBarHeight = getResources().getDimensionPixelSize(tv.resourceId);
One of the Honeycomb samples refers to ?android:attr/actionBarSize
I needed to do replicate these heights properly in a pre-ICS compatibility app and dug into the framework core source. Both answers above are sort of correct.
It basically boils down to using qualifiers. The height is defined by the dimension "action_bar_default_height"
It is defined to 48dip for default. But for -land it is 40dip and for sw600dp it is 56dip.
If you're using the compatibility ActionBar from the recent v7 appcompat support package, you can get the height using
#dimen/abc_action_bar_default_height
Documentation
With the new v7 support library (21.0.0) the name in R.dimen has changed to #dimen/abc_action_bar_default_height_material.
When upgrading from a previous version of the support lib you should therefore use that value as the actionbar's height
If you are using ActionBarSherlock, you can get the height with
#dimen/abs__action_bar_default_height
#AZ13's answer is good, but as per the Android design guidelines, the ActionBar should be at least 48dp high.
Accepted answer in Kotlin :
val Context.actionBarSize
get() = theme.obtainStyledAttributes(intArrayOf(android.R.attr.actionBarSize))
.let { attrs -> attrs.getDimension(0, 0F).toInt().also { attrs.recycle() } }
Usage :
val size = actionBarSize // Inside Activity
val size = requireContext().actionBarSize // Inside Fragment
val size = anyView.context.actionBarSize // Inside RecyclerView ViewHolder
public int getActionBarHeight() {
int actionBarHeight = 0;
TypedValue tv = new TypedValue();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv,
true))
actionBarHeight = TypedValue.complexToDimensionPixelSize(
tv.data, getResources().getDisplayMetrics());
} else {
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,
getResources().getDisplayMetrics());
}
return actionBarHeight;
}
The Class Summary is usually a good place to start. I think the getHeight() method should suffice.
EDIT:
If you need the width, it should be the width of the screen (right?) and that can be gathered like this.
On my Galaxy S4 having > 441dpi > 1080 x 1920 >
Getting Actionbar height with getResources().getDimensionPixelSize I got 144 pixels.
Using formula px = dp x (dpi/160), I was using 441dpi, whereas my device lies
in the category 480dpi. so putting that confirms the result.
I did in this way for myself, this helper method should come in handy for someone:
private static final int[] RES_IDS_ACTION_BAR_SIZE = {R.attr.actionBarSize};
/**
* Calculates the Action Bar height in pixels.
*/
public static int calculateActionBarSize(Context context) {
if (context == null) {
return 0;
}
Resources.Theme curTheme = context.getTheme();
if (curTheme == null) {
return 0;
}
TypedArray att = curTheme.obtainStyledAttributes(RES_IDS_ACTION_BAR_SIZE);
if (att == null) {
return 0;
}
float size = att.getDimension(0, 0);
att.recycle();
return (int) size;
}