weex页面有scrollView嵌套web的页面,如果不给web指定高度就显示不出来。RN也有这个问题,查了下全部是通过原生开启一个不显示的webview提前加载一遍再将高度传给weex来解决,这种方式需要加载俩边资源拖慢了显示速度,而且浪费资源。

研究了下新方式,只加载一遍,用原生自定义的webview在加载完后在原生端修改高度。

同时使用自定义的webivew解决了有些特殊机型无法显示(如LG nexus5),以及webview的一系列设置,安全,js问题。

面临三个问题:
1,如何自定义weex组件?
2,如何通过源码找出修改weex控件宽高的方法?
3,如何得到webview的准确高度?

自定义weex控件:

继承WXComponent指定泛型。

public class WWebview extends WXComponent<DisplayX5Webview> {}

在原生端application中注册组件后weex端就能直接引用,注意:不能有大写字母,weex引用时为蓝色方为成功;暗黄则是失败。

WXSDKEngine.registerComponent("mywebview", WWebview.class);

weex直接引用:

<mywebviewstyle={[styles.webViewContainer]}
/>

在初始化里返回weex显示的控件,这里可以返回任意布局,甚至动态添加子布局等。

@Override
protected DisplayX5Webview initComponentHostView(@NonNull Context context) {webView = new DisplayX5Webview(context.getApplicationContext());initWebView((Activity) context);//初始化return webView;
}

约定weex端的标签属性source:(注意要小写)

@WXComponentProp(name = "source")
public void setSource(String source) {mSource = source;
}

属性直接使用即可:

<mywebviewstyle={[styles.webViewContainer]}source={`url`}
/>

加载weex时component的生命周期会先调用@WXComponentProp(name = "source"),再调用bindData()顾名思义就是加载数据的(小坑:如果weex端没有做判空,在网络请求下来之前先render一遍,后面网络数据返回以后再render就不会执行bindDta了)

 @Overridepublic void bindData(WXComponent component) {super.bindData(component);if (!TextUtils.isEmpty(mSource)) {webView.loadData(mSource, "text/html; charset=UTF-8", "UTF-8");//  webView.loadUrl(mSource);}}

到这里,如果如果在weex端指定高度就已经可以显示了。

在安卓端修改控件高度

修改高度很麻烦,无论如何设置LayoutParams都是没用的,下面大致看下源码里为什么会设置不进去。

Component的注册加载机制参考下:https://www.jianshu.com/p/53f69bfcbc50

直接看处理渲染的中心类WXDomHandler。dom,渲染处理都在此处。

 @Overridepublic boolean handleMessage(Message msg) {if (msg == null) {return false;}int what = msg.what;Object obj = msg.obj;WXDomTask task = null;if (obj != null && obj instanceof WXDomTask) {task = (WXDomTask) obj;Object action = ((WXDomTask) obj).args.get(0);if (action != null && action instanceof TraceableAction) {((TraceableAction) action).mDomQueueTime = SystemClock.uptimeMillis() - msg.getWhen();}}if (!mHasBatch) {mHasBatch = true;if(what != WXDomHandler.MsgType.WX_DOM_BATCH) {int delayTime = DELAY_TIME;if(what == MsgType.WX_DOM_TRANSITION_BATCH){delayTime = TRANSITION_DELAY_TIME;}mWXDomManager.sendEmptyMessageDelayed(WXDomHandler.MsgType.WX_DOM_BATCH, delayTime);}}switch (what) {case MsgType.WX_EXECUTE_ACTION:mWXDomManager.executeAction(task.instanceId, (DOMAction) task.args.get(0), (boolean) task.args.get(1));break;case MsgType.WX_DOM_UPDATE_STYLE://keep this for direct native callmWXDomManager.executeAction(task.instanceId, Actions.getUpdateStyle((String) task.args.get(0),(JSONObject) task.args.get(1),task.args.size() > 2 && (boolean) task.args.get(2)),false);break;case MsgType.WX_DOM_BATCH:mWXDomManager.batch();mHasBatch = false;break;case MsgType.WX_CONSUME_RENDER_TASKS:mWXDomManager.consumeRenderTask(task.instanceId);break;default:break;}return true;}

很明显case MsgType.WX_DOM_UPDATE_STYLE:字面意思就是我们要找的。再看下具体做了什么来更新dom刷新ui:

 case MsgType.WX_DOM_UPDATE_STYLE://keep this for direct native callmWXDomManager.executeAction(task.instanceId, Actions.getUpdateStyle((String) task.args.get(0),(JSONObject) task.args.get(1),task.args.size() > 2 && (boolean) task.args.get(2)),false);break;

需要三个参数:instanceId——WXComponent初始化自带,第二个参数getUpdateStyle,第三个不管

看第二个参数传入的方法:

  public static DOMAction getUpdateStyle(String ref, JSONObject data, boolean byPesudo){return new UpdateStyleAction(ref, data, byPesudo);}

new 的DOMAction最终executeAction来执行执行代码依然在UpdateStyleAction中:

@Overridepublic void executeDom(DOMActionContext context) {if (context.isDestory() || mData == null) {return;}...if (!mData.isEmpty()) {domObject.updateStyle(mData, mIsCausedByPesudo);domObject.applyStyle(mData);if(!mData.isEmpty()) {context.postRenderTask(this);}}}
具体看updateStyle方法:public void updateStyle(Map<String, Object> updates, boolean byPesudo) {
.../*** diff styles* */if(!diffUpdates(updates, getStyles())){return;}if(mStyles == null) {mStyles = new WXStyle();}mStyles.putAll(updates,byPesudo);...}

diffUpdates做了新老对比,无改变return。

mStyles.putAll(updates,byPesudo);这句可以看出最终还是追加修改的方式,所以只需要传入要修改的参数即可。

在WXComponent中有notifyNativeSizeChanged方法但是断点看mNeedLayoutOnAnimation一直为false。把这个方法拷贝出来用。

   public void notifyNativeSizeChanged(int w, int h) {Message message = Message.obtain();WXDomTask task = new WXDomTask();task.instanceId = getInstanceId();if (task.args == null) {task.args = new ArrayList<>();}JSONObject style = new JSONObject(2);Spacing padding = getDomObject().getPadding();Spacing border = getDomObject().getBorder();int top = (int) (padding.get(Spacing.TOP) + border.get(Spacing.TOP));int bottom = (int) (padding.get(Spacing.BOTTOM) + border.get(Spacing.BOTTOM));float webW = WXViewUtils.getWebPxByWidth(w);float webH = WXViewUtils.getWebPxByWidth(h) + top + bottom;style.put("height", webH + 1);style.put("width", webW + 1);task.args.add(getRef());task.args.add(style);message.obj = task;message.what = WXDomHandler.MsgType.WX_DOM_UPDATE_STYLE;WXSDKManager.getInstance().getWXDomManager().sendMessage(message);//   ((WXDomObject) getDomObject()).setStyleHeight(h);// ((WXDomObject) getDomObject()).setLayoutHeight(h);//WXSDKManager.getInstance().getWXDomManager().postRenderTask(getInstanceId());
//        Message msg = Message.obtain();
//        msg.what = WXDomHandler.MsgType.WX_CONSUME_RENDER_TASKS;
//        WXDomTask task = new WXDomTask();
//        task.instanceId = getInstanceId();
//        task.args = new ArrayList<>();
//        task.args.add(null);
//        msg.obj = task;
//        WXSDKManager.getInstance().getWXDomManager().sendMessage(msg);}

高度计算需要算上padding和border,不然会显示不全,获取方式源码都有提供。

综上发起更新style改变高度的方法如下:

    private void reSetHeight() {int contentHeight = webView.getContentHeight();notifyNativeSizeChanged(screenWidth, WXViewUtils.dip2px(contentHeight));}

获取webview内容高度最准确方式

webview获取高度是个小坑,

1,setWebViewClient和setWebChromeClient分别在有些机型上不回调。

2,onPageFinished执行完并不一定加载完

比较推荐自定义webview在onDraw中获取getContentHeight,因为不管webview设置的高度够不够,都会绘制完。

public class DisplayX5Webview  extends X5WebView {public interface DisplayFinish{void After();}DisplayX5Webview.DisplayFinish df;public void setDisplayListner(DisplayX5Webview.DisplayFinish df) {this.df = df;}public DisplayX5Webview(Context context, AttributeSet attrs) {super(context, attrs);}public DisplayX5Webview(Context context) {super(context);}//onDraw表示显示完毕@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);df.After();}
}

setDisplayListner回调中调用reSetHeight。以 if (oldContentHeight < contentHeight) 判断,只取大的高度值。

    private void reSetHeight() {int contentHeight = webView.getContentHeight();if (oldContentHeight < contentHeight) {notifyNativeSizeChanged(screenWidth, WXViewUtils.dip2px(contentHeight));oldContentHeight = contentHeight;}}

weex解决scrollView嵌套webview高度问题,安卓自定义weex组件webview,相关推荐

  1. 解决ScrollView嵌套ListView高度的问题

    2019独角兽企业重金招聘Python工程师标准>>> public static void setListViewHeight(ListView listView) {ListAd ...

  2. 解决ScrollView嵌套ViewPager出现的滑动冲突问题

    /** * 解决ScrollView嵌套ViewPager出现的滑动冲突问题 */ public class ScrollView1 extends ScrollView { private bool ...

  3. 解决ScrollView嵌套RecyclerView出现item显示不全的问题

    解决ScrollView嵌套RecyclerView出现item显示不全的问题 参考文章: (1)解决ScrollView嵌套RecyclerView出现item显示不全的问题 (2)https:// ...

  4. android解决ScrollView嵌套ListView不能下拉刷新

    为了不误导新人,这篇帖子写的比较早了,这里2016年2月23日21:33:20更新的内容: 千万不要在实际开发中用scrollview嵌套listview\recylerview来处理滑动嵌套,   ...

  5. 四种方案解决ScrollView嵌套ListView问题

    在工作中,曾多次碰到ScrollView嵌套ListView的问题,网上的解决方法有很多种,但是杂而不全.我试过很多种方法,它们各有利弊. 在这里我将会从使用ScrollView嵌套ListView结 ...

  6. ApkBus---四种方案解决ScrollView嵌套ListView问题

    原文链接:http://www.apkbus.com/forum.php?mod=viewthread&tid=161576 一. 为什么要使用ScrollView嵌套ListView的奇怪的 ...

  7. Android之解决ScrollView嵌套RecycleView导致滑动冲突或者显示不全的问题

    1 问题 ScrollView嵌套RecycleView导致滑动冲突或者显示不全的问题 2 解决办法 1).ScrollView替换成普通布局,然后RecycleView用的BaseMultiItem ...

  8. 安卓学习UI组件-解决ScrollView嵌套ListView,GridView的冲突

    2019独角兽企业重金招聘Python工程师标准>>> 案例: strings.xml <resources> <string name="app_nam ...

  9. ScrollView 嵌套 RecyclerView 高度自适应遇到的问题

    以下是我用瀑布流的所用的东西 核心 LayoutManager 的 onMeasure 方法重写 //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能 mRecyclerView.se ...

最新文章

  1. 第六周项目一-分数类的雏形(1)
  2. 【控制】《多智能体系统一致性协同演化控制理论与技术》纪良浩老师-目录
  3. openFoam源码中的C++
  4. 大连100公里越野赛_心中的痛
  5. android scrollview居中,使用 HorizontalScrollView 实现滚动控制
  6. 容器编排技术 -- 使用kubectl实现应用伸缩
  7. Linux 命令(111)—— alias 命令(builtin)
  8. 2020年中国标准化发展现状分析,数字化为标准化领域带来新挑战「图」
  9. SQL Transformation
  10. Java中的Math函数常用方法都在这里
  11. java中什么叫服务?
  12. uni的numberbox怎么用_模拟器最强BIOS篇,如何使用uni-bios
  13. OSChina 周日乱弹 ——我已经开始适应这个身体了
  14. 全极化雷达遥感图像的迭代优化非局部均值去噪法
  15. 2021.5.5笔记 多态
  16. 假币问题:有n枚硬币,其中有一枚是假币,已知假币的重量较轻。现只有一个天平,要求用尽量少的比较次数找出这枚假币。
  17. 关于CSDN博客待审核的问题
  18. MySQL 系统表损坏导致xtrabackup备份失败Cannot open filepath
  19. 暗黑破坏神:不朽 unity mmo arpg资源分包精讲
  20. 电子货架标签----仓库管理系统架构

热门文章

  1. Access报表实现记账凭证打印
  2. c++简单排序算法(冒泡、选择以及调用algorithm中的sort函数)
  3. Opencv快速入门(C++版),新手向
  4. Unity学习之PD 过河游戏智能帮助实现
  5. 如何播放巧虎正版DVD光盘
  6. 年产10万吨1,4-丁二醇项目的初步设计-文献综述
  7. 微软服务器故障,微软解释Windows Azure故障原因
  8. 跳一跳python源码下载_《跳》字意思读音、组词解释及笔画数 - 新华字典 - 911查询...
  9. 差分轮式机器人模型matlab,两轮差速机器人运动学分析和控制研究
  10. 【图文直播全文记录】酷狗音乐的大数据实践(纯干货)