我正在尝试在 TextView 中显示带有和弦的歌词。为此,我需要在正文的特定部分上方放置字母或符号。到目前为止,我的想法是像这样子类化 ReplacementSpan:
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.text.style.ReplacementSpan;
public class ChordSpan extends ReplacementSpan {
String chord;
public ChordSpan(String chord) {
super();
this.chord = chord;
}
@Override
public void draw(Canvas canvas,
CharSequence text, int start, int end,
float x, int top, int y, int bottom,
Paint paint) {
FontMetricsInt fm = paint.getFontMetricsInt();
int space = fm.ascent-fm.descent+fm.leading;
canvas.drawText(text, start, end, x, y, paint);
canvas.drawText(chord, x, y+space, paint);
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end,
FontMetricsInt fm) {
return Math.round(paint.measureText(text, start, end));
}
}
这可以很好地将和弦符号放置在文本上方。但是,当我添加和弦时,我还没有找到调整行高的方法,所以和弦被绘制在 TextView 的前一行上。这段代码演示了我的意思:
package com.example.chordspan;
import android.os.Bundle;
import android.app.Activity;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.view.Gravity;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this.getBaseContext());
tv.setGravity(Gravity.CENTER_VERTICAL);
SpannableStringBuilder sb = new SpannableStringBuilder();
sb.append("The line above\n");
int start = sb.length();
sb.append("A line with chords\n");
sb.setSpan(new ChordSpan("C"), start, start+2,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
sb.setSpan(new ChordSpan("Am"), start+7, start+11,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
sb.append("The line below");
tv.setText(sb);
setContentView(tv);
}
}
您会看到和弦已对齐并正确绘制但与“上面的线”重叠。
有没有办法实现我想要的,即在绘制我的自定义 Span 时以某种方式调整线条的行高?我还没有找到 ReplacementSpan 子类的任何好的例子。
或者,我很乐意收到有关如何实现预期效果的其他建议。也许我在想一个完全错误的方向。
感谢您到目前为止的阅读以及提供的任何帮助!
最佳答案
在 Android 源代码中挖掘了一段时间之后,我想我找到了解决方案:ReplacementSpan 的 getSize 方法不应该只返回 Span 的宽度作为int 但也可以更改作为参数传递的 FontMetricsInt。
因此,使用以下代码,行间距可以按需要工作:
public int getSize(Paint paint, CharSequence text, int start, int end,
FontMetricsInt fm) {
if ( fm != null ) {
int space = paint.getFontMetricsInt(fm);
fm.ascent -= space;
fm.top -= space;
}
return Math.round(paint.measureText(text, start, end));
}
关于Android TextView : How to place text above specific position in line/Setting height for ReplacementScan subclass,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21032554/