最近在整理公司用的 React native Android 相关组件,然后发现有个组件封装好后改变属性后居然不生效,然后把软件切入后台再进去就很神奇的这个组件更新了

经过各种搜索,和问公司大佬们,发现这是 react native android UI 组件封装的一个常见的坑了具体的问题大概就是

react-native 为了提升安卓的性能,将 requestLayout 的执行过程统一通过UIManagerModule 来管理,而原 ReactViewGroup 内的 requestLayout 被重写为空方法,就等同于将该 ViewGroup 包裹下的所有子元素的 requestLayout 都被拦截,无法通知到 ViewRootImpl 去进行重绘

如果有小伙伴想深入了解的话可以去了解一下 安卓下的 requestLayout 机制和 RN 下的 requestLayout 的对应调整,我这里就不去分析了,修复方法也是公司的一个大牛教我的,我这里就只是记录一下这个坑和其修复的方法叭

首先有两个重新绘制的方法

import android.view.Choreographer;
import android.view.View;


// for fix addView not showing ====
private static void setupLayoutHack(View mView) {
  Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
      // 这个事件很关键,不然不能触发再次渲染,让 view 在RN里渲染成功!!
      @Override
      public void doFrame(long frameTimeNanos) {
          manuallyLayoutChildren(mView);
          mView.getViewTreeObserver().dispatchOnGlobalLayout();
          Choreographer.getInstance().postFrameCallback(this);
      }
  });
}

// 这个函数很关键,不然不能触发再次渲染,让 view 在RN里渲染成功!!
private static void manuallyLayoutChildren(View mView) {
  for (int i = 0; i < mView.getChildCount(); i++) {
      View child = mView.getChildAt(i);
      child.measure(View.MeasureSpec.makeMeasureSpec(mView.getMeasuredWidth(), View.MeasureSpec.EXACTLY),
        View.MeasureSpec.makeMeasureSpec(mView.getMeasuredHeight(), View.MeasureSpec.EXACTLY));
      child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
  }
}

然后再你改变组件属性的地方调用 setupLayoutHack(View mView) 方法就好了,这里的 mView 就是被你改变的组件 View

好啦,这次的坑就踩到这里,如果你找到更好的方法记得也要告诉我一声哦…