Skip to content

Commit 998fe83

Browse files
committed
[Carousel] Change custom Carousel strategies to be restricted visibility in order to refactor custom strategies
PiperOrigin-RevId: 707143621
1 parent 9e256b6 commit 998fe83

File tree

7 files changed

+16
-96
lines changed

7 files changed

+16
-96
lines changed

docs/components/Carousel.md

Lines changed: 0 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -259,99 +259,3 @@ carouselLayoutManager.setCarouselAlignment(CarouselLayoutManager.CENTER)
259259
```
260260

261261
By default, the focal alignment is start-aligned.
262-
263-
### Creating a custom strategy
264-
265-
You can create a custom Carousel strategy by extending the `CarouselStrategy`
266-
class, and overriding the `onFirstChildMeasuredWithMargins` method. This method
267-
is called when the RecyclerView measures the first item to be added to its
268-
scroll container. This method must return a `KeylineState` which tells the
269-
Carousel how to fill the scroll container with items - how many are visible at
270-
once, what their sizes are, and where they're placed.
271-
272-
This is done by using the `KeylineState.Builder` to add "keylines", which
273-
represent items that will be shown. For example, if there are 3 non-anchor
274-
keylines, 3 items will be shown in the carousel. As the items move through the
275-
carousel, each item will be the exact size specified by each keyline when they
276-
are directly at the center of the keyline.
277-
278-
Note that anchor keylines are used to control how small items become as they
279-
reach the edge of the carousel, and must always be added to denote the start and
280-
ends of the keyline strategy. Smaller anchor keyline sizes will result in items
281-
looking 'squeezed' to the edges of the carousel, whereas bigger anchor sizes
282-
will make it look like there's no size change as it goes off-screen.
283-
284-
Keylines must always follow rule patterns:
285-
286-
- Anchor keylines must always be smaller than any other keyline (it wouldn't
287-
make sense for an item to get bigger as it goes off-screen)
288-
- Anchor keylines must always be off-screen; typically, the left anchor's
289-
center is located at `-(anchorSize)/2` and the right anchor's center is
290-
located at `availableSpace + anchorSize/2`
291-
- The biggest keyline must be focal keylines; these are items that are fully
292-
unmasked
293-
- Focal keylines must be grouped together, and there must be at least one
294-
focal keyline
295-
- Non-anchor keylines must be in ascending size order up to the focal
296-
keyline(s), and in descending order after the focal keyline(s)
297-
- All non-anchor keyline sizes must add up to the available space in the
298-
carousel
299-
300-
For example, if you want the following strategy structure:
301-
302-
![A custom Carousel](assets/carousel/custom.png)
303-
304-
Then you can define it with a `KeylineState` like below in your custom Strategy.
305-
The `KeylineState` returned by `onFirstChildMeasuredWithMargins` should always
306-
be the 'default' `KeylineState`, meaning the `KeylineState` with no altered
307-
behavior. The `CarouselLayoutManager` will take care of special behavior at the
308-
front and ends of the RecyclerView by taking the default `KeylineState` given
309-
and altering them.
310-
311-
```kt
312-
override fun onFirstChildMeasuredWithMargins(
313-
carousel: Carousel,
314-
child: View,
315-
): KeylineState? {
316-
val availableSpace = if (carousel.isHorizontal()) carousel.containerWidth else carousel.containerHeight
317-
val focalItemSize = 200f
318-
val mediumItemSize = 160f
319-
val smallItemSize = 80f
320-
val anchorSize = 50f // the anchor size determines how small items become as they reach the edge of the carousel
321-
val childLayoutParams = child.layoutParams as LayoutParams
322-
val childMargins = (childLayoutParams.leftMargin + childLayoutParams.rightMargin).toFloat() // this will be top and bottom margins for vertical strategies
323-
val anchorMaskSize = CarouselStrategy.getChildMaskPercentage(
324-
anchorSize,
325-
focalItemSize,
326-
childMargins
327-
)
328-
val mediumMaskSize = CarouselStrategy.getChildMaskPercentage(
329-
mediumItemSize,
330-
focalItemSize,
331-
childMargins
332-
)
333-
val smallMaskSize = CarouselStrategy.getChildMaskPercentage(
334-
smallItemSize,
335-
focalItemSize,
336-
childMargins
337-
)
338-
val leftAnchorCenterX = -anchorSize / 2f // the anchor keyline
339-
val rightAnchorCenterX = availableSpace + anchorSize / 2f
340-
return
341-
KeylineState.Builder(/* itemSize= */ focalItemSize, /* availableSpace= */ availableSpace)
342-
.addAnchorKeyline(/* offsetLoc= */ leftAnchorCenterX, /* mask= */ anchorMaskSize, /* maskedItemSize= */ anchorSize)
343-
.addKeyline(/* offsetLoc= */ focalItemSize / 2f, /* mask= */ 0, /* maskedItemSize= */ focalItemSize, /* isFocal= */ true)
344-
.addKeyline(/* offsetLoc= */ focalItemSize + mediumItemSize / 2f, /* mask= */ mediumMaskSize, /* maskedItemSize= */ mediumItemSize)
345-
.addKeyline(/* offsetLoc= */ focalItemSize + mediumItemSize + smallItemSize / 2f, /* mask= */ smallMaskSize, /* maskedItemSize= * smallItemSize)
346-
.addAnchorKeyline(/* offsetLoc= */ rightAnchorCenterX, /* mask= */ anchorMaskSize, /* maskedItemSize= */ anchorSize)
347-
.build()
348-
}
349-
```
350-
351-
You may also use the helper class `Arrangement` and the helper method
352-
`Arrangement.findLowestCostArrangement` to calculate the best suited arrangement
353-
for the given available space, and the given desired number of items along with
354-
their desired sizes. `Arrangement.findLowestCostArrangement` will give you an
355-
arrangement of items and sizes that will fit within the available space. This is
356-
encouraged unless you're doing some custom calculations with the available
357-
carousel size to determine an exact size for all of the keylines.
-8.25 KB
Binary file not shown.

lib/java/com/google/android/material/carousel/Arrangement.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@
2121

2222
import androidx.annotation.NonNull;
2323
import androidx.annotation.Nullable;
24+
import androidx.annotation.RestrictTo;
25+
import androidx.annotation.RestrictTo.Scope;
2426
import androidx.core.math.MathUtils;
2527

2628
/**
2729
* A class that holds data about a combination of large, medium, and small items, knows how to alter
2830
* an arrangement to fit within an available space, and can assess the arrangement's
2931
* desirability according to a priority heuristic.
3032
*/
33+
@RestrictTo(Scope.LIBRARY_GROUP)
3134
public final class Arrangement {
3235

3336
// Specifies a percentage of a medium item's size by which it can be increased or decreased to

lib/java/com/google/android/material/carousel/Carousel.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616

1717
package com.google.android.material.carousel;
1818

19+
import androidx.annotation.RestrictTo;
20+
import androidx.annotation.RestrictTo.Scope;
1921
import com.google.android.material.carousel.CarouselLayoutManager.Alignment;
2022

2123
/** An interface that defines a widget that can be configured as a Carousel. */
24+
@RestrictTo(Scope.LIBRARY_GROUP)
2225
public interface Carousel {
2326

2427
/** Gets the width of the carousel container. */

lib/java/com/google/android/material/carousel/CarouselStrategy.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import android.view.View;
2121
import androidx.annotation.FloatRange;
2222
import androidx.annotation.NonNull;
23+
import androidx.annotation.RestrictTo;
24+
import androidx.annotation.RestrictTo.Scope;
2325

2426
/**
2527
* A class responsible for creating a model used by a carousel to mask and offset views as they move
@@ -104,6 +106,7 @@ void initialize(Context context) {
104106
* along the scrolling axis.
105107
*/
106108
@NonNull
109+
@RestrictTo(Scope.LIBRARY_GROUP)
107110
public abstract KeylineState onFirstChildMeasuredWithMargins(
108111
@NonNull Carousel carousel, @NonNull View child);
109112

@@ -161,6 +164,7 @@ StrategyType getStrategyType() {
161164
*
162165
* @return true if the keylines should be refreshed.
163166
*/
167+
@RestrictTo(Scope.LIBRARY_GROUP)
164168
public boolean shouldRefreshKeylineState(@NonNull Carousel carousel, int oldItemCount) {
165169
// TODO: b/301332183 - Update existing strategies with logic on when to refresh keyline
166170
// state based on item count.

lib/java/com/google/android/material/carousel/KeylineState.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import androidx.annotation.FloatRange;
2323
import androidx.annotation.NonNull;
2424
import androidx.annotation.Nullable;
25+
import androidx.annotation.RestrictTo;
26+
import androidx.annotation.RestrictTo.Scope;
2527
import com.google.android.material.animation.AnimationUtils;
2628
import com.google.errorprone.annotations.CanIgnoreReturnValue;
2729
import java.util.ArrayList;
@@ -49,6 +51,7 @@
4951
* focal keylines at the beginning of the scroll container, center-aligned strategies at the center
5052
* of the scroll container, etc.
5153
*/
54+
@RestrictTo(Scope.LIBRARY_GROUP)
5255
public final class KeylineState {
5356

5457
private final float itemSize;

lib/java/com/google/android/material/carousel/KeylineStateList.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import static java.lang.Math.min;
2121

2222
import androidx.annotation.NonNull;
23+
import androidx.annotation.RestrictTo;
24+
import androidx.annotation.RestrictTo.Scope;
2325
import androidx.core.math.MathUtils;
2426
import com.google.android.material.animation.AnimationUtils;
2527
import com.google.android.material.carousel.KeylineState.Keyline;
@@ -43,6 +45,7 @@
4345
* handle reversing a KeylineState when being laid out right-to-left before constructing a
4446
* KeylineStateList.
4547
*/
48+
@RestrictTo(Scope.LIBRARY_GROUP)
4649
public class KeylineStateList {
4750

4851
private static final int NO_INDEX = -1;

0 commit comments

Comments
 (0)