Giter Club home page Giter Club logo

Comments (4)

listenzz avatar listenzz commented on June 1, 2024

需要在原生端自定义容器和对应的 Navigator。

例如 iOS 可以这么弄:

// DeckViewController.h
#import <NavigationHybrid/NavigationHybrid.h>

@interface DeckViewController : HBDViewController

@property(nonatomic, strong) UIViewController *firstDeckController;
@property(nonatomic, strong) UIViewController *secondDeckController;

@end
// DeckViewController.m
#import "DeckViewController.h"

@interface DeckViewController ()

@end

@implementation DeckViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self addChildViewController:self.firstDeckController];
    self.firstDeckController.view.frame = self.view.bounds;
    [self.view addSubview:self.firstDeckController.view];
    [self.firstDeckController didMoveToParentViewController:self];
    self.firstDeckController.definesPresentationContext = YES;
    
    [self addChildViewController:self.secondDeckController];
    self.secondDeckController.view.frame = self.view.bounds;
    [self.view addSubview:self.secondDeckController.view];
    [self.secondDeckController didMoveToParentViewController:self];
    
}

- (UINavigationController *)navigationController {
    if ([self.firstDeckController isKindOfClass:[UINavigationController class]]) {
        return (UINavigationController *)self.firstDeckController;
    }
    return self.firstDeckController.navigationController;
}

- (UIViewController *)childViewControllerForStatusBarStyle {
    return self.firstDeckController;
}

@end

一个自定义容器对应一个 Navigator

// DeckNavigator.h
#import <NavigationHybrid/NavigationHybrid.h>

@interface DeckNavigator : NSObject <HBDNavigator>

@end
// DeckNavigator.m
#import "DeckNavigator.h"
#import "DeckViewController.h"

@implementation DeckNavigator

- (NSString *)name {
    return @"deck";
}

- (NSArray<NSString *> *)supportActions {
    return @[];
}

- (UIViewController *)createViewControllerWithLayout:(NSDictionary *)layout {
    NSArray *deck = [layout objectForKey:self.name];
    if (deck && deck.count == 2) {
        NSDictionary *first = [deck objectAtIndex:0];
        NSDictionary *second = [deck objectAtIndex:1];
        
        UIViewController *firstController = [[HBDReactBridgeManager sharedInstance] controllerWithLayout:first];
        UIViewController *secondController = [[HBDReactBridgeManager sharedInstance] controllerWithLayout:second];
        
        if (firstController && secondController) {
            DeckViewController *deckController = [[DeckViewController alloc] init];
            deckController.firstDeckController = firstController;
            deckController.secondDeckController = secondController;
            return deckController;
        }
    }
    return nil;
}

- (BOOL)buildRouteGraphWithController:(UIViewController *)vc graph:(NSMutableArray *)container {
    if ([vc isKindOfClass:[DeckViewController class]]) {
        DeckViewController *deck = (DeckViewController *)vc;
        NSMutableArray *children = [[NSMutableArray alloc] init];
        [[HBDReactBridgeManager sharedInstance] routeGraphWithController:deck.firstDeckController container:children];
        [[HBDReactBridgeManager sharedInstance] routeGraphWithController:deck.secondDeckController container:children];
        
        UIViewController *presented = deck.firstDeckController.presentedViewController;
        while (presented && !presented.isBeingDismissed ) {
             [[HBDReactBridgeManager sharedInstance] routeGraphWithController:presented container:children];
            presented = presented.presentedViewController;
        }
        
        [container addObject:@{ @"type": self.name, self.name: children }];
        return YES;
    }
    return NO;
}

- (HBDViewController *)primaryChildViewControllerInController:(UIViewController *)vc {
    if ([vc isKindOfClass:[DeckViewController class]]) {
        DeckViewController *deck = (DeckViewController *)vc;
        UIViewController *presented = deck.firstDeckController;
        while (true) {
            if (presented.presentedViewController && !presented.presentedViewController.isBeingDismissed) {
               presented = presented.presentedViewController;
            } else {
                return [[HBDReactBridgeManager sharedInstance] primaryChildViewControllerInController:presented];
            }
        }
    }
    return nil;
}

- (void)handleNavigationWithViewController:(UIViewController *)vc action:(NSString *)action extras:(NSDictionary *)extras {
    
}

@end

注册这个 Navigator

// AppDelegate.m
#import "DeckNavigator.h"

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

     [[HBDReactBridgeManager sharedInstance] registerNavigator:[DeckNavigator new]];
}

在 RN 中使用这个自定义容器

Navigator.setRoot(
  {
    deck: [
      {
        tabs: [
          {
            screen: { moduleName: 'Navigation' },
          },
          {
            screen: { moduleName: 'Options' },
          },
        ],
      },
      {
        // 这一层总是在顶层
        screen: { moduleName: 'Transparent' },
      },
    ],
  },
  true
);

from hybrid-navigation.

listenzz avatar listenzz commented on June 1, 2024

Android 可以这么弄:

<!-- fragment_deck.xml -->
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/first"
        />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/second"
        />
</FrameLayout>
// DoubleDeckFragment.java
public class DoubleDeckFragment extends AwesomeFragment {

    private static final String SAVED_STATE_FIRST_TAG = "deck_first_tag";
    private static final String SAVED_STATE_SECOND_TAG = "deck_second_tag";

    private String firstTag;
    private String secondTag;

    @Override
    public boolean isParentFragment() {
        return true;
    }

    @Override
    protected AwesomeFragment childFragmentForAppearance() {
        return (AwesomeFragment) getChildFragmentManager().findFragmentById(R.id.second);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_deck, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (savedInstanceState == null) {
            if (firstDeckFragment == null || secondDeckFragment == null) {
                throw new IllegalArgumentException("必须设定 first and second deck");
            }

            FragmentHelper.addFragmentToAddedList(getChildFragmentManager(), R.id.second, secondDeckFragment,false);
            FragmentHelper.addFragmentToBackStack(getChildFragmentManager(), R.id.first, firstDeckFragment, PresentAnimation.None);
        } else {
            firstTag = savedInstanceState.getString(SAVED_STATE_FIRST_TAG);
            secondTag = savedInstanceState.getString(SAVED_STATE_SECOND_TAG);
            firstDeckFragment = (AwesomeFragment) getChildFragmentManager().findFragmentByTag(firstTag);
            secondDeckFragment = (AwesomeFragment) getChildFragmentManager().findFragmentByTag(secondTag);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(SAVED_STATE_FIRST_TAG, firstTag);
        outState.putString(SAVED_STATE_SECOND_TAG, secondTag);
    }

    @Nullable
    @Override
    public NavigationFragment getNavigationFragment() {
        if (!firstDeckFragment.isAdded()) {
            return null;
        }
        if (firstDeckFragment instanceof NavigationFragment) {
            return (NavigationFragment) firstDeckFragment;
        }
        return null;
    }

    private AwesomeFragment firstDeckFragment;

    public void setFirstDeckFragment(AwesomeFragment firstDeckFragment) {
        this.firstDeckFragment = firstDeckFragment;
        firstDeckFragment.setDefinesPresentationContext(true);
        this.firstTag = firstDeckFragment.getSceneId();
    }

    private AwesomeFragment secondDeckFragment;

    public void setSecondDeckFragment(AwesomeFragment secondDeckFragment) {
        this.secondDeckFragment = secondDeckFragment;
        this.secondTag = secondDeckFragment.getSceneId();
    }

    public AwesomeFragment getFirstDeckFragment() {
        return firstDeckFragment;
    }

    public AwesomeFragment getSecondDeckFragment() {
        return secondDeckFragment;
    }

    public AwesomeFragment getPrimaryFragment() {
        return (AwesomeFragment) getChildFragmentManager().findFragmentById(R.id.first);
    }
}
// DeckNavigator.java
public class DeckNavigator implements Navigator {

    private List<String> supportActions = Collections.emptyList();

    @Override
    public String name() {
        return "deck";
    }

    @Override
    public List<String> supportActions() {
        return supportActions;
    }

    @Nullable
    @Override
    public AwesomeFragment createFragment(ReadableMap layout) {
        if (layout.hasKey(name())) {
            ReadableArray deck = layout.getArray(name());
            if (deck.size() == 2) {
                ReadableMap first = deck.getMap(0);
                ReadableMap second = deck.getMap(1);
                AwesomeFragment firstFragment = getReactBridgeManager().createFragment(first);
                AwesomeFragment secondFragment = getReactBridgeManager().createFragment(second);
                DoubleDeckFragment doubleDeckFragment = new DoubleDeckFragment();
                doubleDeckFragment.setFirstDeckFragment(firstFragment);
                doubleDeckFragment.setSecondDeckFragment(secondFragment);
                return doubleDeckFragment;
            }
        }
        return null;
    }

    @Override
    public boolean buildRouteGraph(AwesomeFragment fragment, ArrayList<Bundle> graph, ArrayList<Bundle> modalContainer) {
        if (fragment instanceof DoubleDeckFragment) {
            DoubleDeckFragment deck = (DoubleDeckFragment) fragment;
            ArrayList<Bundle> children = new ArrayList<>();
            List<AwesomeFragment> fragments = deck.getChildFragmentsAtAddedList();
            for (int i = 0; i < fragments.size(); i++) {
                AwesomeFragment child = fragments.get(i);
                if (!child.getShowsDialog()) {
                    getReactBridgeManager().buildRouteGraph(child, children, modalContainer);
                }
            }

            Bundle bundle = new Bundle();
            bundle.putString("type", name());
            bundle.putParcelableArrayList(name(), children);
            graph.add(bundle);
            return true;
        }
        return false;
    }

    @Override
    public HybridFragment primaryChildFragment(@NonNull AwesomeFragment fragment) {
        if (fragment instanceof DoubleDeckFragment) {
            DoubleDeckFragment doubleDeckFragment = (DoubleDeckFragment) fragment;
            return getReactBridgeManager().primaryChildFragment(doubleDeckFragment.getPrimaryFragment());
        }
        return null;
    }

    @Override
    public void handleNavigation(@NonNull AwesomeFragment fragment, @NonNull String action, @NonNull ReadableMap extras) {

    }

    private ReactBridgeManager getReactBridgeManager() {
        return ReactBridgeManager.instance;
    }
}

注册这个 Navigator

public class MainApplication extends MultiDexApplication implements ReactApplication{
    
    @Override
    public void onCreate() {
        super.onCreate();
        SoLoader.init(this, false);

        ReactBridgeManager bridgeManager = ReactBridgeManager.instance;
        bridgeManager.install(getReactNativeHost());
        bridgeManager.registerNavigator(new DeckNavigator());

    }
}

from hybrid-navigation.

listenzz avatar listenzz commented on June 1, 2024

本库内置了 drawer、tabs、stack、screen 四个容器和对应的 Navigator, 如果有必要,完全可以自定义自己的容器和 Navigator.

from hybrid-navigation.

listenzz avatar listenzz commented on June 1, 2024

放在 deck 顶层的 component 需要设置背景透明,并允许事件穿透

  static navigationItem = {
    screenColor: '#00000000',
    passThroughTouches: true,
  };

from hybrid-navigation.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.