<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.markup.tutorial" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="15" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:label="@string/title_activity_main"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".AnotherActivity" android:exported="false"> <intent-filter> <data android:scheme="activity-run" android:host="AnotherActivityHost" /> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest>
package com.example.markup.tutorial; import org.xml.sax.XMLReader; import android.os.Bundle; import android.app.Activity; import android.graphics.drawable.Drawable; import android.text.Editable; import android.text.Html; import android.text.Spannable; import android.text.Spanned; import android.text.method.LinkMovementMethod; import android.widget.TextView; public class MainActivity extends Activity { TextView tvContent; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvContent = (TextView)findViewById(R.id.tvContent); tvContent.setLinksClickable(true); tvContent.setMovementMethod(new LinkMovementMethod()); setArticle("article_main"); } void setArticle(String strArticleResId) { int articleResId = getResources().getIdentifier(strArticleResId, "string", getPackageName()); String text = getString(articleResId); if (text == null) text = "Article not found"; Spanned spannedText = Html.fromHtml(text, htmlImageGetter, htmlTagHandler); Spannable reversedText = revertSpanned(spannedText); tvContent.setText(reversedText); } final Spannable revertSpanned(Spanned stext) { Object[] spans = stext.getSpans(0, stext.length(), Object.class); Spannable ret = Spannable.Factory.getInstance().newSpannable(stext.toString()); if (spans != null && spans.length > 0) { for(int i = spans.length - 1; i >= 0; --i) { ret.setSpan(spans[i], stext.getSpanStart(spans[i]), stext.getSpanEnd(spans[i]), stext.getSpanFlags(spans[i])); } } return ret; } Html.ImageGetter htmlImageGetter = new Html.ImageGetter() { public Drawable getDrawable(String source) { int resId = getResources().getIdentifier(source, "drawable", getPackageName()); Drawable ret = MainActivity.this.getResources().getDrawable(resId); ret.setBounds(0, 0, ret.getIntrinsicWidth(), ret.getIntrinsicHeight()); return ret; } }; Html.TagHandler htmlTagHandler = new Html.TagHandler() { public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { Object span = null; if (tag.startsWith("article_")) span = new ArticleSpan(MainActivity.this, tag); else if ("title".equalsIgnoreCase(tag)) span = new AppearanceSpan(0xffff2020, AppearanceSpan.NONE, 20, true, true, false, false); else if (tag.startsWith("color_")) span = new ParameterizedSpan(tag.substring(6)); if (span != null) processSpan(opening, output, span); } }; void processSpan(boolean opening, Editable output, Object span) { int len = output.length(); if (opening) { output.setSpan(span, len, len, Spannable.SPAN_MARK_MARK); } else { Object[] objs = output.getSpans(0, len, span.getClass()); int where = len; if (objs.length > 0) { for(int i = objs.length - 1; i >= 0; --i) { if (output.getSpanFlags(objs[i]) == Spannable.SPAN_MARK_MARK) { where = output.getSpanStart(objs[i]); output.removeSpan(objs[i]); break; } } } if (where != len) { output.setSpan(span, where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } } }
package com.example.markup.tutorial; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.net.Uri; import android.os.Bundle; public class AnotherActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Uri uri = getIntent().getData(); String caption = uri.getQueryParameter("caption"); String text = uri.getQueryParameter("text"); new AlertDialog.Builder(this) .setTitle(caption) .setMessage(text) .setPositiveButton("OK", dioclOK) .setCancelable(false) .create().show(); } DialogInterface.OnClickListener dioclOK = new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); finish(); } }; }
package com.example.markup.tutorial; import android.text.TextPaint; import android.text.style.CharacterStyle; public class AppearanceSpan extends CharacterStyle { public static final int NONE = -1; final int color, bgColor, textSize; final boolean boldText, italicText, strikeThruText, underlineText; public AppearanceSpan(int color, int bgColor, int textSize, boolean boldText, boolean italicText, boolean strikeThruText, boolean underlineText) { this.color = color; this.bgColor = bgColor; this.textSize = textSize; this.boldText = boldText; this.italicText = italicText; this.strikeThruText = strikeThruText; this.underlineText = underlineText; } @Override public void updateDrawState(TextPaint tp) { if (color != NONE) tp.setColor(color); if (bgColor != NONE) tp.bgColor = bgColor; tp.setFakeBoldText(boldText); tp.setStrikeThruText(strikeThruText); if (textSize != NONE) tp.setTextSize(textSize); tp.setUnderlineText(underlineText); tp.setTextSkewX(italicText ? -0.25f : 0); } }
package com.example.markup.tutorial; import android.text.style.ClickableSpan; import android.view.View; public class ArticleSpan extends ClickableSpan { final MainActivity activity; final String articleId; public ArticleSpan(MainActivity activity, String articleId) { super(); this.activity = activity; this.articleId = articleId; } @Override public void onClick(View arg0) { activity.setArticle(articleId); } }
package com.example.markup.tutorial; import android.graphics.Color; import android.text.TextPaint; import android.text.style.CharacterStyle; public class ParameterizedSpan extends CharacterStyle { int color = 0; public ParameterizedSpan(String param) { try { color = Color.parseColor("#" + param); } catch(Exception ex) { } } @Override public void updateDrawState(TextPaint tp) { tp.setColor(color); } }
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ScrollView android:id="@+id/sv" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/tvContent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Content" /> </ScrollView> </RelativeLayout>
<resources> <string name="app_name">MarkupTutor</string> <string name="hello_world">Hello world!</string> <string name="menu_settings">Settings</string> <string name="title_activity_main">MainActivity</string> <string name="article_main" formatted="false"><![CDATA[ <title> </title><br/> <br/> <img src="res_pushkin_little"> <article_pushkin_stih>.. " "</article_pushkin_stih><br/> <img src="res_activity_little"> <a href="activity-run://AnotherActivityHost?caption=Another%20Activity&text=Hello%20from%20markup!"> Activity</a><br/> <br/> <color_ff00ff00> <color_ffff00ff> </color_ffff00ff>.</color_ff00ff00><br/> GIF-:<br/> <img src="res_alien_anim"> ]]></string> <string name="article_pushkin_stih" formatted="false"><![CDATA[ <br/><article_main> </article_main><br/><br/> <img src="res_pushkin" /><br/><br/> , ,<br/> <br/> , ,<br/> .<br/> ,<br/> - -<br/> ,<br/><br/> .<br/> , ,<br/> , ,<br/> , , .<br/> -, , .<br/> , , <br/> ,<br/> <br/> ,<br/> :<br/> -<br/> <br/> .<br/> ,<br/> , ,<br/> , <br/> !..<br/> , .<br/> ,<br/> .<br/> ?<br/> -<br/> (, )<br/> -<br/> ...<br/> , , ,<br/> .<br/> ]]></string> </resources>
<br/>
. public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvContent = (TextView)findViewById(R.id.tvContent); tvContent.setLinksClickable(true); tvContent.setMovementMethod(new LinkMovementMethod()); setArticle("article_main"); }
void setArticle(String strArticleResId) { int articleResId = getResources().getIdentifier(strArticleResId, "string", getPackageName()); String text = getString(articleResId); if (text == null) text = "Article not found"; Spanned spannedText = Html.fromHtml(text, htmlImageGetter, htmlTagHandler); Spannable reversedText = revertSpanned(spannedText); tvContent.setText(reversedText); }
final Spannable revertSpanned(Spanned stext) { Object[] spans = stext.getSpans(0, stext.length(), Object.class); Spannable ret = Spannable.Factory.getInstance().newSpannable(stext.toString()); if (spans != null && spans.length > 0) { for(int i = spans.length - 1; i >= 0; --i) { ret.setSpan(spans[i], stext.getSpanStart(spans[i]), stext.getSpanEnd(spans[i]), stext.getSpanFlags(spans[i])); } } return ret; }
Html.TagHandler htmlTagHandler = new Html.TagHandler() { public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { Object span = null; if (tag.startsWith("article_")) span = new ArticleSpan(MainActivity.this, tag); else if ("title".equalsIgnoreCase(tag)) span = new AppearanceSpan(0xffff2020, AppearanceSpan.NONE, 20, true, true, false, false); else if (tag.startsWith("color_")) span = new ParameterizedSpan(tag.substring(6)); if (span != null) processSpan(opening, output, span); } };
br
, p
, div
, em
, b
, strong
, cite
, dfn
, i
, big
, small
, font
, blockquote
, tt
, a
, u
, sup
, sub
, h1...h6
and img
. In case the tag is not identified, Html.TagHandler is called (if, of course, it is transferred to the call).<color_ffff0000></color_ffff0000>
. This is a rather limited and not very convenient way, but sometimes it’s better than this. void processSpan(boolean opening, Editable output, Object span) { int len = output.length(); if (opening) { output.setSpan(span, len, len, Spannable.SPAN_MARK_MARK); } else { Object[] objs = output.getSpans(0, len, span.getClass()); int where = len; if (objs.length > 0) { for(int i = objs.length - 1; i >= 0; --i) { if (output.getSpanFlags(objs[i]) == Spannable.SPAN_MARK_MARK) { where = output.getSpanStart(objs[i]); output.removeSpan(objs[i]); break; } } } if (where != len) { output.setSpan(span, where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } }
package com.example.markup.tutorial; import android.text.TextPaint; import android.text.style.CharacterStyle; public class AppearanceSpan extends CharacterStyle { public static final int NONE = -1; final int color, bgColor, textSize; final boolean boldText, italicText, strikeThruText, underlineText; public AppearanceSpan(int color, int bgColor, int textSize, boolean boldText, boolean italicText, boolean strikeThruText, boolean underlineText) { this.color = color; this.bgColor = bgColor; this.textSize = textSize; this.boldText = boldText; this.italicText = italicText; this.strikeThruText = strikeThruText; this.underlineText = underlineText; } @Override public void updateDrawState(TextPaint tp) { if (color != NONE) tp.setColor(color); if (bgColor != NONE) tp.bgColor = bgColor; tp.setFakeBoldText(boldText); tp.setStrikeThruText(strikeThruText); if (textSize != NONE) tp.setTextSize(textSize); tp.setUnderlineText(underlineText); tp.setTextSkewX(italicText ? -0.25f : 0); } }
package com.example.markup.tutorial; import android.text.style.ClickableSpan; import android.view.View; public class ArticleSpan extends ClickableSpan { final MainActivity activity; final String articleId; public ArticleSpan(MainActivity activity, String articleId) { super(); this.activity = activity; this.articleId = articleId; } @Override public void onClick(View arg0) { activity.setArticle(articleId); } }
if (tag.startsWith("article_")) span = new ArticleSpan(MainActivity.this, tag);
package com.example.markup.tutorial; import android.graphics.Color; import android.text.TextPaint; import android.text.style.CharacterStyle; public class ParameterizedSpan extends CharacterStyle { int color = 0; public ParameterizedSpan(String param) { try { color = Color.parseColor("#" + param); } catch(Exception ex) { } } @Override public void updateDrawState(TextPaint tp) { tp.setColor(color); } }
<a href...>
tag with the task of the scheme and the host, which are described in AndroidManifest.xml for the called Activity . <a href="activity-run://AnotherActivityHost?caption=Another%20Activity&text=Hello%20from%20markup!"> Activity</a>
Uri uri = getIntent().getData(); String caption = uri.getQueryParameter("caption"); String text = uri.getQueryParameter("text");
Source: https://habr.com/ru/post/166351/
All Articles