我正在为论坛开发一个应用程序。
我需要像Tapatalk的那样获得一个剧透按钮
隐藏文本部分,仅在用户点击按钮时显示。
我收到了帖子的所有文字,包括剧透BBCode。我已设法通过以下正则表达式获取剧透的内容:
\[SPOILER\](.+?)\[\/SPOILER\]
我的问题是我想添加一个剧透按钮,但我的所有文本都是类似HTML的,因为每个对象(图像,链接,格式代码等等)都是用HTML翻译的,然后由Android处理方法 Html.fromHtml()。
这是解析方法,"翻译"将BBCode转换为HTML:
private static String parsePostContent(String text){
String html = text;
Map<String,String> bbMap = new HashMap<>();
bbMap.put("(\r\n|\r|\n|\n\r)", "<br/>");
bbMap.put("\\[b\\](.+?)\\[/b\\]", "<strong>$1</strong>");
bbMap.put("\\[i\\](.+?)\\[/i\\]", "<span style='font-style:italic;'>$1</span>");
bbMap.put("\\[u\\](.+?)\\[/u\\]", "<span style='text-decoration:underline;'>$1</span>");
bbMap.put("\\[h1\\](.+?)\\[/h1\\]", "<h1>$1</h1>");
bbMap.put("\\[h2\\](.+?)\\[/h2\\]", "<h2>$1</h2>");
bbMap.put("\\[h3\\](.+?)\\[/h3\\]", "<h3>$1</h3>");
bbMap.put("\\[h4\\](.+?)\\[/h4\\]", "<h4>$1</h4>");
bbMap.put("\\[h5\\](.+?)\\[/h5\\]", "<h5>$1</h5>");
bbMap.put("\\[h6\\](.+?)\\[/h6\\]", "<h6>$1</h6>");
bbMap.put("\\[quote\\](.+?)\\[/quote\\]", "<blockquote>$1</blockquote>");
bbMap.put("(?s)^\\[quote name=\"([^\"]+)\".*\\](.+)\\[\\/quote\\]", "<span style='font-style:italic;'>Citazione di: $1</span> <blockquote>$2</blockquote>");
bbMap.put("\\[p\\](.+?)\\[/p\\]", "<p>$1</p>");
bbMap.put("\\[p=(.+?),(.+?)\\](.+?)\\[/p\\]", "<p style='text-indent:$1px;line-height:$2%;'>$3</p>");
bbMap.put("\\[center\\](.+?)\\[/center\\]", "<div align='center'>$1");
bbMap.put("\\[align=(.+?)\\](.+?)\\[/align\\]", "<div align='$1'>$2");
bbMap.put("\\[color=(.+?)\\](.+?)\\[/color\\]", "<span style='color:$1;'>$2</span>");
bbMap.put("\\[size=(.+?)\\](.+?)\\[/size\\]", "<span style='font-size:$1;'>$2</span>");
bbMap.put("\\[img\\](.+?)\\[/img\\]", "<img src='$1' />");
bbMap.put("\\[img=(.+?),(.+?)\\](.+?)\\[/img\\]", "<img width='$1' height='$2' src='$3' />");
bbMap.put("\\[email\\](.+?)\\[/email\\]", "<a href='mailto:$1'>$1</a>");
bbMap.put("\\[email=(.+?)\\](.+?)\\[/email\\]", "<a href='mailto:$1'>$2</a>");
bbMap.put("\\[url\\](.+?)\\[/url\\]", "<a href='$1'>$1</a>");
bbMap.put("\\[url=(.+?)\\](.+?)\\[/url\\]", "<a href='$1'>$2</a>");
bbMap.put("\\[youtube\\](.+?)\\[/youtube\\]", "<object width='640' height='380'><param name='movie' value='http://www.youtube.com/v/$1'></param><embed src='http://www.youtube.com/v/$1' type='application/x-shockwave-flash' width='640' height='380'></embed></object>");
bbMap.put("\\[video\\](.+?)\\[/video\\]", "<video src='$1' />");
bbMap.put("\\[SPOILER\\](.+?)\\[\\/SPOILER\\]", "$1");
for (Map.Entry entry: bbMap.entrySet()) {
html = html.replaceAll(entry.getKey().toString(), entry.getValue().toString());
}
return html;
}
请注意,SPOILER行仅用于测试目的。
然后在Adapter类的TextView中设置字符串:
postText.setText(Html.fromHtml(post.getPostText()));
帖子有这样的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/postAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:text="New Text"
android:textStyle="bold" />
<TextView
android:id="@+id/postDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/postAuthor"
android:layout_alignStart="@+id/postAuthor"
android:layout_below="@+id/postAuthor"
android:layout_marginTop="5dp"
android:text="New Text"
android:textStyle="italic" />
<TextView
android:id="@+id/postText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/postDate"
android:layout_alignStart="@+id/postDate"
android:layout_below="@+id/postDate"
android:layout_marginBottom="15dp"
android:layout_marginTop="20dp"
android:autoLink="web"
android:linksClickable="true"
android:text="New Text" />
</RelativeLayout>
每个帖子对象都放在ListView中。
我的问题是:如何使用HTML或某种外部库创建类似的布局?
感谢。
答案 0 :(得分:0)
TextView
不支持<span>
,<object>
或<button>
标记。有unofficial list支持的代码。
对于[spoiler]
bbcode,您可以呈现两个TextViews
,一个带有,而一个没有扰流板。然后添加一个按钮以在两者之间切换。
JavaScript演示:
var spoilerVisible = false;
$('#toggleSpoiler').on('click', function () {
spoilerVisible = !spoilerVisible;
$('#textview1').toggle(!spoilerVisible);
$('#textview2').toggle(spoilerVisible);
$('#toggleSpoiler').text(spoilerVisible ? 'Hide spoiler' : 'Show spoiler');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="textview1">This is a test.</div>
<div id="textview2" style="display:none;">This is a test. Spoiled!</div>
<button id="toggleSpoiler">Show spoiler</button>
答案 1 :(得分:0)
经过几个小时,代码版本和一些诅咒,我设法得到了这个。这是最终的代码,但我认为它仍然需要更多的修复才能完美。 (如果用户将滚动到列表底部,则包含SPOILER按钮的帖子将消失。)
String[] textArray = postText.split("<spoiler>");
Spanned spoilerText;
String preSpoilerText = "";
String postSpoilerText = "";
List<String> noSpoilerTextList = new ArrayList<>();
for (int i = index - 1; i < textArray.length; i += 2) {
if (!textArray[i].equals("</p>")) {
String temp = textArray[i].replace("\n", "");
temp = temp.replace("[/SPOILER]", "");
if (!temp.equals("")) {
noSpoilerTextList.add(temp);
}
}
}
List<String> spoilerNameList = new ArrayList<>();
List<String> spoilerTextList = new ArrayList<>();
for (int i = index; i < textArray.length; i += 2) {
if (!textArray[i].contains("</p>") || !textArray[i].equals("")) {
String temp = textArray[i].replace("\n", "");
temp = temp.replace("[SPOILER]", "");
if (!temp.equals("")) {
if (temp.contains("<name>")) {
String[] spoilerTextArray = temp.split("<name>");
spoilerNameList.add(spoilerTextArray[1]);
spoilerTextList.add(spoilerTextArray[2]);
} else {
spoilerNameList.add("SPOILER");
spoilerTextList.add(temp);
}
}
}
}
if (noSpoilerTextList.size() == spoilerTextList.size()) {
noSpoilerTextList.add(new String(""));
}
for (int i = 0; i < spoilerTextList.size(); i++) {
int buttonHeight = 0;
float metrics = context.getResources().getDisplayMetrics().density;
if (metrics == 3.0) {
Log.i("DYSPLAYSIZE: ", "xxhdpi");
buttonHeight = 140;
} else if (metrics == 2.0) {
Log.i("DYSPLAYSIZE: ", "xhdpi");
buttonHeight = 120;
} else if (metrics == 1.5) {
Log.i("DYSPLAYSIZE: ", "hdpi");
buttonHeight = 100;
}
final TextView spoilerTextView = new TextView(context);
TextView preSpoilerTextView = new TextView(context);
TextView postSpoilerTextView = new TextView(context);
spoilerTextView.setLinksClickable(true);
preSpoilerTextView.setLinksClickable(true);
postSpoilerTextView.setLinksClickable(true);
spoilerTextView.setAutoLinkMask(Linkify.WEB_URLS);
preSpoilerTextView.setAutoLinkMask(Linkify.WEB_URLS);
postSpoilerTextView.setAutoLinkMask(Linkify.WEB_URLS);
Button spoilerButton = new Button(context);
spoilerButton.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, buttonHeight));
spoilerText = Html.fromHtml(spoilerTextList.get(i), new Html.ImageGetter() {
@Override
public Drawable getDrawable(String source) {
LevelListDrawable d = new LevelListDrawable();
Drawable empty = context.getResources().getDrawable(R.drawable.abc_ab_share_pack_mtrl_alpha);
d.addLevel(0, 0, empty);
d.setBounds(0, 0, empty.getIntrinsicWidth(), empty.getIntrinsicHeight());
new ImageGetterAsyncTask(context, source, d).execute(spoilerTextView);
return d;
}
}, null);
spoilerTextView.setText(spoilerText);
spoilerTextView.setTypeface(null, Typeface.ITALIC);
spoilerTextView.setVisibility(View.GONE);
LinearLayout.LayoutParams spoilerMargins = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
spoilerMargins.setMargins(50, 5, 15, 15);
final boolean[] visible = {false};
spoilerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!visible[0]) {
spoilerTextView.setVisibility(View.VISIBLE);
visible[0] = true;
} else {
spoilerTextView.setVisibility(View.GONE);
visible[0] = false;
}
}
});
if (index == 1) {
preSpoilerText = noSpoilerTextList.get(0);
postSpoilerText = noSpoilerTextList.get(1);
preSpoilerTextView.setText(Html.fromHtml(preSpoilerText));
postSpoilerTextView.setText(Html.fromHtml(postSpoilerText));
postContent.addView(preSpoilerTextView);
} else {
if (i != spoilerTextList.size() - 1) {
postSpoilerText = noSpoilerTextList.get(i + 1);
postSpoilerTextView.setText(Html.fromHtml(postSpoilerText));
} else {
if (spoilerTextList.size() != noSpoilerTextList.size()) {
postSpoilerText = noSpoilerTextList.get(i + 1);
} else {
postSpoilerText = noSpoilerTextList.get(i);
}
postSpoilerTextView.setText(Html.fromHtml(postSpoilerText));
}
}
spoilerButton.setText(spoilerNameList.get(i));
postContent.addView(spoilerButton);
postContent.addView(spoilerTextView, spoilerMargins);
postContent.addView(postSpoilerTextView);