[ProgressIndicator] Added fraction support in track corner radius.

PiperOrigin-RevId: 733576933
This commit is contained in:
pekingme 2025-03-05 05:39:05 +00:00 committed by pfthomas
parent 99ff34c0f2
commit 2e97dd672e
9 changed files with 183 additions and 114 deletions

View File

@ -80,7 +80,7 @@ public class ProgressIndicatorMainDemoFragment extends ProgressIndicatorDemoFrag
Slider thicknessSlider = view.findViewById(R.id.thicknessSlider);
thicknessSlider.addOnChangeListener(
(slider, value, fromUser) -> {
int newThickness = Math.round(value * pixelsInDp);
int newThickness = (int) (value * pixelsInDp);
if (linearIndicator.getTrackThickness() != newThickness) {
linearIndicator.setTrackThickness(newThickness);
}
@ -92,7 +92,7 @@ public class ProgressIndicatorMainDemoFragment extends ProgressIndicatorDemoFrag
Slider cornerSlider = view.findViewById(R.id.cornerSlider);
cornerSlider.addOnChangeListener(
(slider, value, fromUser) -> {
int newCornerRadius = Math.round(value * pixelsInDp);
int newCornerRadius = (int) (value * pixelsInDp);
if (linearIndicator.getTrackCornerRadius() != newCornerRadius) {
linearIndicator.setTrackCornerRadius(newCornerRadius);
}
@ -104,7 +104,7 @@ public class ProgressIndicatorMainDemoFragment extends ProgressIndicatorDemoFrag
Slider gapSlider = view.findViewById(R.id.gapSlider);
gapSlider.addOnChangeListener(
(slider, value, fromUser) -> {
int newGapSize = Math.round(value * pixelsInDp);
int newGapSize = (int) (value * pixelsInDp);
if (linearIndicator.getIndicatorTrackGapSize() != newGapSize) {
linearIndicator.setIndicatorTrackGapSize(newGapSize);
}
@ -125,7 +125,7 @@ public class ProgressIndicatorMainDemoFragment extends ProgressIndicatorDemoFrag
Slider linearStopIndicatorSlider = view.findViewById(R.id.linearStopIndicatorSizeSlider);
linearStopIndicatorSlider.addOnChangeListener(
(slider, value, fromUser) -> {
int newStopIndicatorSize = Math.round(value * pixelsInDp);
int newStopIndicatorSize = (int) (value * pixelsInDp);
if (linearIndicator.getTrackStopIndicatorSize() != newStopIndicatorSize) {
linearIndicator.setTrackStopIndicatorSize(newStopIndicatorSize);
}
@ -134,7 +134,7 @@ public class ProgressIndicatorMainDemoFragment extends ProgressIndicatorDemoFrag
Slider circularSizeSlider = view.findViewById(R.id.circularSizeSlider);
circularSizeSlider.addOnChangeListener(
(slider, value, fromUser) -> {
int newCornerRadius = Math.round(value * pixelsInDp);
int newCornerRadius = (int) (value * pixelsInDp);
if (circularIndicator.getIndicatorSize() != newCornerRadius) {
circularIndicator.setIndicatorSize(newCornerRadius);
}

View File

@ -50,12 +50,10 @@ A determinate progress indicator can be added to a layout:
```xml
<!-- Linear progress indicator -->
<com.google.android.material.progressindicator.LinearProgressIndicator
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- Circular progress indicator -->
android:layout_width="match_parent"
android:layout_height="wrap_content" /><!-- Circular progress indicator -->
<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:layout_width="wrap_content" android:layout_height="wrap_content" />
```
An indeterminate progress indicator can be added:
@ -63,21 +61,19 @@ An indeterminate progress indicator can be added:
```xml
<!-- Linear progress indicator -->
<com.google.android.material.progressindicator.LinearProgressIndicator
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true" />
<!-- Circular progress indicator -->
android:layout_width="match_parent" android:layout_height="wrap_content"
android:indeterminate="true" /><!-- Circular progress indicator -->
<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:indeterminate="true" />
```
![Animation of determinate and indeterminate linear and circular progress indicators: red
indicators travel along pink tracks](assets/progressindicator/linear_circular_composite.gif)
![Animation of determinate and indeterminate linear and circular progress
indicators: red indicators travel along pink
tracks](assets/progressindicator/linear_circular_composite.gif)
1. Determinate
2. Indeterminate
1. Determinate
2. Indeterminate
### Switching from indeterminate to determinate
@ -85,13 +81,13 @@ Indeterminate progress indicators can smoothly transit to determinate progress
indicators by setting the `progress` programmatically:
```kt
int progress = getLoadingProgress()
int progress = getLoadingProgress ()
indicator.setProgressCompat(progress, true)
```
**Note:** Once indeterminate progress indicators are switched to the
determinate mode (or initialized as determinate), they can be set back to
indeterminate mode via calling the `setIndeterminate(true)` method.
**Note:** Once indeterminate progress indicators are switched to the determinate
mode (or initialized as determinate), they can be set back to indeterminate mode
via calling the `setIndeterminate(true)` method.
### Making progress indicators accessible
@ -132,8 +128,8 @@ The modes of behaviors are:
edge and hides the view by collapsing to the baseline (bottom edge); for the
circular type, shows the view by expanding from the outer edge and hides the
view by collapsing to the inner edge.
* `escape` - for the linear type, escapes in the progression direction; for the
circular type, no effect.
* `escape` - for the linear type, escapes in the progression direction; for
the circular type, no effect.
When the hide animation behavior is not none, the visibility of the view will be
changed after the animation finishes. Please use `setVisibilityAfterHide` method
@ -142,8 +138,9 @@ to set the target visibility as `Visibility.INVISIBLE` (default) or
### Rounded corners
Progress indicators can have rounded corners via `app:trackCornerRadius` or the
`setTrackCornerRadius` method.
Progress indicators can have rounded corners via `app:trackCornerRadius` (in dp
or fraction) or the `setTrackCornerRadius` and `setTrackCornerRadiusFraction`
methods.
### Types
@ -179,7 +176,8 @@ API and source code:
The following example shows a determinate linear progress indicator.
<img src="assets/progressindicator/linear_determinate.gif" alt="Determinate linear progress indicator animation: purple indicator fills up
<img src="assets/progressindicator/linear_determinate.gif" alt="Determinate
linear progress indicator animation: purple indicator fills up
grey
track" width="600"/>
@ -187,13 +185,13 @@ In the layout:
```xml
<com.google.android.material.progressindicator.LinearProgressIndicator
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_width="match_parent" android:layout_height="wrap_content" />
```
The following example shows an indeterminate linear progress indicator.
<img src="assets/progressindicator/linear_indeterminate.gif" alt="Indeterminate linear progress indicator animation: purple indicator travels
<img src="assets/progressindicator/linear_indeterminate.gif" alt="Indeterminate
linear progress indicator animation: purple indicator travels
along grey
track" width="600"/>
@ -201,9 +199,8 @@ In the layout:
```xml
<com.google.android.material.progressindicator.LinearProgressIndicator
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true" />
android:layout_width="match_parent" android:layout_height="wrap_content"
android:indeterminate="true" />
```
#### Multi-color indeterminate animation type
@ -211,14 +208,12 @@ In the layout:
For linear progress indicator, there are two indeterminate animation types:
* `disjoint` - animates as repeated cycles with two disjoint segments in the
same color at a time. <img src="assets/progressindicator/linear_multicolor_disjoint.gif" alt="Disjointed indeterminate linear progress indicator animation: red indicator
travels along track 2x then switches to
yellow" width="600"/>
same color at a time.
<img src=" assets/progressindicator/linear_multicolor_disjoint.gif" alt="Disjointed indeterminate linear progress indicator animation: red indicator travels along track 2x then switches to yellow" width="600"/>
* `contiguous` - animates as repeated cycles with three adjacent segments in
different colors. <img src="assets/progressindicator/linear_multicolor_contiguous.gif" alt="Contiguous indeterminate linear progress indicator
animation: red, yellow, blue indicators move sequentially and cover
track" width="600"/>
different colors.
<img src=" assets/progressindicator/linear_multicolor_contiguous.gif" alt="Contiguous indeterminate linear progress indicator animation: red, yellow, blue indicators move sequentially and cover track" width="600"/>
**Note:** There is a minimum requirement of 3 indicator colors to use the
**contiguous** animation. Otherwise, an IllegalArgumentException will be thrown.
@ -245,7 +240,8 @@ API and source code:
The following example shows a determinate circular progress indicator.
<img src="assets/progressindicator/circular_determinate.gif" alt="Determinate circular progress indicator animation: purple indicator draws a
<img src="assets/progressindicator/circular_determinate.gif" alt="Determinate
circular progress indicator animation: purple indicator draws a
circle clockwise from the
top" width="600"/>
@ -253,13 +249,13 @@ In the layout:
```xml
<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:layout_width="wrap_content" android:layout_height="wrap_content" />
```
The following example shows an indeterminate circular progress indicator.
<img src="assets/progressindicator/circular_indeterminate.gif" alt="Indeterminate circular progress indicator animation: purple indicator follows
<img src="assets/progressindicator/circular_indeterminate.gif" alt="
Indeterminate circular progress indicator animation: purple indicator follows
a circle clockwise from the
top" width="600"/>
@ -267,9 +263,8 @@ In the layout:
```xml
<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:indeterminate="true" />
```
### Anatomy and key properties
@ -278,32 +273,32 @@ A progress indicator consists of a track and an indicator.
![Progress indicator anatomy composite](assets/progressindicator/anatomy.png)
1. Active indicator
2. Track
3. Stop indicator
1. Active indicator
2. Track
3. Stop indicator
#### Common attributes
The following attributes are shared between linear and circular progress
indicators:
Element | Attribute | Related method(s) | Default value
----------------------------------------- | ---------------------------------------- | ------------------------------------------------------------ | -------------
**Track thickness** | `app:trackThickness` | `setTrackThickness`<br>`getTrackThickness` | `4dp`
**Indicator color** | `app:indicatorColor` | `setIndicatorColor`<br>`getIndicatorColor` | `colorPrimary`
**Track color** | `app:trackColor` | `setTrackColor`<br>`getTrackColor` | `colorPrimaryContainer` (linear)<br>`@android:color/transparent` (circular)
**Track corner radius** | `app:trackCornerRadius` | `setTrackCornerRadius`<br>`getTrackCornerRadius` | `2dp`
**Indicator track gap size** | `app:indicatorTrackGapSize` | `setIndicatorTrackGapSize`<br>`getIndicatorTrackGapSize` | `4dp`
**Show animation behavior** | `app:showAnimationBehavior` | `setShowAnimationBehavior`<br>`getShowAnimationBehavior` | `none`
**Hide animation behavior** | `app:hideAnimationBehavior` | `setHideAnimationBehavior`<br>`getHideAnimationBehavior` | `none`
**Delay (in ms) to show** | `app:showDelay` | N/A | 0
**Min delay (in ms) to hide** | `app:minHideDelay` | N/A | 0
**Wavelength** | `app:wavelength` | `setWavelength` | 0
**Wavelength in determinate mode** | `app:wavelengthDeterminate` | `setWavelengthDeterminate`<br>`getWavelenthDeterminate` | `wavelength`
**Wavelength in indeterminate mode** | `app:wavelengthIndeterminate` | `setWavelengthIndeterminate`<br>`getWavelengthIndeterminate` | `wavelength`
**Wave amplitude** | `app:waveAmplitude` | `setWaveAmplitude`<br>`getWaveAmplitude` | 0
**Wave speed** | `app:waveSpeed` | `setWaveSpeed`<br>`getWaveSpeed` | 0
**Indeterminate animator duration scale** | `app:indeterminateAnimatorDurationScale` | `setIndeterminateAnimatorDurationScale` | 1
Element | Attribute | Related method(s) | Default value
----------------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------- | -------------
**Track thickness** | `app:trackThickness` | `setTrackThickness`<br>`getTrackThickness` | `4dp`
**Indicator color** | `app:indicatorColor` | `setIndicatorColor`<br>`getIndicatorColor` | `colorPrimary`
**Track color** | `app:trackColor` | `setTrackColor`<br>`getTrackColor` | `colorPrimaryContainer` (linear)<br>`@android:color/transparent` (circular)
**Track corner radius** | `app:trackCornerRadius` | `setTrackCornerRadius`<br>`setTrackCornerRadiusFraction`<br>`getTrackCornerRadius` | `50%`
**Indicator track gap size** | `app:indicatorTrackGapSize` | `setIndicatorTrackGapSize`<br>`getIndicatorTrackGapSize` | `4dp`
**Show animation behavior** | `app:showAnimationBehavior` | `setShowAnimationBehavior`<br>`getShowAnimationBehavior` | `none`
**Hide animation behavior** | `app:hideAnimationBehavior` | `setHideAnimationBehavior`<br>`getHideAnimationBehavior` | `none`
**Delay (in ms) to show** | `app:showDelay` | N/A | 0
**Min delay (in ms) to hide** | `app:minHideDelay` | N/A | 0
**Wavelength** | `app:wavelength` | `setWavelength` | 0
**Wavelength in determinate mode** | `app:wavelengthDeterminate` | `setWavelengthDeterminate`<br>`getWavelenthDeterminate` | `wavelength`
**Wavelength in indeterminate mode** | `app:wavelengthIndeterminate` | `setWavelengthIndeterminate`<br>`getWavelengthIndeterminate` | `wavelength`
**Wave amplitude** | `app:waveAmplitude` | `setWaveAmplitude`<br>`getWaveAmplitude` | 0
**Wave speed** | `app:waveSpeed` | `setWaveSpeed`<br>`getWaveSpeed` | 0
**Indeterminate animator duration scale** | `app:indeterminateAnimatorDurationScale` | `setIndeterminateAnimatorDurationScale` | 1
#### Linear type specific attributes
@ -314,7 +309,7 @@ Element | Attribute | Related me
**Indeterminate animation type** | `app:indeterminateAnimationType` | `setIndeterminateAnimationType`<br>`getIndeterminateAnimationType` | `disjoint`
**Indicator direction** | `app:indicatorDirectionLinear` | `setIndicatorDirection`<br>`getIndicatorDirection` | `leftToRight`
**Track stop indicator size** | `app:trackStopIndicatorSize` | `setTrackStopIndicatorSize`<br>`getTrackStopIndicatorSize` | `4dp`
**Track inner corner radius** | `app:trackInnerCornerRadius` | `setTrackInnerCornerRadius`<br>`setTrackInnerCornerRadiusFraction`<br>`getTrackInnerCornerRadius` | `none`
**Track inner corner radius** | `app:trackInnerCornerRadius` | `setTrackInnerCornerRadius`<br>`setTrackInnerCornerRadiusFraction`<br>`getTrackInnerCornerRadius` | `none` (use `trackCornerRadius`)
#### Circular type specific attributes
@ -352,16 +347,16 @@ In order to comply with the latest accessibility requirements, the
`LinearProgressIndicator` and `CircularProgressIndicator` have been updated with
additional attributes:
- `app:indicatorTrackGapSize`: size of the gap between the indicator and the
track, 4dp by default.
- `app:trackStopIndicatorSize`: size of the stop at the end of the track, 4dp by
default. Only applies to the linear determinate configuration.
- `app:indicatorTrackGapSize`: size of the gap between the indicator and the
track, 4dp by default.
- `app:trackStopIndicatorSize`: size of the stop at the end of the track, 4dp
by default. Only applies to the linear determinate configuration.
`*.Legacy` styles have been added to revert to the previous behavior (**not
recommended**):
- `Widget.Material3.LinearProgressIndicator.Legacy`
- `Widget.Material3.CircularProgressIndicator.Legacy`
- `Widget.Material3.LinearProgressIndicator.Legacy`
- `Widget.Material3.CircularProgressIndicator.Legacy`
## Theming
@ -391,8 +386,8 @@ circular progress indicators and affects other components:
```xml
<style name="Theme.App" parent="Theme.Material3.*">
...
<item name="colorPrimary">@color/shrine_pink_100</item>
...
<item name="colorPrimary">@color/shrine_pink_100</item>
</style>
```
@ -401,17 +396,22 @@ all circular progress indicators but does not affect other components:
```xml
<style name="Theme.App" parent="Theme.Material3.*">
...
<item name="circularProgressIndicatorStyle">@style/Widget.App.CircularProgressIndicator</item>
...
<item name="circularProgressIndicatorStyle">
@style/Widget.App.CircularProgressIndicator
</item>
</style>
<style name="Widget.App.CircularProgressIndicator" parent="Widget.Material3.CircularProgressIndicator.Legacy">
<item name="materialThemeOverlay">@style/ThemeOverlay.App.CircularProgressIndicator</item>
<item name="trackThickness">20dp</item>
<style name="Widget.App.CircularProgressIndicator"
parent="Widget.Material3.CircularProgressIndicator.Legacy">
<item name="materialThemeOverlay">
@style/ThemeOverlay.App.CircularProgressIndicator
</item>
<item name="trackThickness">20dp</item>
</style>
<style name="ThemeOverlay.App.CircularProgressIndicator" parent="">
<item name="colorPrimary">@color/shrine_pink_100</item>
<item name="colorPrimary">@color/shrine_pink_100</item>
</style>
```
@ -419,7 +419,5 @@ Use the style in the layout, which affects only this specific circular progress
indicator:
```xml
<com.google.android.material.progressindicator.CircularProgressIndicator
...
style="@style/Widget.App.CircularProgressIndicator" />
<com.google.android.material.progressindicator.CircularProgressIndicator...style="@style/Widget.App.CircularProgressIndicator" />
```

View File

@ -647,7 +647,36 @@ public abstract class BaseProgressIndicator<S extends BaseProgressIndicatorSpec>
*/
public void setTrackCornerRadius(@Px int trackCornerRadius) {
if (spec.trackCornerRadius != trackCornerRadius) {
spec.trackCornerRadius = Math.round(min(trackCornerRadius, spec.trackThickness / 2f));
spec.trackCornerRadius = min(trackCornerRadius, spec.trackThickness / 2);
spec.useRelativeTrackCornerRadius = false;
invalidate();
}
}
/**
* Returns the relative radius of the rounded corner for the indicator and track in pixels.
*
* @see #setTrackCornerRadiusFraction(float)
* @attr ref
* com.google.android.material.progressindicator.R.styleable#BaseProgressIndicator_trackCornerRadius
*/
public float getTrackCornerRadiusFraction() {
return spec.trackCornerRadiusFraction;
}
/**
* Sets the radius of the rounded corner for the indicator and track in fraction of track
* thickness.
*
* @param fraction The fraction of corner radius to track thickness.
* @see #getTrackCornerRadiusFraction()
* @attr ref
* com.google.android.material.progressindicator.R.styleable#BaseProgressIndicator_trackCornerRadius
*/
public void setTrackCornerRadiusFraction(@FloatRange(from = 0f, to = 0.5f) float fraction) {
if (spec.trackCornerRadiusFraction != fraction) {
spec.trackCornerRadiusFraction = min(fraction, 0.5f);
spec.useRelativeTrackCornerRadius = true;
invalidate();
}
}

View File

@ -54,6 +54,18 @@ public abstract class BaseProgressIndicatorSpec {
*/
@Px public int trackCornerRadius;
/**
* The fraction of the track thickness to be used as the corner radius. And the stroke ROUND cap
* is used to prevent artifacts like (b/319309456), when 0.5f is specified.
*/
public float trackCornerRadiusFraction;
/**
* When this is true, the {#link trackCornerRadiusFraction} takes effect. Otherwise, the {@link
* trackCornerRadius} takes effect.
*/
public boolean useRelativeTrackCornerRadius;
/**
* The color array used in the indicator. In determinate mode, only the first item will be used.
*/
@ -112,11 +124,21 @@ public abstract class BaseProgressIndicatorSpec {
trackThickness =
getDimensionPixelSize(
context, a, R.styleable.BaseProgressIndicator_trackThickness, defaultIndicatorSize);
trackCornerRadius =
min(
getDimensionPixelSize(
context, a, R.styleable.BaseProgressIndicator_trackCornerRadius, 0),
Math.round(trackThickness / 2f));
TypedValue trackCornerRadiusValue =
a.peekValue(R.styleable.BaseProgressIndicator_trackCornerRadius);
if (trackCornerRadiusValue != null) {
if (trackCornerRadiusValue.type == TypedValue.TYPE_DIMENSION) {
trackCornerRadius =
min(
TypedValue.complexToDimensionPixelSize(
trackCornerRadiusValue.data, a.getResources().getDisplayMetrics()),
trackThickness / 2);
useRelativeTrackCornerRadius = false;
} else if (trackCornerRadiusValue.type == TypedValue.TYPE_FRACTION) {
trackCornerRadiusFraction = min(trackCornerRadiusValue.getFraction(1.0f, 1.0f), 0.5f);
useRelativeTrackCornerRadius = true;
}
}
showAnimationBehavior =
a.getInt(
R.styleable.BaseProgressIndicator_showAnimationBehavior,
@ -222,6 +244,27 @@ public abstract class BaseProgressIndicatorSpec {
&& ((!isDeterminate && wavelengthIndeterminate > 0)
|| (isDeterminate && wavelengthDeterminate > 0));
}
/**
* Returns the track corner radius in pixels.
*
* <p>If {@link #useRelativeTrackCornerRadius} is true, the track corner radius is calculated
* using the track thickness and the track corner radius fraction. Otherwise, the track corner
* radius is returned directly.
*/
public int getTrackCornerRadiusInPx() {
return useRelativeTrackCornerRadius
? (int) (trackThickness * trackCornerRadiusFraction)
: trackCornerRadius;
}
/**
* Returns true if the stroke ROUND cap should be used to prevent artifacts like (b/319309456),
* when fully rounded corners are specified.
*/
public boolean useStrokeCap() {
return useRelativeTrackCornerRadius && trackCornerRadiusFraction == 0.5f;
}
@CallSuper
void validateSpec() {

View File

@ -58,8 +58,6 @@ final class CircularDrawingDelegate extends DrawingDelegate<CircularProgressIndi
private float cachedAmplitude;
private int cachedWavelength;
private float cachedRadius;
// For full round ends, the stroke ROUND cap is used to prevent artifacts like (b/319309456).
private boolean useStrokeCap;
private boolean drawingDeterminateIndicator;
// This will be used in the ESCAPE hide animation. The start and end fraction in track will be
@ -138,10 +136,9 @@ final class CircularDrawingDelegate extends DrawingDelegate<CircularProgressIndi
-outerRadiusWithInset, -outerRadiusWithInset, outerRadiusWithInset, outerRadiusWithInset);
// These are used when drawing the indicator and track.
useStrokeCap = spec.trackThickness / 2f <= spec.trackCornerRadius;
displayedTrackThickness = spec.trackThickness * trackThicknessFraction;
displayedCornerRadius =
min(spec.trackThickness / 2f, spec.trackCornerRadius) * trackThicknessFraction;
min(spec.trackThickness / 2, spec.getTrackCornerRadiusInPx()) * trackThicknessFraction;
displayedAmplitude = spec.waveAmplitude * trackThicknessFraction;
// Further adjusts the radius for animated visibility change.
@ -348,7 +345,7 @@ final class CircularDrawingDelegate extends DrawingDelegate<CircularProgressIndi
} else {
// Draws the arc with ROUND cap if the corner radius is half of the track thickness.
paint.setStyle(Style.STROKE);
paint.setStrokeCap(useStrokeCap ? Cap.ROUND : Cap.BUTT);
paint.setStrokeCap(spec.useStrokeCap() ? Cap.ROUND : Cap.BUTT);
// Draws the arc without rounded corners.
float startDegreeWithoutCorners = startDegree + displayedCornerRadiusInDegree;
float arcDegreeWithoutCorners = arcDegree - displayedCornerRadiusInDegree * 2;
@ -374,7 +371,7 @@ final class CircularDrawingDelegate extends DrawingDelegate<CircularProgressIndi
}
// Draws rounded rectangles if ROUND cap is not used and the corner radius is bigger than 0.
if (!useStrokeCap && displayedCornerRadius > 0) {
if (!spec.useStrokeCap() && displayedCornerRadius > 0) {
paint.setStyle(Style.FILL);
drawRoundedBlock(canvas, paint, endPoints.first, blockWidth, displayedTrackThickness);
drawRoundedBlock(canvas, paint, endPoints.second, blockWidth, displayedTrackThickness);

View File

@ -55,7 +55,6 @@ final class LinearDrawingDelegate extends DrawingDelegate<LinearProgressIndicato
private float displayedAmplitude;
private float adjustedWavelength;
private int cachedWavelength;
private boolean useStrokeCap;
private boolean drawingDeterminateIndicator;
// This will be used in the ESCAPE hide animation. The start and end fraction in track will be
@ -124,14 +123,11 @@ final class LinearDrawingDelegate extends DrawingDelegate<LinearProgressIndicato
// These are set for the drawing the indicator and track.
displayedTrackThickness = spec.trackThickness * trackThicknessFraction;
displayedCornerRadius =
min(spec.trackThickness / 2f, spec.trackCornerRadius) * trackThicknessFraction;
min(spec.trackThickness / 2, spec.getTrackCornerRadiusInPx()) * trackThicknessFraction;
displayedAmplitude = spec.waveAmplitude * trackThicknessFraction;
displayedInnerCornerRadius =
min(spec.trackThickness / 2f, spec.getTrackInnerCornerRadiusInPx())
* trackThicknessFraction;
useStrokeCap =
spec.trackThickness / 2f <= spec.trackCornerRadius
&& displayedCornerRadius == displayedInnerCornerRadius;
// Further adjusts the canvas for animated visibility change.
if (isShowing || isHiding) {
@ -319,7 +315,7 @@ final class LinearDrawingDelegate extends DrawingDelegate<LinearProgressIndicato
// Draws the path with ROUND cap if the corner radius is half of the track
// thickness.
paint.setStyle(Style.STROKE);
paint.setStrokeCap(useStrokeCap ? Cap.ROUND : Cap.BUTT);
paint.setStrokeCap(spec.useStrokeCap() ? Cap.ROUND : Cap.BUTT);
// If start rounded block is on the left of end rounded block, draws the path with the
// start and end rounded blocks.
@ -343,7 +339,7 @@ final class LinearDrawingDelegate extends DrawingDelegate<LinearProgressIndicato
phaseFraction);
canvas.drawPath(displayedActivePath, paint);
}
if (!useStrokeCap) {
if (!spec.useStrokeCap()) {
if (startBlockCenterX > 0 && startCornerRadius > 0) {
// Draws the start rounded block.
drawRoundedBlock(

View File

@ -130,12 +130,17 @@ public final class LinearProgressIndicatorSpec extends BaseProgressIndicatorSpec
public int getTrackInnerCornerRadiusInPx() {
return !hasInnerCornerRadius
? trackCornerRadius
? getTrackCornerRadiusInPx()
: useRelativeTrackInnerCornerRadius
? (int) (trackThickness * trackInnerCornerRadiusFraction)
: trackInnerCornerRadius;
}
@Override
public boolean useStrokeCap() {
return super.useStrokeCap() && getTrackInnerCornerRadiusInPx() == getTrackCornerRadiusInPx();
}
@Override
void validateSpec() {
super.validateSpec();
@ -145,7 +150,8 @@ public final class LinearProgressIndicatorSpec extends BaseProgressIndicatorSpec
}
if (indeterminateAnimationType
== LinearProgressIndicator.INDETERMINATE_ANIMATION_TYPE_CONTIGUOUS) {
if ((trackCornerRadius > 0 || (hasInnerCornerRadius && getTrackInnerCornerRadiusInPx() > 0))
if ((getTrackCornerRadiusInPx() > 0
|| (hasInnerCornerRadius && getTrackInnerCornerRadiusInPx() > 0))
&& indicatorTrackGapSize == 0) {
// Throws an exception if trying to use the cornered indicator/track with contiguous
// indeterminate animation type without gap.

View File

@ -24,9 +24,9 @@
<!--
The radius of each corner of both the indicator and the track. A radius
larger than half of the track width will throw exceptions during
initialization.
initialization. Use 50% for fully rounded corners.
-->
<attr name="trackCornerRadius" format="dimension" />
<attr name="trackCornerRadius" format="dimension|fraction" />
<!--
The indicator color (or colors in an array). By default, it uses theme
primary color.

View File

@ -84,7 +84,7 @@
<item name="trackThickness">@dimen/m3_comp_progress_indicator_linear_track_thickness</item>
<item name="trackColor">@macro/m3_comp_progress_indicator_track_color</item>
<item name="indicatorColor">@macro/m3_comp_progress_indicator_active_indicator_color</item>
<item name="trackCornerRadius">2dp</item>
<item name="trackCornerRadius">50%</item>
<item name="indicatorTrackGapSize">@dimen/m3_comp_progress_indicator_linear_track_active_indicator_space</item>
<item name="trackStopIndicatorSize">@dimen/m3_comp_progress_indicator_linear_stop_indicator_size</item>
</style>
@ -95,7 +95,7 @@
<item name="indicatorSize">@dimen/m3_comp_progress_indicator_circular_size</item>
<item name="indicatorColor">@macro/m3_comp_progress_indicator_active_indicator_color</item>
<item name="trackColor">@macro/m3_comp_progress_indicator_track_color</item>
<item name="trackCornerRadius">2dp</item>
<item name="trackCornerRadius">50%</item>
<item name="indicatorTrackGapSize">@dimen/m3_comp_progress_indicator_circular_track_active_indicator_space</item>
<item name="indeterminateTrackVisible">false</item>
</style>
@ -104,14 +104,14 @@
<item name="trackThickness">@dimen/mtrl_progress_circular_track_thickness_small</item>
<item name="indicatorSize">@dimen/mtrl_progress_circular_size_small</item>
<item name="indicatorInset">@dimen/mtrl_progress_circular_inset_small</item>
<item name="trackCornerRadius">1.5dp</item>
<item name="trackCornerRadius">50%</item>
<item name="indicatorTrackGapSize">3dp</item>
</style>
<style name="Widget.Material3.CircularProgressIndicator.ExtraSmall">
<item name="trackThickness">@dimen/mtrl_progress_circular_track_thickness_extra_small</item>
<item name="indicatorSize">@dimen/mtrl_progress_circular_size_extra_small</item>
<item name="indicatorInset">@dimen/mtrl_progress_circular_inset_extra_small</item>
<item name="trackCornerRadius">1.25dp</item>
<item name="trackCornerRadius">50%</item>
<item name="indicatorTrackGapSize">2dp</item>
</style>