我正试图在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);

}

}

您将看到和弦已对齐并正确绘制,但与“上面的线”重叠.

有没有办法实现我想要的,即在绘制我的自定义跨度时以某种方式调整线条的线条高度?我还没有找到任何有关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

来源: https://codeday.me/bug/20190831/1773634.html

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐