Skip to content

Commit 4005294

Browse files
pekingmedsn5ft
authored andcommitted
[ProgressIndicator] Added the function in ProgressIndicatorSpec to load from style.
PiperOrigin-RevId: 322580332
1 parent 745a3ef commit 4005294

File tree

2 files changed

+168
-86
lines changed

2 files changed

+168
-86
lines changed

lib/java/com/google/android/material/progressindicator/ProgressIndicator.java

Lines changed: 8 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
import android.animation.AnimatorSet;
2525
import android.content.Context;
26-
import android.content.res.Resources;
2726
import android.content.res.TypedArray;
2827
import android.graphics.Canvas;
2928
import android.graphics.drawable.Drawable;
@@ -40,7 +39,6 @@
4039
import androidx.annotation.Px;
4140
import androidx.annotation.VisibleForTesting;
4241
import androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback;
43-
import com.google.android.material.color.MaterialColors;
4442
import java.lang.annotation.Retention;
4543
import java.lang.annotation.RetentionPolicy;
4644

@@ -52,8 +50,10 @@
5250
*/
5351
public class ProgressIndicator extends ProgressBar {
5452

55-
private static final int DEF_STYLE_RES =
53+
protected static final int DEF_STYLE_RES =
5654
R.style.Widget_MaterialComponents_ProgressIndicator_Linear_Determinate;
55+
protected static final float DEFAULT_OPACITY = 0.2f;
56+
protected static final int MAX_ALPHA = 255;
5757

5858
// Constants for track shape.
5959

@@ -88,9 +88,6 @@ public class ProgressIndicator extends ProgressBar {
8888
/** The progress indicator will expand from and shrink to the central line of the indicator. */
8989
public static final int GROW_MODE_BIDIRECTIONAL = 3;
9090

91-
private static final float DEFAULT_OPACITY = 0.2f;
92-
private static final int MAX_ALPHA = 255;
93-
9491
/**
9592
* The maximum time, in milliseconds, that the requested hide action is allowed to wait once
9693
* {@link #show()} is called.
@@ -162,8 +159,8 @@ public ProgressIndicator(
162159
context = getContext();
163160

164161
spec = new ProgressIndicatorSpec();
165-
loadDefaultAttributes(context.getResources(), spec);
166-
loadAttributes(context, attrs, defStyleAttr, defStyleRes);
162+
spec.loadFromAttributes(context, attrs, defStyleAttr, defStyleRes);
163+
loadExtraAttributes(context, attrs, defStyleAttr, defStyleRes);
167164

168165
if (spec.indicatorType != CUSTOM) {
169166
initializeDrawables();
@@ -172,88 +169,13 @@ public ProgressIndicator(
172169

173170
// ******************** Initialization **********************
174171

175-
/** Loads some default dimensions from resource file. */
176-
private static void loadDefaultAttributes(Resources resources, ProgressIndicatorSpec spec) {
177-
spec.indicatorWidth = resources.getDimensionPixelSize(R.dimen.mtrl_progress_indicator_width);
178-
spec.circularInset = resources.getDimensionPixelSize(R.dimen.mtrl_progress_circular_inset);
179-
spec.circularRadius = resources.getDimensionPixelSize(R.dimen.mtrl_progress_circular_radius);
180-
// By default, rounded corners are not applied.
181-
spec.indicatorCornerRadius = 0;
182-
}
183-
184-
/** Loads attributes defined in layout or style files. */
185-
private void loadAttributes(
186-
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
172+
/** Loads extra attributes specifically defined for material progress indicator. */
173+
private void loadExtraAttributes(
174+
@NonNull Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
187175
TypedArray a =
188176
context.obtainStyledAttributes(
189177
attrs, R.styleable.ProgressIndicator, defStyleAttr, defStyleRes);
190178

191-
spec.indicatorType = a.getInt(R.styleable.ProgressIndicator_indicatorType, LINEAR);
192-
spec.indicatorWidth =
193-
a.getDimensionPixelSize(R.styleable.ProgressIndicator_indicatorWidth, spec.indicatorWidth);
194-
spec.circularInset =
195-
a.getDimensionPixelSize(R.styleable.ProgressIndicator_circularInset, spec.circularInset);
196-
spec.circularRadius =
197-
a.getDimensionPixelSize(R.styleable.ProgressIndicator_circularRadius, spec.circularRadius);
198-
if (spec.indicatorType == CIRCULAR && spec.circularRadius < spec.indicatorWidth / 2) {
199-
// Throws an exception if circularRadius is less than half of the indicatorWidth, which will
200-
// result in a part of the inner side of the indicator overshoots the center, and the visual
201-
// becomes undefined.
202-
throw new IllegalArgumentException(
203-
"The circularRadius cannot be less than half of the indicatorWidth.");
204-
}
205-
spec.inverse = a.getBoolean(R.styleable.ProgressIndicator_inverse, false);
206-
spec.growMode = a.getInt(R.styleable.ProgressIndicator_growMode, GROW_MODE_NONE);
207-
208-
// Gets indicator colors from resource if existed, otherwise use indicatorColor attribute.
209-
if (a.hasValue(R.styleable.ProgressIndicator_indicatorColors)) {
210-
spec.indicatorColors =
211-
getResources()
212-
.getIntArray(a.getResourceId(R.styleable.ProgressIndicator_indicatorColors, -1));
213-
if (a.hasValue(R.styleable.ProgressIndicator_indicatorColor)) {
214-
// Throws an exception if both indicatorColors and indicatorColor exist in attribute set.
215-
throw new IllegalArgumentException(
216-
"Attributes indicatorColors and indicatorColor cannot be used at the same time.");
217-
} else if (spec.indicatorColors.length == 0) {
218-
// Throws an exception if indicatorColor doesn't exist and indicatorColors is empty.
219-
throw new IllegalArgumentException(
220-
"indicatorColors cannot be empty when indicatorColor is not used.");
221-
}
222-
} else if (a.hasValue(R.styleable.ProgressIndicator_indicatorColor)) {
223-
spec.indicatorColors =
224-
new int[] {a.getColor(R.styleable.ProgressIndicator_indicatorColor, -1)};
225-
} else {
226-
// Uses theme primary color for indicator if neither indicatorColor nor indicatorColors exists
227-
// in attribute set.
228-
spec.indicatorColors = new int[] {MaterialColors.getColor(context, R.attr.colorPrimary, -1)};
229-
}
230-
// Gets track color if defined, otherwise, use indicator color with the disable alpha value.
231-
if (a.hasValue(R.styleable.ProgressIndicator_trackColor)) {
232-
spec.trackColor = a.getColor(R.styleable.ProgressIndicator_trackColor, -1);
233-
} else {
234-
spec.trackColor = spec.indicatorColors[0];
235-
236-
TypedArray disabledAlphaArray =
237-
context.getTheme().obtainStyledAttributes(new int[] {android.R.attr.disabledAlpha});
238-
float defaultOpacity = disabledAlphaArray.getFloat(0, DEFAULT_OPACITY);
239-
disabledAlphaArray.recycle();
240-
241-
int trackAlpha = (int) (MAX_ALPHA * defaultOpacity);
242-
spec.trackColor = MaterialColors.compositeARGBWithAlpha(spec.trackColor, trackAlpha);
243-
}
244-
// Gets linearSeamless or overrides it if necessary.
245-
if (isEligibleToSeamless()) {
246-
spec.linearSeamless = a.getBoolean(R.styleable.ProgressIndicator_linearSeamless, true);
247-
} else {
248-
spec.linearSeamless = false;
249-
}
250-
// Gets the radius of rounded corners if defined, otherwise, use 0 (sharp corner).
251-
setIndicatorCornerRadius(
252-
a.getDimensionPixelSize(
253-
R.styleable.ProgressIndicator_indicatorCornerRadius, spec.indicatorCornerRadius));
254-
// Sets if is indeterminate.
255-
setIndeterminate(a.getBoolean(R.styleable.ProgressIndicator_android_indeterminate, false));
256-
257179
if (a.hasValue(R.styleable.ProgressIndicator_minHideDelay)) {
258180
int minHideDelayUncapped = a.getInt(R.styleable.ProgressIndicator_minHideDelay, -1);
259181
minHideDelay = min(minHideDelayUncapped, MAX_HIDE_DELAY);

lib/java/com/google/android/material/progressindicator/ProgressIndicatorSpec.java

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@
1515
*/
1616
package com.google.android.material.progressindicator;
1717

18+
import com.google.android.material.R;
19+
20+
import static java.lang.Math.min;
21+
22+
import android.content.Context;
23+
import android.content.res.TypedArray;
24+
import android.util.AttributeSet;
25+
import androidx.annotation.DimenRes;
26+
import androidx.annotation.Dimension;
27+
import androidx.annotation.NonNull;
28+
import androidx.annotation.StyleableRes;
29+
import com.google.android.material.color.MaterialColors;
30+
1831
/** A spec class managing all attributes of {@link ProgressIndicator}. */
1932
public final class ProgressIndicatorSpec {
2033

@@ -67,4 +80,151 @@ public final class ProgressIndicatorSpec {
6780
* connected. Ignored for determinate mode and indeterminate mode with less than 3 colors.
6881
*/
6982
public boolean linearSeamless;
83+
84+
public void loadFromAttributes(@NonNull Context context, AttributeSet attrs, int defStyleAttr) {
85+
loadFromAttributes(context, attrs, defStyleAttr, ProgressIndicator.DEF_STYLE_RES);
86+
}
87+
88+
public void loadFromAttributes(
89+
@NonNull Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
90+
TypedArray a =
91+
context.obtainStyledAttributes(
92+
attrs, R.styleable.ProgressIndicator, defStyleAttr, defStyleRes);
93+
indicatorType = a.getInt(R.styleable.ProgressIndicator_indicatorType, ProgressIndicator.LINEAR);
94+
indicatorWidth =
95+
getDimensionPixelSize(
96+
context,
97+
a,
98+
R.styleable.ProgressIndicator_indicatorWidth,
99+
R.dimen.mtrl_progress_indicator_width);
100+
circularInset =
101+
getDimensionPixelSize(
102+
context,
103+
a,
104+
R.styleable.ProgressIndicator_circularInset,
105+
R.dimen.mtrl_progress_circular_inset);
106+
circularRadius =
107+
getDimensionPixelSize(
108+
context,
109+
a,
110+
R.styleable.ProgressIndicator_circularRadius,
111+
R.dimen.mtrl_progress_circular_radius);
112+
inverse = a.getBoolean(R.styleable.ProgressIndicator_inverse, false);
113+
growMode = a.getInt(R.styleable.ProgressIndicator_growMode, ProgressIndicator.GROW_MODE_NONE);
114+
115+
// Loads the indicator colors.
116+
loadIndicatorColors(context, a);
117+
118+
// Loads the track color.
119+
loadTrackColor(context, a);
120+
121+
linearSeamless =
122+
a.getBoolean(R.styleable.ProgressIndicator_linearSeamless, true)
123+
&& indicatorType == ProgressIndicator.LINEAR
124+
&& indicatorColors.length >= 3;
125+
indicatorCornerRadius =
126+
min(
127+
a.getDimensionPixelSize(R.styleable.ProgressIndicator_indicatorCornerRadius, 0),
128+
indicatorWidth / 2);
129+
130+
a.recycle();
131+
132+
validate();
133+
}
134+
135+
public void validate() {
136+
if (indicatorType == ProgressIndicator.CIRCULAR && circularRadius < indicatorWidth / 2) {
137+
// Throws an exception if circularRadius is less than half of the indicatorWidth, which will
138+
// result in a part of the inner side of the indicator overshoots the center, and the visual
139+
// becomes undefined.
140+
throw new IllegalArgumentException(
141+
"The circularRadius cannot be less than half of the indicatorWidth.");
142+
}
143+
if (linearSeamless && indicatorCornerRadius > 0) {
144+
// Throws an exception if trying to use cornered indicator for linear seamless mode.
145+
throw new IllegalArgumentException(
146+
"Rounded corners are not supported in linear seamless mode.");
147+
}
148+
}
149+
150+
/**
151+
* Returns a dimension in pixels from attributes if available; otherwise, the default resource
152+
* value. This method doesn't recycle the {@link TypedArray} argument.
153+
*
154+
* @param context The current active context.
155+
* @param typedArray The TypedArray object of the attributes.
156+
* @param resId The styleable id of the attribute.
157+
* @param defaultResId The resource id of the default value.
158+
*/
159+
@Dimension
160+
private static int getDimensionPixelSize(
161+
@NonNull Context context,
162+
@NonNull TypedArray typedArray,
163+
@StyleableRes int resId,
164+
@DimenRes int defaultResId) {
165+
return typedArray.getDimensionPixelSize(
166+
resId, context.getResources().getDimensionPixelSize(defaultResId));
167+
}
168+
169+
/**
170+
* Loads the indicatorColors from attributes if existing; otherwise, uses indicatorColor attribute
171+
* or theme primary color for the indicator. This method doesn't recycle the {@link TypedArray}
172+
* argument.
173+
*
174+
* @param context The current active context.
175+
* @param typedArray The TypedArray object of the attributes.
176+
* @throws IllegalArgumentException if both indicatorColors and indicatorColor exist in attribute
177+
* set.
178+
* @throws IllegalArgumentException if indicatorColor doesn't exist and indicatorColors is empty.
179+
*/
180+
private void loadIndicatorColors(@NonNull Context context, @NonNull TypedArray typedArray) {
181+
if (typedArray.hasValue(R.styleable.ProgressIndicator_indicatorColors)) {
182+
indicatorColors =
183+
context
184+
.getResources()
185+
.getIntArray(
186+
typedArray.getResourceId(R.styleable.ProgressIndicator_indicatorColors, -1));
187+
if (typedArray.hasValue(R.styleable.ProgressIndicator_indicatorColor)) {
188+
throw new IllegalArgumentException(
189+
"Attributes indicatorColors and indicatorColor cannot be used at the same time.");
190+
}
191+
if (indicatorColors.length == 0) {
192+
throw new IllegalArgumentException(
193+
"indicatorColors cannot be empty when indicatorColor is not used.");
194+
}
195+
} else {
196+
// Uses theme primary color for indicator if neither indicatorColor nor indicatorColors exists
197+
// in attribute set.
198+
indicatorColors =
199+
new int[] {
200+
typedArray.hasValue(R.styleable.ProgressIndicator_indicatorColor)
201+
? typedArray.getColor(R.styleable.ProgressIndicator_indicatorColor, -1)
202+
: MaterialColors.getColor(context, R.attr.colorPrimary, -1)
203+
};
204+
}
205+
}
206+
207+
/**
208+
* Loads the trackColor from attributes if existing; otherwise, uses the first value in {@link
209+
* #indicatorColors} applying the alpha value for disable items from theme. This method doesn't
210+
* recycle the {@link TypedArray} argument.
211+
*
212+
* @param context The current active context.
213+
* @param typedArray The TypedArray object of the attributes.
214+
*/
215+
private void loadTrackColor(@NonNull Context context, @NonNull TypedArray typedArray) {
216+
if (typedArray.hasValue(R.styleable.ProgressIndicator_trackColor)) {
217+
trackColor = typedArray.getColor(R.styleable.ProgressIndicator_trackColor, -1);
218+
} else {
219+
trackColor = indicatorColors[0];
220+
221+
TypedArray disabledAlphaArray =
222+
context.getTheme().obtainStyledAttributes(new int[] {android.R.attr.disabledAlpha});
223+
float defaultOpacity = disabledAlphaArray.getFloat(0, ProgressIndicator.DEFAULT_OPACITY);
224+
disabledAlphaArray.recycle();
225+
226+
int trackAlpha = (int) (ProgressIndicator.MAX_ALPHA * defaultOpacity);
227+
trackColor = MaterialColors.compositeARGBWithAlpha(trackColor, trackAlpha);
228+
}
229+
}
70230
}

0 commit comments

Comments
 (0)