diff --git a/lib/java/com/google/android/material/appbar/CollapsingToolbarLayout.java b/lib/java/com/google/android/material/appbar/CollapsingToolbarLayout.java index a4832cea1a5..05dcd6b670e 100644 --- a/lib/java/com/google/android/material/appbar/CollapsingToolbarLayout.java +++ b/lib/java/com/google/android/material/appbar/CollapsingToolbarLayout.java @@ -1398,6 +1398,24 @@ public int getHyphenationFrequency() { return collapsingTextHelper.getHyphenationFrequency(); } + /** + * Sets the {@link StaticLayoutBuilderConfigurer} for the {@link android.text.StaticLayout} of the + * title text. + * + *

Note that the updates to the {@link android.text.StaticLayout.Builder} in the configure + * method (e.g., the text, alignment, max lines, line spacing, etc.) will take precedence over and + * overwrite any previous configurations made by the {@link CollapsingToolbarLayout} to the same + * properties. + * + * @hide + */ + @RestrictTo(LIBRARY_GROUP) + @RequiresApi(VERSION_CODES.M) + public void setStaticLayoutBuilderConfigurer( + @Nullable StaticLayoutBuilderConfigurer staticLayoutBuilderConfigurer) { + collapsingTextHelper.setStaticLayoutBuilderConfigurer(staticLayoutBuilderConfigurer); + } + /** * Sets whether {@code TextDirectionHeuristics} should be used to determine whether the title text * is RTL. Experimental Feature. @@ -1732,4 +1750,15 @@ public void onOffsetChanged(AppBarLayout layout, int verticalOffset) { collapsingTextHelper.setExpansionFraction(Math.abs(verticalOffset) / (float) expandRange); } } + + /** + * Interface that allows for further customization of the provided {@link + * android.text.StaticLayout}. + * + * @hide + */ + @RestrictTo(LIBRARY_GROUP) + @RequiresApi(VERSION_CODES.M) + public interface StaticLayoutBuilderConfigurer + extends com.google.android.material.internal.StaticLayoutBuilderConfigurer {} } diff --git a/lib/java/com/google/android/material/internal/CollapsingTextHelper.java b/lib/java/com/google/android/material/internal/CollapsingTextHelper.java index a84e4d69dfd..b5d063804bd 100644 --- a/lib/java/com/google/android/material/internal/CollapsingTextHelper.java +++ b/lib/java/com/google/android/material/internal/CollapsingTextHelper.java @@ -176,6 +176,7 @@ public final class CollapsingTextHelper { private float lineSpacingAdd = StaticLayoutBuilderCompat.DEFAULT_LINE_SPACING_ADD; private float lineSpacingMultiplier = StaticLayoutBuilderCompat.DEFAULT_LINE_SPACING_MULTIPLIER; private int hyphenationFrequency = StaticLayoutBuilderCompat.DEFAULT_HYPHENATION_FREQUENCY; + @Nullable private StaticLayoutBuilderConfigurer staticLayoutBuilderConfigurer; public CollapsingTextHelper(View view) { this.view = view; @@ -1075,6 +1076,7 @@ private StaticLayout createStaticLayout(int maxLines, float availableWidth, bool .setMaxLines(maxLines) .setLineSpacing(lineSpacingAdd, lineSpacingMultiplier) .setHyphenationFrequency(hyphenationFrequency) + .setStaticLayoutBuilderConfigurer(staticLayoutBuilderConfigurer) .build(); } catch (StaticLayoutBuilderCompatException e) { Log.e(TAG, e.getCause().getMessage(), e); @@ -1220,6 +1222,15 @@ public int getHyphenationFrequency() { return hyphenationFrequency; } + @RequiresApi(VERSION_CODES.M) + public void setStaticLayoutBuilderConfigurer( + @Nullable StaticLayoutBuilderConfigurer staticLayoutBuilderConfigurer) { + if (this.staticLayoutBuilderConfigurer != staticLayoutBuilderConfigurer) { + this.staticLayoutBuilderConfigurer = staticLayoutBuilderConfigurer; + recalculate(/* forceRecalculate= */ true); + } + } + /** * Returns true if {@code value} is 'close' to it's closest decimal value. Close is currently * defined as it's difference being < 0.00001. diff --git a/lib/java/com/google/android/material/internal/StaticLayoutBuilderCompat.java b/lib/java/com/google/android/material/internal/StaticLayoutBuilderCompat.java index 62fc5a2c023..ad3d4156107 100644 --- a/lib/java/com/google/android/material/internal/StaticLayoutBuilderCompat.java +++ b/lib/java/com/google/android/material/internal/StaticLayoutBuilderCompat.java @@ -84,6 +84,7 @@ final class StaticLayoutBuilderCompat { private boolean includePad; private boolean isRtl; @Nullable private TextUtils.TruncateAt ellipsize; + @Nullable private StaticLayoutBuilderConfigurer staticLayoutBuilderConfigurer; private StaticLayoutBuilderCompat(CharSequence source, TextPaint paint, int width) { this.source = source; @@ -219,6 +220,17 @@ public StaticLayoutBuilderCompat setEllipsize(@Nullable TextUtils.TruncateAt ell return this; } + /** + * Set the {@link StaticLayoutBuilderConfigurer} which allows additional custom configurations on + * the static layout. + */ + @NonNull + public StaticLayoutBuilderCompat setStaticLayoutBuilderConfigurer( + @Nullable StaticLayoutBuilderConfigurer staticLayoutBuilderConfigurer) { + this.staticLayoutBuilderConfigurer = staticLayoutBuilderConfigurer; + return this; + } + /** A method that allows to create a StaticLayout with maxLines on all supported API levels. */ public StaticLayout build() throws StaticLayoutBuilderCompatException { if (source == null) { @@ -259,6 +271,9 @@ public StaticLayout build() throws StaticLayoutBuilderCompatException { if (maxLines > 1) { builder.setHyphenationFrequency(hyphenationFrequency); } + if (staticLayoutBuilderConfigurer != null) { + staticLayoutBuilderConfigurer.configure(builder); + } return builder.build(); } diff --git a/lib/java/com/google/android/material/internal/StaticLayoutBuilderConfigurer.java b/lib/java/com/google/android/material/internal/StaticLayoutBuilderConfigurer.java new file mode 100644 index 00000000000..e51e8b1e2dd --- /dev/null +++ b/lib/java/com/google/android/material/internal/StaticLayoutBuilderConfigurer.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.material.internal; + +import android.text.StaticLayout; +import androidx.annotation.NonNull; +import androidx.annotation.RestrictTo; +import androidx.annotation.RestrictTo.Scope; + +/** + * Interface that allows for further customization of the provided {@link + * android.text.StaticLayout}. + * + * @hide + */ +@RestrictTo(Scope.LIBRARY_GROUP) +public interface StaticLayoutBuilderConfigurer { + void configure(@NonNull StaticLayout.Builder builder); +}