Реактивная оболочка для координаторовLayout и BottomSheetBehavior

Я писал собственный модуль для 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);
    }
}

И мой реагирующий компонент станет таким.

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, но не работает с реагирующими компонентами. Итак, как сделать RelativeLayout для обертывания реагирующего компонента <View style={{height: 300}} />? Я также попытался реализовать некоторый меру shadownode, но не работал должным образом, я не знаю, как они работают.

Я добавил этот пример в мой github, потому что каждый хочет попробовать его. https://github.com/cesardeazevedo/react-native-bottom-sheet-behavior

Ответ 1

После большой отладки, наконец, я получил ее, мне пришлось сделать 2 вещи, прежде всего, чтобы переопределить функцию onMeasure и применить высоту ребенка в setMeasuredDimension и, по-видимому, устранить проблему с высотой, но после небольшой игры бит, любое изменение состояния разбивает положение нижнего листа, поэтому мне пришлось вызвать requestLayout для каждого изменения состояния через UIManager.dispatchViewManagerCommand и работает очень хорошо.

Итак, это исправление, которое исправляет.

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,
      [],
    )
  }

Update

Я понял, что состояние обновления во время скольжения мерцает во всех макетах, после поиска кода некоторых библиотек я нашел функцию needsCustomLayoutForChildren, которая описана в ViewGroupManager.java

  /**
   * 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 responsibility to properly call layout on its
   * children.
   * Returns false for the default behavior of automatically laying out children without going
   * through the ViewGroup onLayout method. In that case, onLayout for this View type must *not*
   * call layout on its children.
   */
  public boolean needsCustomLayoutForChildren() {
    return false;
  }

Итак, я исправлено, возвращая true в CoordinatorLayoutManager.java

Вот как это выглядит.

react-native-bottom-sheet-behavior