|
27 | 27 |
|
28 | 28 | public class XLyricsLineView extends View { |
29 | 29 |
|
| 30 | + private static Typeface sharedTypeface; |
| 31 | + private static final AccelerateDecelerateInterpolator sharedInterpolator = new AccelerateDecelerateInterpolator(); |
| 32 | + private static final Random sharedRandom = new Random(); |
| 33 | + private static LinearGradient sharedBrushShader; |
| 34 | + private static int lastActiveColor = -1; |
| 35 | + private static int lastFutureColor = -1; |
| 36 | + |
30 | 37 | public final TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); |
31 | 38 | private final Paint sparklePaint = new Paint(Paint.ANTI_ALIAS_FLAG); |
32 | | - private final AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator(); |
33 | | - private final Random random = new Random(); |
34 | 39 |
|
35 | 40 | protected StaticLayout staticLayout; |
36 | 41 | private LyricLine lyricLine; |
@@ -125,8 +130,11 @@ public XLyricsLineView(Context context, AttributeSet attrs) { |
125 | 130 | } |
126 | 131 |
|
127 | 132 | private void init() { |
128 | | - Typeface customFont = ResourcesCompat.getFont(getContext(), R.font.gsans_flex_full); |
129 | | - textPaint.setTypeface(Typeface.create(customFont, Typeface.BOLD)); |
| 133 | + if (sharedTypeface == null) { |
| 134 | + Typeface customFont = ResourcesCompat.getFont(getContext(), R.font.gsans_flex_full); |
| 135 | + sharedTypeface = Typeface.create(customFont, Typeface.BOLD); |
| 136 | + } |
| 137 | + textPaint.setTypeface(sharedTypeface); |
130 | 138 | textPaint.setFontFeatureSettings("'liga' 0, 'clig' 0"); |
131 | 139 | setClipToOutline(false); |
132 | 140 | setClickable(false); |
@@ -185,7 +193,11 @@ public int getDesiredHeight() { |
185 | 193 | } |
186 | 194 |
|
187 | 195 | public int getDesiredHeight(String text, int width) { |
188 | | - if (width <= 0) return 0; |
| 196 | + if (width <= 0 || text == null || text.isEmpty()) return 0; |
| 197 | + LayoutCache cache = this.layoutCache; |
| 198 | + if (cache != null && text.equals(cache.text) && width == cache.width && this.alignment == cache.alignment) { |
| 199 | + return cache.staticLayout.getHeight() + (int)(getExtraPadding() * 2); |
| 200 | + } |
189 | 201 | StaticLayout temp = StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, width) |
190 | 202 | .setAlignment(alignment) |
191 | 203 | .setIncludePad(true) |
@@ -527,10 +539,15 @@ public void setText(String text, int width) { |
527 | 539 | } |
528 | 540 |
|
529 | 541 | private void updateShader() { |
530 | | - brushShader = new LinearGradient(0, 0, GRADIENT_WIDTH, 0, |
531 | | - new int[]{activeColor, activeColor, futureColor, futureColor}, |
532 | | - new float[]{0f, 0.1f, 0.9f, 1f}, |
533 | | - Shader.TileMode.CLAMP); |
| 542 | + if (sharedBrushShader == null || activeColor != lastActiveColor || futureColor != lastFutureColor) { |
| 543 | + lastActiveColor = activeColor; |
| 544 | + lastFutureColor = futureColor; |
| 545 | + sharedBrushShader = new LinearGradient(0, 0, GRADIENT_WIDTH, 0, |
| 546 | + new int[]{activeColor, activeColor, futureColor, futureColor}, |
| 547 | + new float[]{0f, 0.1f, 0.9f, 1f}, |
| 548 | + Shader.TileMode.CLAMP); |
| 549 | + } |
| 550 | + brushShader = sharedBrushShader; |
534 | 551 | } |
535 | 552 |
|
536 | 553 | private float getGlobalXForOffset(int offset) { |
@@ -592,15 +609,15 @@ public void updateProgress(int progressMs, boolean snap) { |
592 | 609 | float gap = syl.startTime - lastEndTime; |
593 | 610 | if (gap > 0) { |
594 | 611 | float ratio = (float) (progressMs - lastEndTime) / gap; |
595 | | - globalX = lastLineEndGlobal + (sylGlobalStart - lastLineEndGlobal) * interpolator.getInterpolation(ratio); |
| 612 | + globalX = lastLineEndGlobal + (sylGlobalStart - lastLineEndGlobal) * sharedInterpolator.getInterpolation(ratio); |
596 | 613 | } else { |
597 | 614 | globalX = lastLineEndGlobal; |
598 | 615 | } |
599 | 616 | found = true; |
600 | 617 | break; |
601 | 618 | } else if (progressMs >= syl.startTime && progressMs <= syl.endTime) { |
602 | 619 | float ratio = (float) (progressMs - syl.startTime) / Math.max(1, syl.endTime - syl.startTime); |
603 | | - globalX = sylGlobalStart + ((sylGlobalEnd - sylGlobalStart) * interpolator.getInterpolation(ratio)); |
| 620 | + globalX = sylGlobalStart + ((sylGlobalEnd - sylGlobalStart) * sharedInterpolator.getInterpolation(ratio)); |
604 | 621 | found = true; |
605 | 622 | break; |
606 | 623 | } |
@@ -641,19 +658,19 @@ public void updateProgress(int progressMs, boolean snap) { |
641 | 658 | private void spawnSparkle(float headX, float topY, float bottomY) { |
642 | 659 | if (sparkles.size() > 45) return; |
643 | 660 | Sparkle s = new Sparkle(); |
644 | | - s.baseX = headX - (random.nextFloat() * spToPx(4f)); |
| 661 | + s.baseX = headX - (sharedRandom.nextFloat() * spToPx(4f)); |
645 | 662 | float h = bottomY - topY; |
646 | | - s.baseY = topY + (h * 0.125f) + (random.nextFloat() * (h * 0.75f)); |
647 | | - s.vx = (random.nextFloat() - 0.5f) * spToPx(8f); |
648 | | - s.vy = -(random.nextFloat() * spToPx(10f) + spToPx(4f)); |
649 | | - s.maxLife = 0.4f + random.nextFloat() * 0.6f; |
| 663 | + s.baseY = topY + (h * 0.125f) + (sharedRandom.nextFloat() * (h * 0.75f)); |
| 664 | + s.vx = (sharedRandom.nextFloat() - 0.5f) * spToPx(8f); |
| 665 | + s.vy = -(sharedRandom.nextFloat() * spToPx(10f) + spToPx(4f)); |
| 666 | + s.maxLife = 0.4f + sharedRandom.nextFloat() * 0.6f; |
650 | 667 | s.life = s.maxLife; |
651 | | - s.maxAlpha = 0.6f + random.nextFloat() * 0.4f; |
| 668 | + s.maxAlpha = 0.6f + sharedRandom.nextFloat() * 0.4f; |
652 | 669 | s.alpha = s.maxAlpha; |
653 | | - s.size = spToPx(0.8f + random.nextFloat() * 1.4f); |
654 | | - s.phase = random.nextFloat() * (float) Math.PI * 2f; |
655 | | - s.amplitude = spToPx(1.5f + random.nextFloat() * 1.5f); |
656 | | - s.frequency = 6f + random.nextFloat() * 8f; |
| 670 | + s.size = spToPx(0.8f + sharedRandom.nextFloat() * 1.4f); |
| 671 | + s.phase = sharedRandom.nextFloat() * (float) Math.PI * 2f; |
| 672 | + s.amplitude = spToPx(1.5f + sharedRandom.nextFloat() * 1.5f); |
| 673 | + s.frequency = 6f + sharedRandom.nextFloat() * 8f; |
657 | 674 | sparkles.add(s); |
658 | 675 | } |
659 | 676 |
|
@@ -824,8 +841,8 @@ protected void onDraw(Canvas canvas) { |
824 | 841 | float lineBottom = staticLayout.getLineBottom(currentLineIdx); |
825 | 842 |
|
826 | 843 | if (clampedLocalX > 0 && clampedLocalX < lineWidth) { |
827 | | - if (random.nextFloat() < 0.7f) { |
828 | | - int spawnCount = random.nextInt(2) + 1; |
| 844 | + if (sharedRandom.nextFloat() < 0.7f) { |
| 845 | + int spawnCount = sharedRandom.nextInt(2) + 1; |
829 | 846 | for(int k=0; k<spawnCount; k++) { |
830 | 847 | spawnSparkle(headX, lineTop + getExtraPadding(), lineBottom + getExtraPadding()); |
831 | 848 | } |
|
0 commit comments