mirror of
https://github.com/androidx/media.git
synced 2025-05-04 06:00:37 +08:00
Merge pull request #8943 from dlafayet:embeddedstyle2
PiperOrigin-RevId: 375484765
This commit is contained in:
parent
55f50e24eb
commit
69394e6fb5
@ -15,6 +15,10 @@
|
|||||||
* DRM:
|
* DRM:
|
||||||
* Don't restore offline keys before releasing them. In OEMCrypto v16+ keys
|
* Don't restore offline keys before releasing them. In OEMCrypto v16+ keys
|
||||||
must be released without restoring them first.
|
must be released without restoring them first.
|
||||||
|
* UI:
|
||||||
|
* Keep subtitle language features embedded (e.g. rubies & tate-chu-yoko)
|
||||||
|
in `Cue.text` even when `SubtitleView#setApplyEmbeddedStyles()` is
|
||||||
|
false.
|
||||||
|
|
||||||
### 2.14.0 (2021-05-13)
|
### 2.14.0 (2021-05-13)
|
||||||
|
|
||||||
|
@ -29,4 +29,4 @@ package com.google.android.exoplayer2.text.span;
|
|||||||
// NOTE: There's no Android layout support for this, so this span currently doesn't extend any
|
// NOTE: There's no Android layout support for this, so this span currently doesn't extend any
|
||||||
// styling superclasses (e.g. MetricAffectingSpan). The only way to render this styling is to
|
// styling superclasses (e.g. MetricAffectingSpan). The only way to render this styling is to
|
||||||
// extract the spans and do the layout manually.
|
// extract the spans and do the layout manually.
|
||||||
public final class HorizontalTextInVerticalContextSpan {}
|
public final class HorizontalTextInVerticalContextSpan implements LanguageFeatureSpan {}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 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.exoplayer2.text.span;
|
||||||
|
|
||||||
|
/** Marker interface for span classes that carry language features rather than style information. */
|
||||||
|
public interface LanguageFeatureSpan {}
|
@ -30,7 +30,7 @@ package com.google.android.exoplayer2.text.span;
|
|||||||
// extract the spans and do the layout manually.
|
// extract the spans and do the layout manually.
|
||||||
// TODO: Consider adding support for parenthetical text to be used when rendering doesn't support
|
// TODO: Consider adding support for parenthetical text to be used when rendering doesn't support
|
||||||
// rubies (e.g. HTML <rp> tag).
|
// rubies (e.g. HTML <rp> tag).
|
||||||
public final class RubySpan {
|
public final class RubySpan implements LanguageFeatureSpan {
|
||||||
|
|
||||||
/** The ruby text, i.e. the smaller explanatory characters. */
|
/** The ruby text, i.e. the smaller explanatory characters. */
|
||||||
public final String rubyText;
|
public final String rubyText;
|
||||||
|
@ -32,7 +32,7 @@ import java.lang.annotation.Retention;
|
|||||||
// NOTE: There's no Android layout support for text emphasis, so this span currently doesn't extend
|
// NOTE: There's no Android layout support for text emphasis, so this span currently doesn't extend
|
||||||
// any styling superclasses (e.g. MetricAffectingSpan). The only way to render this emphasis is to
|
// any styling superclasses (e.g. MetricAffectingSpan). The only way to render this emphasis is to
|
||||||
// extract the spans and do the layout manually.
|
// extract the spans and do the layout manually.
|
||||||
public final class TextEmphasisSpan {
|
public final class TextEmphasisSpan implements LanguageFeatureSpan {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The possible mark shapes that can be used.
|
* The possible mark shapes that can be used.
|
||||||
|
@ -21,10 +21,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.text.SpannableString;
|
|
||||||
import android.text.Spanned;
|
|
||||||
import android.text.style.AbsoluteSizeSpan;
|
|
||||||
import android.text.style.RelativeSizeSpan;
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -380,37 +376,13 @@ public final class SubtitleView extends FrameLayout implements TextOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Cue removeEmbeddedStyling(Cue cue) {
|
private Cue removeEmbeddedStyling(Cue cue) {
|
||||||
@Nullable CharSequence cueText = cue.text;
|
Cue.Builder strippedCue = cue.buildUpon();
|
||||||
if (!applyEmbeddedStyles) {
|
if (!applyEmbeddedStyles) {
|
||||||
Cue.Builder strippedCue =
|
SubtitleViewUtils.removeAllEmbeddedStyling(strippedCue);
|
||||||
cue.buildUpon().setTextSize(Cue.DIMEN_UNSET, Cue.TYPE_UNSET).clearWindowColor();
|
|
||||||
if (cueText != null) {
|
|
||||||
// Remove all spans, regardless of type.
|
|
||||||
strippedCue.setText(cueText.toString());
|
|
||||||
}
|
|
||||||
return strippedCue.build();
|
|
||||||
} else if (!applyEmbeddedFontSizes) {
|
} else if (!applyEmbeddedFontSizes) {
|
||||||
if (cueText == null) {
|
SubtitleViewUtils.removeEmbeddedFontSizes(strippedCue);
|
||||||
return cue;
|
|
||||||
}
|
|
||||||
Cue.Builder strippedCue = cue.buildUpon().setTextSize(Cue.DIMEN_UNSET, Cue.TYPE_UNSET);
|
|
||||||
if (cueText instanceof Spanned) {
|
|
||||||
SpannableString spannable = SpannableString.valueOf(cueText);
|
|
||||||
AbsoluteSizeSpan[] absSpans =
|
|
||||||
spannable.getSpans(0, spannable.length(), AbsoluteSizeSpan.class);
|
|
||||||
for (AbsoluteSizeSpan absSpan : absSpans) {
|
|
||||||
spannable.removeSpan(absSpan);
|
|
||||||
}
|
|
||||||
RelativeSizeSpan[] relSpans =
|
|
||||||
spannable.getSpans(0, spannable.length(), RelativeSizeSpan.class);
|
|
||||||
for (RelativeSizeSpan relSpan : relSpans) {
|
|
||||||
spannable.removeSpan(relSpan);
|
|
||||||
}
|
|
||||||
strippedCue.setText(spannable);
|
|
||||||
}
|
|
||||||
return strippedCue.build();
|
|
||||||
}
|
}
|
||||||
return cue;
|
return strippedCue.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,16 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.ui;
|
package com.google.android.exoplayer2.ui;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||||
|
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.text.style.AbsoluteSizeSpan;
|
||||||
|
import android.text.style.RelativeSizeSpan;
|
||||||
import com.google.android.exoplayer2.text.Cue;
|
import com.google.android.exoplayer2.text.Cue;
|
||||||
|
import com.google.android.exoplayer2.text.span.LanguageFeatureSpan;
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
|
||||||
/** Utility class for subtitle layout logic. */
|
/** Utility class for subtitle layout logic. */
|
||||||
/* package */ final class SubtitleViewUtils {
|
/* package */ final class SubtitleViewUtils {
|
||||||
@ -48,5 +57,50 @@ import com.google.android.exoplayer2.text.Cue;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Removes all styling information from {@code cue}. */
|
||||||
|
public static void removeAllEmbeddedStyling(Cue.Builder cue) {
|
||||||
|
cue.clearWindowColor();
|
||||||
|
if (cue.getText() instanceof Spanned) {
|
||||||
|
if (!(cue.getText() instanceof Spannable)) {
|
||||||
|
cue.setText(SpannableString.valueOf(cue.getText()));
|
||||||
|
}
|
||||||
|
removeSpansIf(
|
||||||
|
(Spannable) checkNotNull(cue.getText()), span -> !(span instanceof LanguageFeatureSpan));
|
||||||
|
}
|
||||||
|
removeEmbeddedFontSizes(cue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all font size information from {@code cue}.
|
||||||
|
*
|
||||||
|
* <p>This involves:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>Clearing {@link Cue.Builder#setTextSize(float, int)}.
|
||||||
|
* <li>Removing all {@link AbsoluteSizeSpan} and {@link RelativeSizeSpan} spans from {@link
|
||||||
|
* Cue#text}.
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public static void removeEmbeddedFontSizes(Cue.Builder cue) {
|
||||||
|
cue.setTextSize(Cue.DIMEN_UNSET, Cue.TYPE_UNSET);
|
||||||
|
if (cue.getText() instanceof Spanned) {
|
||||||
|
if (!(cue.getText() instanceof Spannable)) {
|
||||||
|
cue.setText(SpannableString.valueOf(cue.getText()));
|
||||||
|
}
|
||||||
|
removeSpansIf(
|
||||||
|
(Spannable) checkNotNull(cue.getText()),
|
||||||
|
span -> span instanceof AbsoluteSizeSpan || span instanceof RelativeSizeSpan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void removeSpansIf(Spannable spannable, Predicate<Object> removeFilter) {
|
||||||
|
Object[] spans = spannable.getSpans(0, spannable.length(), Object.class);
|
||||||
|
for (Object span : spans) {
|
||||||
|
if (removeFilter.apply(span)) {
|
||||||
|
spannable.removeSpan(span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private SubtitleViewUtils() {}
|
private SubtitleViewUtils() {}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 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.exoplayer2.ui;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.testutil.truth.SpannedSubject.assertThat;
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.text.Layout;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.text.style.AbsoluteSizeSpan;
|
||||||
|
import android.text.style.RelativeSizeSpan;
|
||||||
|
import android.text.style.UnderlineSpan;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import com.google.android.exoplayer2.text.Cue;
|
||||||
|
import com.google.android.exoplayer2.text.span.HorizontalTextInVerticalContextSpan;
|
||||||
|
import com.google.android.exoplayer2.text.span.RubySpan;
|
||||||
|
import com.google.android.exoplayer2.text.span.TextAnnotation;
|
||||||
|
import com.google.android.exoplayer2.text.span.TextEmphasisSpan;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
/** Tests for {@link SubtitleView}. */
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class SubtitleViewUtilsTest {
|
||||||
|
|
||||||
|
private static final Cue CUE = buildCue();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveAllEmbeddedStyling() {
|
||||||
|
Cue.Builder cueBuilder = CUE.buildUpon();
|
||||||
|
SubtitleViewUtils.removeAllEmbeddedStyling(cueBuilder);
|
||||||
|
Cue strippedCue = cueBuilder.build();
|
||||||
|
|
||||||
|
Spanned originalText = (Spanned) CUE.text;
|
||||||
|
Spanned strippedText = (Spanned) strippedCue.text;
|
||||||
|
|
||||||
|
// Assert all non styling properties and spans are kept
|
||||||
|
assertThat(strippedCue.textAlignment).isEqualTo(CUE.textAlignment);
|
||||||
|
assertThat(strippedCue.multiRowAlignment).isEqualTo(CUE.multiRowAlignment);
|
||||||
|
assertThat(strippedCue.line).isEqualTo(CUE.line);
|
||||||
|
assertThat(strippedCue.lineType).isEqualTo(CUE.lineType);
|
||||||
|
assertThat(strippedCue.position).isEqualTo(CUE.position);
|
||||||
|
assertThat(strippedCue.positionAnchor).isEqualTo(CUE.positionAnchor);
|
||||||
|
assertThat(strippedCue.textSize).isEqualTo(Cue.DIMEN_UNSET);
|
||||||
|
assertThat(strippedCue.textSizeType).isEqualTo(Cue.TYPE_UNSET);
|
||||||
|
assertThat(strippedCue.size).isEqualTo(CUE.size);
|
||||||
|
assertThat(strippedCue.verticalType).isEqualTo(CUE.verticalType);
|
||||||
|
assertThat(strippedCue.shearDegrees).isEqualTo(CUE.shearDegrees);
|
||||||
|
TextEmphasisSpan expectedTextEmphasisSpan =
|
||||||
|
originalText.getSpans(0, originalText.length(), TextEmphasisSpan.class)[0];
|
||||||
|
assertThat(strippedText)
|
||||||
|
.hasTextEmphasisSpanBetween(
|
||||||
|
originalText.getSpanStart(expectedTextEmphasisSpan),
|
||||||
|
originalText.getSpanEnd(expectedTextEmphasisSpan));
|
||||||
|
RubySpan expectedRubySpan = originalText.getSpans(0, originalText.length(), RubySpan.class)[0];
|
||||||
|
assertThat(strippedText)
|
||||||
|
.hasRubySpanBetween(
|
||||||
|
originalText.getSpanStart(expectedRubySpan), originalText.getSpanEnd(expectedRubySpan));
|
||||||
|
HorizontalTextInVerticalContextSpan expectedHorizontalTextInVerticalContextSpan =
|
||||||
|
originalText
|
||||||
|
.getSpans(0, originalText.length(), HorizontalTextInVerticalContextSpan.class)[0];
|
||||||
|
assertThat(strippedText)
|
||||||
|
.hasHorizontalTextInVerticalContextSpanBetween(
|
||||||
|
originalText.getSpanStart(expectedHorizontalTextInVerticalContextSpan),
|
||||||
|
originalText.getSpanEnd(expectedHorizontalTextInVerticalContextSpan));
|
||||||
|
|
||||||
|
// Assert all styling properties and spans are removed
|
||||||
|
assertThat(strippedCue.windowColorSet).isFalse();
|
||||||
|
assertThat(strippedText).hasNoUnderlineSpanBetween(0, strippedText.length());
|
||||||
|
assertThat(strippedText).hasNoRelativeSizeSpanBetween(0, strippedText.length());
|
||||||
|
assertThat(strippedText).hasNoAbsoluteSizeSpanBetween(0, strippedText.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveEmbeddedFontSizes() {
|
||||||
|
Cue.Builder cueBuilder = CUE.buildUpon();
|
||||||
|
SubtitleViewUtils.removeEmbeddedFontSizes(cueBuilder);
|
||||||
|
Cue strippedCue = cueBuilder.build();
|
||||||
|
|
||||||
|
Spanned originalText = (Spanned) CUE.text;
|
||||||
|
Spanned strippedText = (Spanned) strippedCue.text;
|
||||||
|
|
||||||
|
// Assert all non text-size properties and spans are kept
|
||||||
|
assertThat(strippedCue.textAlignment).isEqualTo(CUE.textAlignment);
|
||||||
|
assertThat(strippedCue.multiRowAlignment).isEqualTo(CUE.multiRowAlignment);
|
||||||
|
assertThat(strippedCue.line).isEqualTo(CUE.line);
|
||||||
|
assertThat(strippedCue.lineType).isEqualTo(CUE.lineType);
|
||||||
|
assertThat(strippedCue.position).isEqualTo(CUE.position);
|
||||||
|
assertThat(strippedCue.positionAnchor).isEqualTo(CUE.positionAnchor);
|
||||||
|
assertThat(strippedCue.size).isEqualTo(CUE.size);
|
||||||
|
assertThat(strippedCue.windowColor).isEqualTo(CUE.windowColor);
|
||||||
|
assertThat(strippedCue.windowColorSet).isEqualTo(CUE.windowColorSet);
|
||||||
|
assertThat(strippedCue.verticalType).isEqualTo(CUE.verticalType);
|
||||||
|
assertThat(strippedCue.shearDegrees).isEqualTo(CUE.shearDegrees);
|
||||||
|
TextEmphasisSpan expectedTextEmphasisSpan =
|
||||||
|
originalText.getSpans(0, originalText.length(), TextEmphasisSpan.class)[0];
|
||||||
|
assertThat(strippedText)
|
||||||
|
.hasTextEmphasisSpanBetween(
|
||||||
|
originalText.getSpanStart(expectedTextEmphasisSpan),
|
||||||
|
originalText.getSpanEnd(expectedTextEmphasisSpan));
|
||||||
|
RubySpan expectedRubySpan = originalText.getSpans(0, originalText.length(), RubySpan.class)[0];
|
||||||
|
assertThat(strippedText)
|
||||||
|
.hasRubySpanBetween(
|
||||||
|
originalText.getSpanStart(expectedRubySpan), originalText.getSpanEnd(expectedRubySpan));
|
||||||
|
HorizontalTextInVerticalContextSpan expectedHorizontalTextInVerticalContextSpan =
|
||||||
|
originalText
|
||||||
|
.getSpans(0, originalText.length(), HorizontalTextInVerticalContextSpan.class)[0];
|
||||||
|
assertThat(strippedText)
|
||||||
|
.hasHorizontalTextInVerticalContextSpanBetween(
|
||||||
|
originalText.getSpanStart(expectedHorizontalTextInVerticalContextSpan),
|
||||||
|
originalText.getSpanEnd(expectedHorizontalTextInVerticalContextSpan));
|
||||||
|
UnderlineSpan expectedUnderlineSpan =
|
||||||
|
originalText.getSpans(0, originalText.length(), UnderlineSpan.class)[0];
|
||||||
|
assertThat(strippedText)
|
||||||
|
.hasUnderlineSpanBetween(
|
||||||
|
originalText.getSpanStart(expectedUnderlineSpan),
|
||||||
|
originalText.getSpanEnd(expectedUnderlineSpan));
|
||||||
|
|
||||||
|
// Assert the text-size properties and spans are removed
|
||||||
|
assertThat(strippedCue.textSize).isEqualTo(Cue.DIMEN_UNSET);
|
||||||
|
assertThat(strippedCue.textSizeType).isEqualTo(Cue.TYPE_UNSET);
|
||||||
|
assertThat(strippedText).hasNoRelativeSizeSpanBetween(0, strippedText.length());
|
||||||
|
assertThat(strippedText).hasNoAbsoluteSizeSpanBetween(0, strippedText.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Cue buildCue() {
|
||||||
|
SpannableString spanned =
|
||||||
|
new SpannableString("TextEmphasis おはよ Ruby ございます 123 Underline RelativeSize AbsoluteSize");
|
||||||
|
spanned.setSpan(
|
||||||
|
new TextEmphasisSpan(
|
||||||
|
TextEmphasisSpan.MARK_SHAPE_CIRCLE,
|
||||||
|
TextEmphasisSpan.MARK_FILL_FILLED,
|
||||||
|
TextAnnotation.POSITION_BEFORE),
|
||||||
|
"Text emphasis ".length(),
|
||||||
|
"Text emphasis おはよ".length(),
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
spanned.setSpan(
|
||||||
|
new RubySpan("おはよ", TextAnnotation.POSITION_BEFORE),
|
||||||
|
"TextEmphasis おはよ Ruby ".length(),
|
||||||
|
"TextEmphasis おはよ Ruby ございます".length(),
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
spanned.setSpan(
|
||||||
|
new HorizontalTextInVerticalContextSpan(),
|
||||||
|
"TextEmphasis おはよ Ruby ございます ".length(),
|
||||||
|
"TextEmphasis おはよ Ruby ございます 123".length(),
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
spanned.setSpan(
|
||||||
|
new UnderlineSpan(),
|
||||||
|
"TextEmphasis おはよ Ruby ございます 123 ".length(),
|
||||||
|
"TextEmphasis おはよ Ruby ございます 123 Underline".length(),
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
spanned.setSpan(
|
||||||
|
new RelativeSizeSpan(1f),
|
||||||
|
"TextEmphasis おはよ Ruby ございます 123 Underline ".length(),
|
||||||
|
"TextEmphasis おはよ Ruby ございます 123 Underline RelativeSize".length(),
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
spanned.setSpan(
|
||||||
|
new AbsoluteSizeSpan(10),
|
||||||
|
"TextEmphasis おはよ Ruby ございます 123 Underline RelativeSize ".length(),
|
||||||
|
"TextEmphasis おはよ Ruby ございます 123 Underline RelativeSize AbsoluteSize".length(),
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
return new Cue.Builder()
|
||||||
|
.setText(spanned)
|
||||||
|
.setTextAlignment(Layout.Alignment.ALIGN_CENTER)
|
||||||
|
.setMultiRowAlignment(Layout.Alignment.ALIGN_NORMAL)
|
||||||
|
.setLine(5, Cue.LINE_TYPE_NUMBER)
|
||||||
|
.setLineAnchor(Cue.ANCHOR_TYPE_END)
|
||||||
|
.setPosition(0.4f)
|
||||||
|
.setPositionAnchor(Cue.ANCHOR_TYPE_MIDDLE)
|
||||||
|
.setTextSize(0.2f, Cue.TEXT_SIZE_TYPE_FRACTIONAL)
|
||||||
|
.setSize(0.8f)
|
||||||
|
.setWindowColor(Color.CYAN)
|
||||||
|
.setVerticalType(Cue.VERTICAL_TYPE_RL)
|
||||||
|
.setShearDegrees(-15f)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user