Sha*_*ikh 15 markdown android textview
有没有办法启用TextView
检测降价标记并相应地呈现文本?更具体地说,我的应用程序包含一个TextView
用户可以提供描述的应用程序,并且通常他们将使用markdown来格式化他们的描述.不幸的是,文本没有呈现,而是我们看到所有标签都写在了textview
.
textview中没有对markdown的继承支持,但是如果你只需要通过简单的"regexp"匹配来实现简单的markdown-lite实现,那么请参阅https://github.com/mofosyne/中的 "从项目根文件夹加载自述文件" instantReadmeApp会有所帮助.
请注意,这不会删除文本中的标记,只会对行进行不同的样式.根据您的应用,这可能是好事也可能是坏事.
哦,好的东西?它在原生文本视图中设置样式,因此文本仍可像普通文本一样进行选择.
特别是这一行:https://github.com/mofosyne/instantReadmeApp/blob/master/app/src/main/java/com/github/mofosyne/instantreadme/ReadMe.java#L137
稍微修改如下:private void updateMainDisplay(String text)
to private void style_psudomarkdown_TextView(String text, TextView textview_input)
,因此您可以对不同的文本视图使用相同的功能
```
/*
Text Styler
A crappy psudo markdown styler. Could do with a total revamp.
*/
/*
* Styling the textview for easier readability
* */
private void style_psudomarkdown_TextView(String text, TextView textview_input) {
//TextView mTextView = (TextView) findViewById(R.id.readme_info);
TextView mTextView = textview_input;
// Let's update the main display
// Needs to set as spannable otherwise http://stackoverflow.com/questions/16340681/fatal-exception-string-cant-be-cast-to-spannable
mTextView.setText(text, TextView.BufferType.SPANNABLE);
// Let's prettify it!
changeLineinView_TITLESTYLE(mTextView, "# ", 0xfff4585d, 2f); // Primary Header
changeLineinView(mTextView, "\n# ", 0xFFF4A158, 1.5f); // Secondary Header
changeLineinView(mTextView, "\n## ", 0xFFF4A158, 1.2f); // Secondary Header
changeLineinView(mTextView, "\n---", 0xFFF4A158, 1.2f); // Horizontal Rule
changeLineinView(mTextView, "\n>", 0xFF89e24d, 0.9f); // Block Quotes
changeLineinView(mTextView, "\n - ", 0xFFA74DE3, 1f); // Classic Markdown List
changeLineinView(mTextView, "\n- ", 0xFFA74DE3, 1f); // NonStandard List
//spanSetterInView(String startTarget, String endTarget, int typefaceStyle, String fontFamily,TextView tv, int colour, float size)
// Limitation of spanSetterInView. Well its not a regular expression... so can't exactly have * list, and *bold* at the same time.
spanSetterInView(mTextView, "\n```\n", "\n```\n", Typeface.BOLD, "monospace", 0xFF45c152, 0.8f, false); // fenced code Blocks ( endAtLineBreak=false since this is a multiline block operator)
spanSetterInView(mTextView, " **" , "** ", Typeface.BOLD, "", 0xFF89e24d, 1f, true); // Bolding
spanSetterInView(mTextView, " *" , "* ", Typeface.ITALIC, "", 0xFF4dd8e2, 1f, true); // Italic
spanSetterInView(mTextView, " ***" , "*** ", Typeface.BOLD_ITALIC, "", 0xFF4de25c, 1f, true); // Bold and Italic
spanSetterInView(mTextView, " `" , "` ", Typeface.BOLD, "monospace", 0xFF45c152, 0.8f, true); // inline code
spanSetterInView(mTextView, "\n " , "\n", Typeface.BOLD, "monospace", 0xFF45c152, 0.7f, true); // classic indented code
}
private void changeLineinView(TextView tv, String target, int colour, float size) {
String vString = (String) tv.getText().toString();
int startSpan = 0, endSpan = 0;
//Spannable spanRange = new SpannableString(vString);
Spannable spanRange = (Spannable) tv.getText();
while (true) {
startSpan = vString.indexOf(target, endSpan-1); // (!@#$%) I want to check a character behind in case it is a newline
endSpan = vString.indexOf("\n", startSpan+1); // But at the same time, I do not want to read the point found by startSpan. This is since startSpan may point to a initial newline.
ForegroundColorSpan foreColour = new ForegroundColorSpan(colour);
// Need a NEW span object every loop, else it just moves the span
// Fix: -1 in startSpan or endSpan, indicates that the indexOf has already searched the entire string with not valid match (Lack of endspan check, occoured because of the inclusion of endTarget, which added extra complications)
if ( (startSpan < 0) || ( endSpan < 0 ) ) break;// Need a NEW span object every loop, else it just moves the span
// Need to make sure that start range is always smaller than end range. (Solved! Refer to few lines above with (!@#$%) )
if (endSpan > startSpan) {
//endSpan = startSpan + target.length();
spanRange.setSpan(foreColour, startSpan, endSpan, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Also wannna bold the span too
spanRange.setSpan(new RelativeSizeSpan(size), startSpan, endSpan, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spanRange.setSpan(new StyleSpan(Typeface.BOLD), startSpan, endSpan, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
tv.setText(spanRange);
}
private void changeLineinView_TITLESTYLE(TextView tv, String target, int colour, float size) {
String vString = (String) tv.getText().toString();
int startSpan = 0, endSpan = 0;
//Spannable spanRange = new SpannableString(vString);
Spannable spanRange = (Spannable) tv.getText();
/*
* Had to do this, since there is something wrong with this overlapping the "##" detection routine
* Plus you only really need one title.
*/
//while (true) {
startSpan = vString.substring(0,target.length()).indexOf(target, endSpan-1); //substring(target.length()) since we only want the first line
endSpan = vString.indexOf("\n", startSpan+1);
ForegroundColorSpan foreColour = new ForegroundColorSpan(colour);
// Need a NEW span object every loop, else it just moves the span
/*
if (startSpan < 0)
break;
*/
if ( !(startSpan < 0) ) { // hacky I know, but its to cater to the case where there is no header text
// Need to make sure that start range is always smaller than end range.
if (endSpan > startSpan) {
//endSpan = startSpan + target.length();
spanRange.setSpan(foreColour, startSpan, endSpan, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Also wannna bold the span too
spanRange.setSpan(new RelativeSizeSpan(size), startSpan, endSpan, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spanRange.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), startSpan, endSpan, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
//}
tv.setText(spanRange);
}
private void spanSetterInView(TextView tv, String startTarget, String endTarget, int typefaceStyle, String fontFamily, int colour, float size, boolean endAtLineBreak) {
String vString = (String) tv.getText().toString();
int startSpan = 0, endSpan = 0;
//Spannable spanRange = new SpannableString(vString);
Spannable spanRange = (Spannable) tv.getText();
while (true) {
startSpan = vString.indexOf(startTarget, endSpan-1); // (!@#$%) I want to check a character behind in case it is a newline
endSpan = vString.indexOf(endTarget, startSpan+1+startTarget.length()); // But at the same time, I do not want to read the point found by startSpan. This is since startSpan may point to a initial newline. We also need to avoid the first patten matching a token from the second pattern.
// Since this is pretty powerful, we really want to avoid overmatching it, and limit any problems to a single line. Especially if people forget to type in the closing symbol (e.g. * in bold)
if (endAtLineBreak){
int endSpan_linebreak = vString.indexOf("\n", startSpan+1+startTarget.length());
if ( endSpan_linebreak < endSpan ) { endSpan = endSpan_linebreak; }
}
// Fix: -1 in startSpan or endSpan, indicates that the indexOf has already searched the entire string with not valid match (Lack of endspan check, occoured because of the inclusion of endTarget, which added extra complications)
if ( (startSpan < 0) || ( endSpan < 0 ) ) break;// Need a NEW span object every loop, else it just moves the span
// We want to also include the end "** " characters
endSpan += endTarget.length();
// If all is well, we shall set the styles and etc...
if (endSpan > startSpan) {// Need to make sure that start range is always smaller than end range. (Solved! Refer to few lines above with (!@#$%) )
spanRange.setSpan(new ForegroundColorSpan(colour), startSpan, endSpan, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spanRange.setSpan(new RelativeSizeSpan(size), startSpan, endSpan, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spanRange.setSpan(new StyleSpan(typefaceStyle), startSpan, endSpan, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Default to normal font family if settings is empty
if( !fontFamily.equals("") ) spanRange.setSpan(new TypefaceSpan(fontFamily), startSpan, endSpan, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
tv.setText(spanRange);
}
Run Code Online (Sandbox Code Playgroud)
```
上述实现最多只支持2个头文件(但您可以轻松修改regexp以支持2个以上的头文件).
它是一系列基于正则表达式的文本视图,由regexp的两个函数组成,它们始终匹配一行changeLineinView()
和changeLineinView_TITLESTYLE()
对于多行跨越spanSetterInView()
函数处理它.
只要你有一个不与任何其他语法冲突的正则表达式,就可以扩展它以适合你的目的.
这是受支持的语法.不能支持完全降价,因为这只是一个简单的hacky实现.但对于易于在手机键盘上打字的无褶皱显示器而言非常方便.
# H1 only in first line (Due to technical hacks used)
## H2 headers as usual
## Styling
Like: *italic* **bold** ***bold_italic***
## Classic List
- list item 1
- list item 2
## Nonstandard List Syntax
- list item 1
- list item 2
## Block Quotes
> Quoted stuff
## codes
here is inline `literal` codes. Must have space around it.
```
codeblocks
Good for ascii art
```
Or 4 space code indent like classic markdown.
Run Code Online (Sandbox Code Playgroud)
我知道您想将String
包含 Markdown 标记转换为CharSequence
可以在TextView
. 我知道的两个选项是:
我两个都用过,在我看来,第二个更好:不需要处理原生架构,更小的 APK,而且性能相当好(在我的情况下慢了 2 倍,已经足够了)
更新:找到了另一个选项(这是我现在正在使用的选项):
我从上周五开始关注这篇文章,并测试了这里建议的许多 Markdown 库 - 这个问题和这些答案基本上是我可以在网上找到的关于该主题的最佳来源。
其中两个最引起我的注意,MarkdownView和Markwon,但前者比后者更容易处理,因此我用它通过 Markdown 格式来支持Room 笔记应用程序(这是我的主要个人目标)。
如果你想有一个 Markdown 实时预览,你可以使用库本身提供的这个示例活动,除其他选项外,如果你需要调整你自己的活动,我建议你将以下代码添加到你的项目:
构建.gradle
implementation 'us.feras.mdv:markdownview:1.1.0'
Run Code Online (Sandbox Code Playgroud)
private MarkdownView markdownView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.markdownView = findViewById(R.id.markdownView);
this.udateMarkdownView();
}
private void updateMarkdownView() {
markdownView.loadMarkdown(note_content.getText().toString());
}
Run Code Online (Sandbox Code Playgroud)
在这里,您可以找到我在 GitHub 上提供的示例,除了库本身为我们提供的示例之外,您还可以在其中看到一个工作项目。
归档时间: |
|
查看次数: |
11004 次 |
最近记录: |