WeeX跨平台框架,自定义安卓平台MarkDown文本渲染组件高度跟随内容自适应实现思路探索

需求描述

应用要求能够加载markdown文本,以及常规html标签。

组件高度自适应问题

JS端只设置组件宽度,不设置组件高度,我们期待组件高度跟随内容调整,使得内容能够完全显示出来。 但是JS端组件不设置高度和原生组件不调用setContentBoxMeasurement方法,那么组件高度就是默认0,组件将无法显示。其次由于是富文本,常规使用

java 复制代码
setContentBoxMeasurement(new TextContentBoxMeasurement())

将出现内容显示不全被裁减的问题,因为TextContentBoxMeasurement是通过给TextPaint画笔设置字体大小和行高来测量文本显示的Layout。MarkDown中有很多格式转义符(标签、*号、#号)等,这些仅用于配置文本的样式,如果将它们也纳入普通文本通过TextContentBoxMeasurement测量,那么必然测量出来的高度是有问题,尤其是插入了图片、标题等。

解决思路

原生组件使用ScrollerView包裹TextView,这样即便ScrollerView和其父层容器高度为0,Text View将也可以自由伸展,等TextView渲染完成后,我们拿到最新的TextView高度,将高度数据返回通知JS端去重新设置组件高度,这样就解决了高度自适应问题。

java 复制代码
@Override
    protected FrameLayout initComponentHostView(@NonNull Context context) {
        // 外层侦布局
        FrameLayout layout = new FrameLayout(context);
        // 可滚动布局【用于让文本组件可自由伸展】
        ScrollView scrollView = new ScrollView(context);
        // 设置滚动布局高度撑满,即JS设置多高,它便有多高
        ViewGroup.LayoutParams params =
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        scrollView.setLayoutParams(params);
        // 隐藏可滚动条,禁止滚动,拦截滚动事件
        scrollView.setVerticalScrollBarEnabled(false);
        scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
        scrollView.setOnTouchListener((v, event) -> true);
        // 创建文本显示组件
        this.mTextView = new TextView(context);
        ViewGroup.LayoutParams textParams =
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        this.mTextView.setLayoutParams(textParams);
        // 添加文本组件布局变化监听
        this.mTextView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                int actualHeight = bottom - top;
                if (actualHeight > 0 && lastLayoutHeight != actualHeight) {
                    // fireEvent 通知Weex JS或者native,让上层刷新使用最新测量的实际高度
                    // JS端接收后,请重新设置高度
                    Map<String, Object> params = new HashMap<>();
                    params.put("height", WXViewUtils.getWebPxByWidth(actualHeight));
                    fireEvent("onRealHeight", params);
                }
            }
        });
        scrollView.addView(this.mTextView);
        layout.addView(scrollView);
        return layout;
    }

JS端:

html 复制代码
<Markdown
  class="richtext"
  :style="{height: maxValue || 'auto'}"
  :content="content"
  @onRealHeight="handleOnRealHeight"
/>
css 复制代码
.richtext {
  font-size: 26px;
  color: #666666;
  line-height: 40px;
}
javascript 复制代码
handleOnRealHeight (params) {
  const newHeight = params.height
  if (newHeight > this.maxValue) {
    this.maxValue = newHeight
  }
}
相关推荐
杉氧11 小时前
深入理解 Compose 重组机制:快照系统如何驱动 UI 精准刷新?
android·架构·android jetpack
召钱熏11 小时前
状态枚举正确≠渲染正确:一个语音按钮的状态机边界修复实录
android·前端
杉氧12 小时前
深度解析:Jetpack Compose 核心架构与底层原理 —— 十年安卓老兵的“破茧重生”
android·架构·android jetpack
通玄12 小时前
Jetpack Compose 入门系列(七):ViewModel 与界面状态管理
android
落魄Android在线炒饭12 小时前
Android Framework 开发技巧:android.jar 生成与系统快速编译验证
android
如此风景13 小时前
Kotlin Flow操作符学习
android·kotlin
plainGeekDev14 小时前
GreenDAO → Room
android·java·kotlin
weiggle14 小时前
第八篇:ViewModel + Compose——生产级状态管理实践
android
恋猫de小郭19 小时前
Amper 正式转正 Kotlin Toolchain ,Gradle 未来何去何从
android·前端·flutter
plainGeekDev21 小时前
ButterKnife → ViewBinding
android·java·kotlin