一:资讯正文
开源中国和大部分新闻客户端一样,使用webview显示html的数据
首先看看是如何获取数据,这里是在initData实现的
// 初始化控件数据
private void initData() {
mHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 1) {
headButtonSwitch(DATA_LOAD_COMPLETE);
mTitle.setText(newsDetail.getTitle());
mAuthor.setText(newsDetail.getAuthor());
mPubDate.setText(StringUtils.friendly_time(newsDetail
.getPubDate()));
mCommentCount.setText(String.valueOf(newsDetail
.getCommentCount()));
// 是否收藏
if (newsDetail.getFavorite() == 1)
mFavorite
.setImageResource(R.drawable.widget_bar_favorite2);
else
mFavorite
.setImageResource(R.drawable.widget_bar_favorite);
// 显示评论数
if (newsDetail.getCommentCount() > 0) {
bv_comment.setText(newsDetail.getCommentCount() + "");
bv_comment.show();
} else {
bv_comment.setText("");
bv_comment.hide();
}
String body = UIHelper.WEB_STYLE + newsDetail.getBody();
// 读取用户设置:是否加载文章图片--默认有wifi下始终加载图片
boolean isLoadImage;
AppContext ac = (AppContext) getApplication();
if (AppContext.NETTYPE_WIFI == ac.getNetworkType()) {
isLoadImage = true;
} else {
isLoadImage = ac.isLoadImage();
}
if (isLoadImage) {
// 过滤掉 img标签的width,height属性
body = body.replaceAll(
"(<img[^>]*?)\\s+width\\s*=\\s*\\S+", "$1");
body = body.replaceAll(
"(<img[^>]*?)\\s+height\\s*=\\s*\\S+", "$1");
// 添加点击图片放大支持
body = body.replaceAll("(<img[^>]+src=\")(\\S+)\"",
"$1$2\" onClick=\"javascript:mWebViewImageListener.onImageClick('$2')\"");
} else {
// 过滤掉 img标签
body = body.replaceAll("<\\s*img\\s+([^>]*)\\s*>", "");
}
// 更多关于***软件的信息
String softwareName = newsDetail.getSoftwareName();
String softwareLink = newsDetail.getSoftwareLink();
if (!StringUtils.isEmpty(softwareName)
&& !StringUtils.isEmpty(softwareLink))
body += String
.format("<div id='oschina_software' style='margin-top:8px;color:#FF0000;font-weight:bold'>更多关于: <a href='%s'>%s</a> 的详细信息</div>",
softwareLink, softwareName);
// 相关新闻
if (newsDetail.getRelatives().size() > 0) {
String strRelative = "";
for (Relative relative : newsDetail.getRelatives()) {
strRelative += String
.format("<a href='%s' style='text-decoration:none'>%s</a><p/>",
relative.url, relative.title);
}
body += String.format(
"<p/><hr/><b>相关资讯</b><div><p/>%s</div>",
strRelative);
}
body += "<div style='margin-bottom: 80px'/>";
System.out.println(body);
mWebView.loadDataWithBaseURL(null, body, "text/html",
"utf-8", null);
mWebView.setWebViewClient(UIHelper.getWebViewClient());
// 发送通知广播
if (msg.obj != null) {
UIHelper.sendBroadCast(NewsDetail.this,
(Notice) msg.obj);
}
} else if (msg.what == 0) {
headButtonSwitch(DATA_LOAD_FAIL);
UIHelper.ToastMessage(NewsDetail.this,
R.string.msg_load_is_null);
} else if (msg.what == -1 && msg.obj != null) {
headButtonSwitch(DATA_LOAD_FAIL);
((AppException) msg.obj).makeToast(NewsDetail.this);
}
}
};
initData(newsId, false);
}
(1)由于在 WebView 上显示HTML,不可能只显示纯文本,而没有一点样式,这会显得很难看,String body = UIHelper.WEB_STYLE + newsDetail.getBody()中的WEB_STYLE中定义了全局web样式
public final static String WEB_STYLE = "<style>* {font-size:16px;line-height:20px;} p {color:#333;} a {color:#3E62A6;} img {max-width:310px;} "
+ "img.alignleft {float:left;max-width:120px;margin:0 10px 5px 0;border:1px solid #ccc;background:#fff;padding:2px;} "
+ "pre {font-size:9pt;line-height:12pt;font-family:Courier New,Arial;border:1px solid #ddd;border-left:5px solid #6CE26C;background:#f6f6f6;padding:5px;} "
+ "a.tag {font-size:15px;text-decoration:none;background-color:#bbd6f3;border-bottom:2px solid #3E6D8E;border-right:2px solid #7F9FB6;color:#284a7b;margin:2px 2px 2px 0;padding:2px 4px;white-space:nowrap;}</style>";
上面全局样式:“*”定义了字体大小以及行高;“p”标签内的字体颜色;“a”标签内的字体颜色;“img”标签的图片最大宽度;“pre”为代码样式;
资讯内容是由服务返回的一串带HTML标签的字符串 : newsDetail.getBody()
相关资讯等是有返回的数据组装成的
if (newsDetail.getRelatives().size() > 0) {
String strRelative = "";
for (Relative relative : newsDetail.getRelatives()) {
strRelative += String
.format("<a href='%s' style='text-decoration:none'>%s</a><p/>",
relative.url, relative.title);
}
body += String.format(
"<p/><hr/><b>相关资讯</b><div><p/>%s</div>",
strRelative);
}
(2)图片显示
WebView上显示图片,不能直接显示大图,这会影响页面的美观以及用户体验,因此要过滤掉原始图片的高宽属性,使用全局的图片样式。同时客户端可以根据用户设置,是否加载图片显示,以达到节省流量的目的。
if (isLoadImage) {
// 过滤掉 img标签的width,height属性
body = body.replaceAll(
"(<img[^>]*?)\\s+width\\s*=\\s*\\S+", "$1");
body = body.replaceAll(
"(<img[^>]*?)\\s+height\\s*=\\s*\\S+", "$1");
// 添加点击图片放大支持
body = body.replaceAll("(<img[^>]+src=\")(\\S+)\"",
"$1$2\" onClick=\"javascript:mWebViewImageListener.onImageClick('$2')\"");
} else {
// 过滤掉 img标签
body = body.replaceAll("<\\s*img\\s+([^>]*)\\s*>", "");
}
(3)将HTML数据显示到WebView中
mWebView.loadDataWithBaseURL(null, body, "text/html","utf-8", null);
(4)处理超链接
我们知道Webview的setWebViewClient函数可以处理超链接跳转等功能,OSC也是这样实现的
mWebView.setWebViewClient(UIHelper.getWebViewClient());
接下来看看UIHelper.getWebViewClient()
public static WebViewClient getWebViewClient() {
return new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
showUrlRedirect(view.getContext(), url);
return true;
}
};
}
继续看看showUrlRedirect,这个方法实现了url跳转
public static void showUrlRedirect(Context context, String url) {
URLs urls = URLs.parseURL(url);
if (urls != null) {
showLinkRedirect(context, urls.getObjType(), urls.getObjId(),
urls.getObjKey());
} else {
openBrowser(context, url);
}
}
URLs urls = URLs.parseURL(url); 是将url转换为URLs实体
public static void showLinkRedirect(Context context, int objType,int objId, String objKey)
showLinkRedirect是根据不同类型跳转到不同的Activity
(5)点击查看大图
body = body.replaceAll("(<img[^>]+src=\")(\\S+)\"","$1$2\" onClick=\"javascript:mWebViewImageListener.onImageClick('$2')\"");
接下来我们在UIHelper中查找mWebViewImageListener ,发现addWebImageShow这个方法,这就是添加网页的点击图片展示支持
public static void addWebImageShow(final Context cxt, WebView wv) {
wv.getSettings().setJavaScriptEnabled(true);
wv.addJavascriptInterface(new OnWebViewImageListener() {
@Override
public void onImageClick(String bigImageUrl) {
if (bigImageUrl != null)
UIHelper.showImageZoomDialog(cxt, bigImageUrl);
}
}, "mWebViewImageListener");
}
在初始化控件时调用了这个方法 UIHelper.addWebImageShow(this, mWebView);
showImageZoomDialog这是方法是调用了ImageZoomDialog这个Activity,这是查看大图的Activity,并且支持缩放等,我们下次就研究这个。。。
二:底部视图
(1)底部视图中资讯和评论的切换
private void viewSwitch(int type) {
switch (type) {
case VIEWSWITCH_TYPE_DETAIL:
mDetail.setEnabled(false);
mCommentList.setEnabled(true);
mHeadTitle.setText(R.string.news_detail_head_title);
mViewSwitcher.setDisplayedChild(0);
break;
case VIEWSWITCH_TYPE_COMMENTS:
mDetail.setEnabled(true);
mCommentList.setEnabled(false);
mHeadTitle.setText(R.string.comment_list_head_title);
mViewSwitcher.setDisplayedChild(1);
break;
}
}
使用了viewswitch,可以省去重复设置setVisibility
(2)评论视图
评论使用了一个开源控件BadgeView
这个的使用也很简单 ,首先设置 bv_comment = new BadgeView(this, mCommentList);
bv_comment.setBackgroundResource(R.drawable.widget_count_bg2);
bv_comment.setIncludeFontPadding(false);
bv_comment.setGravity(Gravity.CENTER);
bv_comment.setTextSize(8f);
bv_comment.setTextColor(Color.WHITE);
接着
if (newsDetail.getCommentCount() > 0) {
bv_comment.setText(newsDetail.getCommentCount() + "");
bv_comment.show();
} else {
bv_comment.setText("");
bv_comment.hide();
}
(3)发表评论
mFootEditebox.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mFootViewSwitcher.showNext();
mFootEditer.setVisibility(View.VISIBLE);
mFootEditer.requestFocus();
mFootEditer.requestFocusFromTouch();
}
});
mFootEditer = (EditText) findViewById(R.id.news_detail_foot_editer);
mFootEditer.setOnFocusChangeListener(new View.OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
imm.showSoftInput(v, 0);
} else {
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
});
mFootEditer.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (mFootViewSwitcher.getDisplayedChild() == 1) {
mFootViewSwitcher.setDisplayedChild(0);
mFootEditer.clearFocus();
mFootEditer.setVisibility(View.GONE);
}
return true;
}
return false;
}
});
// 编辑器添加文本监听
mFootEditer.addTextChangedListener(UIHelper.getTextWatcher(this,
tempCommentKey));
// 显示临时编辑内容
UIHelper.showTempEditContent(this, mFootEditer, tempCommentKey);