Android详情页+定位评论区
App中不可避免的会有详情页的需求,其中详情页千变万化没有一点规律,这时候就要用到Webview了。文章有点长,可以直接翻目录找自己需要的部分。
首先放一张详情页的效果图。
结构呢是:
<ScrollView>
<LinearLayout>
</LinearLayout>
</ScrollView>
以上只有主题内容部分,不包括标题栏。
有人就要嗤之以鼻了,这么多内容的页面你这么简单的布局就搞定了?
没错,就他妈的这么简单!
- 其实没那么简单
有句话说的好,你之所以看不见黑暗,是因为有人竭尽全力把黑暗挡在你看不见的地方,没错!这个LinearLayout就是竭尽全力把复杂挡在了代码里的ViewGroup(逃 。。。。
我们知道了重点在这个LinearLayout ,下面来看下他都有哪些孩子?
- 辅助加载类 ArticleDetailView
package com.lerdong.toys52.details;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
/**
- Created by Lwang on 16/6/20.
*/
public class ArticleDetailView {
private Activity mContext;
private LinearLayout linearLayout,llGroup;
private View product_detail,recomment_detail,comment_num,detail_zan,htmlPrase,pinglunEmpty,flowLayoutTag;
public ArticleDetailView(Activity context) {
mContext = context;
linearLayout = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.article_detail_view, null);
llGroup = (LinearLayout) linearLayout.findViewById(R.id.ll_group);
product_detail = LayoutInflater.from(mContext).inflate(R.layout.detail_product,null);
flowLayoutTag = LayoutInflater.from(mContext).inflate(R.layout.tag_flowlayout,null);
product_detail.setVisibility(View.GONE);
htmlPrase = LayoutInflater.from(mContext).inflate(R.layout.prase_html_content,null);
pinglunEmpty = LayoutInflater.from(mContext).inflate(R.layout.detail_pinglun_empty_view,null);
recomment_detail = LayoutInflater.from(mContext).inflate(R.layout.detail_recomment,null);
comment_num = LayoutInflater.from(mContext).inflate(R.layout.item_comment_num,null);
detail_zan = LayoutInflater.from(mContext).inflate(R.layout.detail_zan,null);
}
/**
* 赞
* @return
*/
public View getDetail_zan() {
return detail_zan;
}
/**
* 商品详情
* @return
*/
public View getProduct_detail() {
return product_detail;
}
/**
* 相关推荐
* @return
*/
public View getRecomment_detail() {
return recomment_detail;
}
/**
* 评论
* @return
*/
public View getComment_num() {
return comment_num;
}
/**
* html解析器,带标题
* @return
*/
public View getHtmlPrase() {
return htmlPrase;
}
/**
* 标签
* @return
*/
public View getFlowLayoutTag() {
return flowLayoutTag;
}
/**
* 评论为空时显示
* @return
*/
public View getEmptyView() {
return pinglunEmpty;
}
public void destoryView() {
product_detail = null;
recomment_detail = null;
comment_num = null;
linearLayout = null;
mContext = null;
llGroup = null;
}
}
可以看到辅助类(ArticleDetailView)中加载了所有需要用到的模块。
这些模块大都一通百通,所以咱们就看下咱们的重点评论区。
评论区
rlDetail为评论区的RecyclerView,很遗憾没有什么高深的东西,只是new出来 addView到LinearLayout里了。
@Override
public void init() {
reminderDialog = new ReminderDialog(this);
DaggerArticleDetailComponents.builder().articleModule(new ArticleModule(this)).build().inject(this);
// mArticleDetailPresenter = new ArticleDetailPresenter(this);
initIncludeOperation();
rlDetail = new RecyclerView(this);
rlDetail.setBackgroundColor(getResources().getColor(R.color.white));
articleDetailAdapter = new ArticleDetailAdapter();
articleDetailAdapter.setTOYSOnItemClickListener(this);
articleDetailAdapter.setTOYSOnItemChildClicklistener(this);
rlDetail.setLayoutManager(new LinearLayoutManager(this));
rlDetail.setAdapter(articleDetailAdapter);
articleDetailAdapter.setHolderStausListenter(this);
mRecommentFragment = new ImageTextFragment();
mRecommentFragment.setFirstMarginGone(true);
mRecommentFragment.setiFollowListener(this);
mRecommentFragment.setInitListener(this);
mRecommentFragment.setRFLoadMoreListener(this);
}
- 什么?你问我ScrollView嵌套RecyclerView会不会出现问题?
很明确的回答你,会的。 - 可能会出现什么问题?
1、RecyclerView滑动失灵,没有那种飘逸灵动的感觉了。(惯性滑动)
解决方案:自定义ScrollView重写onInterceptTouchEvent
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
onTouchEvent(ev);
return super.onInterceptTouchEvent(ev);
}
2、RecyclerView显示不全(我是没有遇到)
解决方案:
接下来重点WebView
首先来看下web返回来的json数据
"content": "<p>有着“万物有灵”观念的日本人,基于现实的种种,创造了各种妖怪,其中唐伞小僧(からかさ小僧)由于频繁地在电影、动漫和画作中出现,可能也与伞是人们日常接触较多的物件的关系,总之这个妖怪是大众熟悉的一位。</p><p><img src=\"http://img3.52toys.com/e609debfd7e0b058dce85b89e0db1d7b\" /></p><p style=\"text-align: center;\">水木茂笔下的唐伞小僧</p><p style=\"text-align: left;\">唐伞小僧是日本神话传说中的一种妖怪,属于付丧神的一种。传说中,它是油纸伞放置100年后变化而成的,特点是单眼、吐舌、单脚,且通常穿着下驮。<br/></p><p style=\"text-align: left;\"><img src=\"http://img3.52toys.com/1393e3813c5037ed6b1715409949b7ba\" /></p><p style=\"text-align: center;\">藤子·F·不二雄笔下的唐伞小僧</p><p style=\"text-align: left;\">唐伞小僧的形象并非一成不变的,也有两只手和两只腿的造型,只要基本造型没有脱离“伞”,大多归为唐伞小僧的词条下。<br/></p><p style=\"text-align: center;\"><img src=\"http://img3.52toys.com/75771e321ed220bc3a68ddbff06275fc\" />歌川芳員『百種怪談妖物双六』里的伞妖怪“一本足”</p><p><img src=\"http://img3.52toys.com/002c4a5f46ffada9f9b1a49d860e72ba\" /></p><p style=\"text-align: center;\">狩野宴信『百鬼夜行図巻』里的伞妖怪“二本足”</p><p style=\"text-align: center;\"><img src=\"http://img3.52toys.com/933604495de5999980c9574dfac46c43\" />歌舞伎演员是单腿扮演唐伞小僧的</p><p>上图歌舞伎演员尾上菊五郎扮演的唐伞小僧,和我最近收藏的一款搪胶玩具Karakasa Tattoo Man形象完全一样,制作方日本Secret Base应该参考这个演员的扮相。</p><p><img src=\"http://img3.52toys.com/4627ea3e355553276deef564421e4adc\" />第一次看到Karakasa Tattoo Man就非常喜欢这个造型,只是对于中国玩家来说,这个玩具不太容易买到。Secret Base基于这个造型,已经将其平台玩具化,推出了数款配色。其中有一款是夜光的版本,我对夜光材质的玩具向来是很喜欢的,而且夜光这个概念本身也很适合妖怪,所以就更想要了,只是遗憾的是这个版本只在美国发售。机缘巧合之下,一位美国好友帮我购入了。下面是这个夜光版本的实物照片:</p><p><img src=\"http://img3.52toys.com/c2d7e6187d695a9a46e5f15dff059b3f\" /></p><p>夜光材质的绝妙应用,把玩具烘托出一阵萌萌的鬼气。<br/><img src=\"http://img3.52toys.com/b1046a95a9d993a493b0882125bd93f3\" /></p><p>面部涂装是我们熟悉的歌舞伎演员形象。<br/><img src=\"http://img3.52toys.com/5ad69422135272bad99d6d9f490101b6\" /></p><p>左右胳膊和腿部都有非常精细的纹身,不过要非常小心避免摩擦和刺碰,导致纹身受损。<br/><img src=\"http://img3.52toys.com/969e9a5b751506c6a8fa13834b47bcdc\" /></p><p>没什么可动关节,但胜在造型亮眼,非常适合在书房中陈列。</p><p><img src=\"http://img3.52toys.com/2f9c1bb2d258559dfe49ccabb8f6a6fa\" /></p><p>这个玩具如果放上一百年,也会成精的吧?</p>",
可以看到content
字段里有成片成片的html标签
- 配置WebView
提醒一句,关闭硬件加速。然后找个你喜欢的位置addView到LinearLayout中就行了
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void settingWebView() {
wvWeb.setWebViewClient(new MyWebViewClient());
wvWeb.setWebChromeClient(new WebChromeClient());
wvWeb.getSettings().setPluginState(WebSettings.PluginState.ON);
wvWeb.getSettings().setUseWideViewPort(true);
wvWeb.getSettings().setDefaultZoom(WebSettings.ZoomDensity.FAR);
wvWeb.getSettings().setBuiltInZoomControls(true);
wvWeb.getSettings().setSupportZoom(true);
wvWeb.getSettings().setJavaScriptCanOpenWindowsAutomatically(
true);
wvWeb.getSettings().setAllowFileAccess(true);
wvWeb.getSettings().setDomStorageEnabled(true);
wvWeb.getSettings().setDefaultTextEncodingName("UTF-8");
wvWeb.getSettings().setAppCacheEnabled(true);
wvWeb.getSettings().setLoadWithOverviewMode(true);
wvWeb.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH);
wvWeb.getSettings().setJavaScriptEnabled(true);
wvWeb.addJavascriptInterface(new JavaScriptObject(ArticleDetailActivity.this), "toys52");
// wvWeb.setLayerType(View.LAYER_TYPE_HARDWARE, null);
wvWeb.getSettings().setBlockNetworkImage(true);
//注释掉,解决查看图文详情会崩溃的问题
// wvWeb.setTransitionGroup(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
wvWeb.getSettings().setDisplayZoomControls(false);
if (Build.VERSION.SDK_INT >= 19) {
wvWeb.getSettings().setLoadsImagesAutomatically(true);
} else {
wvWeb.getSettings().setLoadsImagesAutomatically(false);
}
}
- WebView插入之后就是喜闻乐见塞数据了。
wvWeb.loadDataWithBaseURL(null, getHtmlData(content), "text/html", "utf-8", null);
public String getHtmlData(String content) {
TLog.e("webContent", "content:" + content);
String htmlData = "<html>\n" +
"<head>\n" +
"<meta charset=\"UTF-8\">" +
"<link rel=\"stylesheet\" href=\"file:///android_asset/common.css\"/>\n" +
"<link rel=\"stylesheet\" href=\"file:///android_asset/mobile.css\"/>\n" +
"<link rel=\"stylesheet\" href=\"file:///android_asset/bootstrap.min.css\"/>\n" +
"<script src=\"file:///android_asset/base.js\"></script>" +
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n" +
"<meta name=\"viewport\" content=\"initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width\">" +
"<style type=\"text/css\">\n" +
".detail iframe{" +
"width: 100%;" +
"}" +
"</style>\n" +
"</head>\n" +
"<body>\n" +
"<div class=\"detail\">\n" +
content +
"</div>\n" +
"</body>\n" +
"</html>";
return htmlData;
}
html里引用了三个css文件,这些是从我司前端大大哪里搞来的,主要是控制图片,视频,文字大小等等的。
Js文件呢是用来监听WebView中图片加载完成的,之后在调用Android方法跳转评论区。晚些会把css文件和js文件上传。
详情页搞定。
跳转评论区
首先要知晓一点,android所有的滑动都是移动view来完成的,所以,我们要定位到评论区需要攻克的问题就是知道评论区View在ViewGroup中的位置。
介绍一个方法。 getLocationInWindow(int[])
,计算该视图在它所在的widnow的坐标x,y值,//获取在整个窗口内的绝对坐标
顺着思路来讲我只要获取到评论区在window中的位置和ScrollView在window中的位置就可以确定我要ScrollTo到何处了。
/**
* 定位到评论区
*/
private void goCommentLocation() {
needLocation = false;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if(comment_num != null && mEasyScroll != null) {
int[] comment_numxy = new int[2];
int[] easyScrollxy = new int[2];
comment_num.getLocationInWindow(comment_numxy);
mEasyScroll.getLocationInWindow(easyScrollxy);
mEasyScroll.smoothScrollTo(0, comment_numxy[1] - easyScrollxy[1]);
}
}
},postTime);
}
ScrollView到window定位的高正好是状态栏的高度,所以我们用评论区的高减去ScrollView的高就是我们要跳转的高度数值。
- scrollBy,scrollTo和smoothScrollTo
scrollBy是根据在上一个点的基础上+x, 移动后坐标为x+x1,y+y1
scrollTo是移动到x1,y1上,移动后坐标为x1,y1
smoothScrollTo 基本与scrollTo相同,不同点scrollTo没有动画,而smoothScrollTo平滑移动到目标点上。
什么时候跳转?
WebView加载多图卡顿崩溃?
当然是在整个WebView加载完成之后跳转了,但是还会有一个问题,那就是,WebView一次性加载很多张图片会直接卡到崩溃。
解决办法:wvWeb.getSettings().setBlockNetworkImage(false);
WebView加载数据的时候阻塞图片不要加载,等文字内容全部解析完毕,再wvWeb.getSettings().setBlockNetworkImage(true);
,这样就会陆续开始加载图片。提示:onPageFinished
js监听图片加载完毕,回调Android跳转评论区
window.onload = function() {
var imgList = document.querySelectorAll('img');
var imgNum = imgList.length;
for(var i in imgList) {
imgList[i].onload = function(){
imgNum--;
if(imgNum == 0){
toys52.fun1FromAndroid();
}
};
}
}