Хотя я вижу, что в Html.java API стиль и выравнивание текста должны использоваться с тегами <p>
, <div>
и т. Д. Я не могу заставить его работать с <p align="center">
или <p style="text-align: center">
и много других вариантов. Не имея возможности выполнить выравнивание текста по центру и другие стили, такие как размер шрифта, несколько граней шрифта из моих файлов ttf, цвет фона, я создал свой собственный htmlTextView на основе TextView, но с моим собственным классом tagHandler. Учитывая одно или два незначительных раздражения, большинство тегов в порядке, но мои собственные теги выравнивания, влево , в центре , вправо работают только в особых условиях (что я не понимаю), иначе. они не работают или сбивают приложение! Это моя ручка тега выравнивания. Он имеет ту же структуру, что и все другие обработчики пользовательских тегов, но на самом деле ведет себя странно! Основная форма моих обработчиков тегов одинакова, и не задумана мной ! Я нашел шаблон taghandler после многих часов поиска в Интернете. Я благодарен тому, кто это написал, но моя память и организационные способности таковы, что я не могу вспомнить, кто или где, поэтому, если вы узнаете этот код как свой, пожалуйста, дайте мне знать. Единственная ссылка (которая есть здесь) у меня есть в моем коде: stackoverflow : Android: Как использовать Html.TagHandler?
private void ProcessAlignment(Layout.Alignment align, boolean opening, Editable output) {
int len = output.length();
if (opening) {
output.setSpan(new AlignmentSpan.Standard(align), len, len, Spannable.SPAN_MARK_MARK);
} else {
Object obj = getLast(output, AlignmentSpan.Standard.class);
int where = output.getSpanStart(obj);
output.removeSpan(obj);
if (where != len) {
output.setSpan(new AlignmentSpan.Standard(align), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
Мне кажется, проблема в том, что конечный тег не подключается к правильному начальному тегу.
private Object getLast(Editable text, Class kind) {
Object[] objs = text.getSpans(0, text.length(), kind);
if (objs.length == 0) {
return null;
} else {
for (int i = objs.length - 1; i >= 0; --i) {
if (text.getSpanFlags(objs[i]) == Spannable.SPAN_MARK_MARK) {
return objs[i];
}
}
return null;
}
}
Это общий класс, и что-то не так. Самым большим компонентом является мое понимание! Возможно, кто-то может помочь мне лучше понять ...
public class htmlTextView extends AppCompatTextView {
static Typeface mLogo;
static Typeface mGAMZ;
static Typeface mChalk;
static Typeface mSouvenir;
int GS_PAINTFLAGS = FILTER_BITMAP_FLAG | ANTI_ALIAS_FLAG | SUBPIXEL_TEXT_FLAG | HINTING_ON;
public htmlTextView(Context context) {
super(context);
initialise();
}
public htmlTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initialise();
}
public htmlTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialise();
}
private void initialise() {
mLogo = Typeface.createFromAsset(theAssetManager, "fonts/logo.ttf");
mGAMZ = Typeface.createFromAsset(theAssetManager, "fonts/GAMZ One.ttf");
mChalk = Typeface.createFromAsset(theAssetManager, "fonts/swapfix.ttf");
mSouvenir = Typeface.createFromAsset(theAssetManager, "fonts/Souvenir Regular.ttf");
setPaintFlags(GS_PAINTFLAGS);
}
public void setDefaultTypefaceSouvenir() {
setTypeface(mSouvenir);
}
public void setDefaultTypefaceGAMZ() {
setTypeface(mGAMZ);
}
public void setDefaultTypefaceChalk() {
setTypeface(mChalk);
}
/*public myTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}*/
public void setHTML(String htmltext) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // Nougat API 24
setText(Html.fromHtml(htmltext, Html.FROM_HTML_MODE_LEGACY,
null, new TypefaceTagHandler()));
} else {
setText(Html.fromHtml(htmltext, null, new TypefaceTagHandler()));
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
@Override
public Bitmap getDrawingCache(boolean autoScale) {
return super.getDrawingCache(autoScale);
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
}
// /3099677/android-kak-ispolzovat-html-taghandler
private static class TypefaceTagHandler implements Html.TagHandler {
private void ProcessAlignment(Layout.Alignment align, boolean opening, Editable output) {
int len = output.length();
if (opening) {
output.setSpan(new AlignmentSpan.Standard(align), len, len, Spannable.SPAN_MARK_MARK);
} else {
Object obj = getLast(output, AlignmentSpan.Standard.class);
int where = output.getSpanStart(obj);
output.removeSpan(obj);
if (where != len) {
output.setSpan(new AlignmentSpan.Standard(align), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
private void ProcessTypefaceTag(Typeface tf, boolean opening, Editable output) {
int len = output.length();
if (opening) {
output.setSpan(new CustomTypefaceSpan("", tf), len, len,
Spannable.SPAN_MARK_MARK);
} else {
Object obj = getLast(output, CustomTypefaceSpan.class);
int where = output.getSpanStart(obj);
output.removeSpan(obj);
if (where != len) {
output.setSpan(new CustomTypefaceSpan("", tf), where, len,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
private void ProcessScaleTag(float scalefactor, boolean opening, Editable output) {
int len = output.length();
if (opening) {
output.setSpan(new RelativeSizeSpan(scalefactor), len, len,
Spannable.SPAN_MARK_MARK);
} else {
Object obj = getLast(output, RelativeSizeSpan.class);
int where = output.getSpanStart(obj);
output.removeSpan(obj);
if (where != len) {
output.setSpan(new RelativeSizeSpan(scalefactor), where, len,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
private void ProcessBox(int colour, boolean opening, Editable output) {
int len = output.length();
if (opening) {
output.setSpan(new BackgroundColorSpan(colour), len, len,
Spannable.SPAN_MARK_MARK);
} else {
Object obj = getLast(output, BackgroundColorSpan.class);
int where = output.getSpanStart(obj);
output.removeSpan(obj);
if (where != len) {
output.setSpan(new BackgroundColorSpan(colour), where, len,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
private void ProcessTextColour(int colour, boolean opening, Editable output) {
int len = output.length();
if (opening) {
output.setSpan(new ForegroundColorSpan(colour), len, len,
Spannable.SPAN_MARK_MARK);
} else {
Object obj = getLast(output, ForegroundColorSpan.class);
int where = output.getSpanStart(obj);
output.removeSpan(obj);
if (where != len) {
output.setSpan(new ForegroundColorSpan(colour), where, len,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
final HashMap<String, String> attributes = new HashMap<>();
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
String Attr = "";
//if (!opening) attributes.clear();
processAttributes(xmlReader);
if ("txt".equalsIgnoreCase(tag)) {
Attr = attributes.get("clr");
System.out.println("clr Attr: " + Attr + ", opening: " + opening);
if (Attr == null || Attr.isEmpty()
|| "black".equalsIgnoreCase(Attr)
|| Attr.charAt(0) == 'k') {
System.out.println("did black, opening: " + opening);
ProcessTextColour(parseColor("#000000"), opening, output);
} else {
if (Attr.equalsIgnoreCase("g")) {
ProcessTextColour(parseColor("#b2b3b3"), opening, output);
} else {
System.out.println("did colour, opening: " + opening);
ProcessTextColour(parseColor(Attr), opening, output);
}
}
return;
}
if ("box".equalsIgnoreCase(tag)) {
ProcessBox(parseColor("#d7d6d5"), opening, output);
return;
}
if ("scl".equalsIgnoreCase(tag)) {
Attr = attributes.get("fac");
System.out.println("scl Attr: " + Attr);
if (Attr != null && !Attr.isEmpty()) {
ProcessScaleTag(parseFloat(Attr), opening, output);
}
return;
}
if ("left".equalsIgnoreCase(tag)) {
ProcessAlignment(Layout.Alignment.ALIGN_NORMAL, opening, output);
return;
}
if ("centre".equalsIgnoreCase(tag)) {
ProcessAlignment(Layout.Alignment.ALIGN_CENTER, opening, output);
return;
}
if ("right".equalsIgnoreCase(tag)) {
ProcessAlignment(Layout.Alignment.ALIGN_OPPOSITE, opening, output);
return;
}
if ("logo".equalsIgnoreCase(tag)) {
ProcessTypefaceTag(mLogo, opening, output);
return;
}
if ("gamz".equalsIgnoreCase(tag)) {
ProcessTypefaceTag(mGAMZ, opening, output);
return;
}
if ("chalk".equalsIgnoreCase(tag)) {
System.out.println("chalk " + (opening ? "opening" : "closing"));
ProcessTypefaceTag(mChalk, opening, output);
return;
}
}
private Object getLast(Editable text, Class kind) {
Object[] objs = text.getSpans(0, text.length(), kind);
if (objs.length == 0) {
return null;
} else {
for (int i = objs.length - 1; i >= 0; --i) {
if (text.getSpanFlags(objs[i]) == Spannable.SPAN_MARK_MARK) {
return objs[i];
}
}
return null;
}
}
private void processAttributes(final XMLReader xmlReader) {
try {
Field elementField = xmlReader.getClass().getDeclaredField("theNewElement");
elementField.setAccessible(true);
Object element = elementField.get(xmlReader);
Field attsField = element.getClass().getDeclaredField("theAtts");
attsField.setAccessible(true);
Object atts = attsField.get(element);
Field dataField = atts.getClass().getDeclaredField("data");
dataField.setAccessible(true);
String[] data = (String[])dataField.get(atts);
Field lengthField = atts.getClass().getDeclaredField("length");
lengthField.setAccessible(true);
int len = (Integer)lengthField.get(atts);
/**
* MSH: Look for supported attributes and add to hash map.
* This is as tight as things can get :)
* The data index is "just" where the keys and values are stored.
*/
for(int i = 0; i < len; i++)
attributes.put(data[i * 5 + 1], data[i * 5 + 4]);
}
catch (Exception e) {
Log.d(TAG, "Exception: " + e);
}
}
}
private static class CustomTypefaceSpan extends TypefaceSpan {
private final Typeface newType;
public CustomTypefaceSpan(String family, Typeface type) {
super(family);
newType = type;
}
@Override
public void updateDrawState(TextPaint ds) {
applyCustomTypeFace(ds, newType);
}
@Override
public void updateMeasureState(TextPaint paint) {
applyCustomTypeFace(paint, newType);
}
private void applyCustomTypeFace(Paint paint, Typeface tf) {
int oldStyle;
Typeface old = paint.getTypeface();
if (old == null) {
oldStyle = 0;
} else {
oldStyle = old.getStyle();
}
int fake = oldStyle & ~tf.getStyle();
if ((fake & Typeface.BOLD) != 0) {
paint.setFakeBoldText(true);
}
if ((fake & Typeface.ITALIC) != 0) {
paint.setTextSkewX(-0.25f);
}
paint.setTypeface(tf);
}
}
}
htmlTextView создается из действия с:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
theAssetManager = getAssets();
htmlTextView tv = new htmlTextView(this);
tv.setDefaultTypefaceSouvenir();
tv.setTextColor(BLACK);
tv.setBackgroundColor(0xfff0f0f0);
tv.setPadding(4, 4, 4, 4);
tv.setTextSize(30);
tv.setMovementMethod(new ScrollingMovementMethod());
tv.setHTML(getString(R.string.htmljumblies));
//tv.setHTML(getString(R.string.htmltest));
RelativeLayout rl = (RelativeLayout) findViewById(R.id.rl);
rl.addView(tv);
}
и htmljumblies определены в strings.xml, как показано ниже. Эта конкретная версия приведет к сбою приложения, но если первые строки <centre>
, </centre>
будут удалены из строк 7 и 9, Jumblies будут отображаться централизованно? Смущает и расстраивает! Сохраните их и удалите теги <centre>
, </centre>
, содержащие Jumblies , и ничего не произойдет. Строка в заголовке не выровнена по центру!
<string name="htmljumblies">
<![CDATA[⟹<logo><scl fac="1.1"><font color="#e5053a">GAMZ</font></scl></logo>
<chalk><scl fac="1.8"> SWAP </scl></chalk>
<scl fac="1.00">Set <b>1</b>, Game <b>1</b></scl>
<br>
<centre>
<gamz><font color="#e5053a"><scl fac="1.50">a</scl></font><scl fac="0.90">(9)</scl></gamz>, <gamz><font color="#00a3dd"><scl fac="1.50">e</scl></font><scl fac="0.90">(8)</scl></gamz>, <gamz><font color="#fba311"><scl fac="1.50">i</scl></font><scl fac="0.90">(8)</scl></gamz>, <gamz><font color="#bc5e1e"><scl fac="1.50">o</scl></font><scl fac="0.90">(8)</scl></gamz>, <gamz><font color="#bf30b5"><scl fac="1.50">u</scl></font><scl fac="0.90">(9)</scl></gamz>
</centre>
<br>
This is an example of my custom <b>htmlTextView</b> drawn from HTML format
text with custom tags to use custom fonts, colouring typeface sizing and highlight boxes.
The default font is <b><i>Souvenir</i></b>, but 3 other fonts are used:<br>
The <font color="#e5053a"><b><logo><scl fac="1.1">GAMZ</scl></logo></b></font>
<font color="#000080"><gamz><scl fac="0.8"><box>letter</box>
<box>fonts</box><sc></gamz></font>
and <chalk><scl fac="1.8">swapfix</scl></chalk>, essentially
<chalk><scl fac="0.9">Staccato 555</scl></chalk>,
as used in the words <chalk><scl fac="1.2">SWAP</scl></chalk> and
<chalk><scl fac="1.2">FIX</scl></chalk>
on the <font color="#e5053a"><b><logo><scl fac="1.1">GAMZ</scl></logo></b></font>
boxes.
<br>
<centre>
<scl fac="2"><box><b> <u>The Jumblies</u> </b></box></scl><br>
<font color="#0000ff">
They went to sea in a Sieve, they did,<br>
In a Sieve they went to sea:<br>
In spite of all their friends could say,<br>
On a winter\'s morn, on a stormy day,<br>
In a Sieve they went to sea!<br>
And when the Sieve turned round and round,<br>
And every one cried, \'You\'ll all be drowned!\'<br>
They called aloud, \'Our Sieve ain\'t big,<br>
But we don\'t care a button! we don\'t care a fig!<br>
In a Sieve we\'ll go to sea!\'<br>
Far and few, far and few,<br>
Are the lands where the Jumblies live;<br>
Their heads are green, and their hands are blue,<br>
And they went to sea in a Sieve.<br>
<br>
They sailed away in a Sieve, they did,<br>
In a Sieve they sailed so fast,<br>
With only a beautiful pea-green veil<br>
Tied with a riband by way of a sail,<br>
To a small tobacco-pipe mast;<br>
And every one said, who saw them go,<br>
\'O won\'t they be soon upset, you know!<br>
For the sky is dark, and the voyage is long,<br>
And happen what may, it\'s extremely wrong<br>
In a Sieve to sail so fast!\'<br>
Far and few, far and few,<br>
Are the lands where the Jumblies live;<br>
Their heads are green, and their hands are blue,<br>
And they went to sea in a Sieve.<br>
<br>
The water it soon came in, it did,<br>
The water it soon came in;<br>
So to keep them dry, they wrapped their feet<br>
In a pinky paper all folded neat,<br>
And they fastened it down with a pin.<br>
And they passed the night in a crockery-jar,<br>
And each of them said, \'How wise we are!<br>
Though the sky be dark, and the voyage be long,<br>
Yet we never can think we were rash or wrong,<br>
While round in our Sieve we spin!\'<br>
Far and few, far and few,<br>
Are the lands where the Jumblies live;<br>
Their heads are green, and their hands are blue,<br>
And they went to sea in a Sieve.<br>
<br>
And all night long they sailed away;<br>
And when the sun went down,<br>
They whistled and warbled a moony song<br>
To the echoing sound of a coppery gong,<br>
In the shade of the mountains brown.<br>
\'O Timballo! How happy we are,<br>
When we live in a Sieve and a crockery-jar,<br>
And all night long in the moonlight pale,<br>
We sail away with a pea-green sail,<br>
In the shade of the mountains brown!\'<br>
Far and few, far and few,<br>
Are the lands where the Jumblies live;<br>
Their heads are green, and their hands are blue,<br>
And they went to sea in a Sieve.<br>
<br>
They sailed to the Western Sea, they did,<br>
To a land all covered with trees,<br>
And they bought an Owl, and a useful Cart,<br>
And a pound of Rice, and a Cranberry Tart,<br>
And a hive of silvery Bees.<br>
And they bought a Pig, and some green Jack-daws,<br>
And a lovely Monkey with lollipop paws,<br>
And forty bottles of Ring-Bo-Ree,<br>
And no end of Stilton Cheese.<br>
Far and few, far and few,<br>
Are the lands where the Jumblies live;<br>
Their heads are green, and their hands are blue,<br>
And they went to sea in a Sieve.<br>
<br>
And in twenty years they all came back,<br>
In twenty years or more,<br>
And every one said, \'How tall they\'ve grown!<br>
For they\'ve been to the Lakes, and the Torrible Zone,<br>
And the hills of the Chankly Bore!\'<br>
And they drank their health, and gave them a feast<br>
Of dumplings made of beautiful yeast;<br>
And every one said, \'If we only live,<br>
We too will go to sea in a Sieve,---<br>
To the hills of the Chankly Bore!\'<br>
Far and few, far and few,<br>
Are the lands where the Jumblies live;<br>
Their heads are green, and their hands are blue,<br>
And they went to sea in a Sieve.</centre></font>
]]>
</string>