【问题标题】:react-native wrapper for CoordinatorLayout and BottomSheetBehaviorCoordinatorLayout 和 BottomSheetBehavior 的 react-native 包装器
【发布时间】:2016-12-19 17:10:03
【问题描述】:

我一直在编写一个原生 android 模块,它封装了 BottomSheetBehavior

一个非常简单的BottomSheetBehavior可以这样实现 https://gist.github.com/cesardeazevedo/a4dc4ed12df33fe1877fc6cea42475ae

我面临的第一件事是,整个页面必须是 CoordinatorLayout 的子级,并且底部是 BottomSheetBehavior。

所以我不得不编写 2 个原生模块,<CoordinatorLayout /><BottomSheetBehavior />

这是 bottomSheetBehavior 包装器。

BottomSheetBehaviorManager.java

public class BottomSheetBehaviorManager extends ViewGroupManager<BottomSheetBehaviorView> {

    @Override
    public BottomSheetBehaviorView createViewInstance(ThemedReactContext context) {
        return new BottomSheetBehaviorView(context);
    }
}

BottomSheetBehaviorView.java

public class BottomSheetBehaviorView extends RelativeLayout {

    public BottomSheetBehaviorView(Context context) {
        super(context);

        int width  = ViewGroup.LayoutParams.WRAP_CONTENT;
        int height = ViewGroup.LayoutParams.WRAP_CONTENT;
        // int height = 1000; // fixed a height works, it only slide up half of the screen

        CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams(width, height);
        params.setBehavior(new BottomSheetBehavior());
        this.setLayoutParams(params);

        BottomSheetBehavior<BottomSheetBehaviorView> bottomSheetBehavior = BottomSheetBehavior.from(this);
        bottomSheetBehavior.setHideable(false);
        bottomSheetBehavior.setPeekHeight(200);
    }
}

而我的 react 组件变成了这个样子。

index.android.js

  return () {
    <CoordinatorLayout style={{flex: 1}}>
      <View><!--app--></View>
      <BottomSheetBehavior>
        <View style={{height: 300}}> <!--height doesnt work-->
          <Text>BottomSheetBehavior !</Text>
        </View>
      </BottomSheetBehavior>
    </CoordinatorLayout>
  )

而且它有效!

但我一直在努力让 BottomSheet 用 wrap_content 包裹他们的孩子,它不应该滑动整个屏幕,它应该只滑动包裹的内容(在这种情况下是 lorem ipsum 文本),它适用于 android 组件,但不适用于 react 组件。那么,如何制作一个 RelativeLayout 来包装一个反应 &lt;View style={{height: 300}} /&gt; 组件?我也尝试实现了一些measure shadownode,但没有按预期工作,我不知道它们是如何工作的。

我已经在我的 github 上添加了这个示例,供大家尝试。 https://github.com/cesardeazevedo/react-native-bottom-sheet-behavior

【问题讨论】:

    标签: android react-native react-native-android bottom-sheet


    【解决方案1】:

    经过大量调试,终于搞定了,我必须做两件事,首先是重写onMeasure函数并将子高度应用到setMeasuredDimension,显然修复了高度问题,但玩了一点之后位,状态的任何变化都会破坏bottomSheet的位置,所以我不得不通过UIManager.dispatchViewManagerCommand为每个状态变化调用requestLayout,并且效果很好。

    所以,这就是修复的实现。

    commit

    BottomSheetBehaviorView.js

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        View child = this.getChildAt(0);
    
        if (child != null) {
            setMeasuredDimension(widthMeasureSpec, child.getHeight());
        }
    }
    

    BottomSheetBehaviorManager.js

    @Override
    public Map<String, Integer> getCommandsMap() {
        return MapBuilder.of("setRequestLayout", COMMAND_SET_REQUEST_LAYOUT);
    }
    
    @Override
    public void receiveCommand(BottomSheetBehaviorView view, int commandType, @Nullable ReadableArray args) {
        if (commandType == COMMAND_SET_REQUEST_LAYOUT) {
            setRequestLayout(view);
        }
    }
    
    private void setRequestLayout(BottomSheetBehaviorView view) {
        view.requestLayout();
    }
    

    BottomSheetBehavior.js

      componentDidUpdate() {
        UIManager.dispatchViewManagerCommand(
          findNodeHandle(this),
          UIManager.RCTBottomSheetBehaviorAndroid.Commands.setRequestLayout,
          [],
        )
      }
    

    更新

    我意识到滑动时更新状态会闪烁所有布局,在查看了一些库代码后,我发现了viewGroupManager.java中描述的needsCustomLayoutForChildren函数

      /**
       * Returns whether this View type needs to handle laying out its own children instead of
       * deferring to the standard css-layout algorithm.
       * Returns true for the layout to *not* be automatically invoked. Instead onLayout will be
       * invoked as normal and it is the View instance's responsibility to properly call layout on its
       * children.
       * Returns false for the default behavior of automatically laying out children without going
       * through the ViewGroup's onLayout method. In that case, onLayout for this View type must *not*
       * call layout on its children.
       */
      public boolean needsCustomLayoutForChildren() {
        return false;
      }
    

    所以我 fixed 在 CoordinatorLayoutManager.java 上返回 true

    这是它的样子。

    【讨论】:

    • 哇哇,真是太棒了,谢谢先生的分享,我会试试这个并与BottomSheetFragment进行公关! :)
    猜你喜欢
    • 2017-09-03
    • 1970-01-01
    • 1970-01-01
    • 2018-09-10
    • 2016-07-13
    • 2018-09-08
    • 2022-12-14
    • 2019-08-23
    • 2021-02-09
    相关资源
    最近更新 更多