簡體   English   中英

如何從 FlutterViewController 中“推送”一個 UIViewController

[英]How can I “push” a UIViewController from FlutterViewController

我想在我們的 Flutter 視圖上“推送”一個新的原生視圖(Android 中的 Activity 和 iOS 中的 UIViewController),在新的原生視圖完成/完成后,讓屏幕回到我們的 Flutter 視圖。

我可以在 Android 中做到這一點。 但是我對 iOS 很陌生,當我嘗試在ios/Runner/AppDelegate.m執行此操作時:

  SwiftViewController *swiftViewController = [controller.storyboard instantiateViewControllerWithIdentifier:@"SwiftViewController"];
  [(FlutterViewController *)self.window.rootViewController pushViewController:swiftViewController animated:YES];

它給出了錯誤:

“FlutterViewController”沒有可見的@interface 聲明了選擇器“pushViewController:animated”

那么如何在iOS中做到這一點呢? 謝謝

在 Swift 中,我們可以使用方法通道從顫動動作事件中打開原生 iOS viewController,

  • 在 flutter 中,需要添加以下幾行來觸發 iOS 原生方法。 在您的操作方法中添加這些行
var platform = const MethodChannel('com.nativeActivity/iosChannel');
final String result = await platform.invokeMethod('StartNativeIOS');
  • 在 iOS 中,在 AppDelegate 應用程序方法中添加以下幾行
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController

let methodChannel = FlutterMethodChannel(name: "com.nativeActivity/iosChannel", binaryMessenger:controller.binaryMessenger)

methodChannel.setMethodCallHandler({
  (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
        
  if call.method == "StartNativeIOS" {
    let mainVC = MainViewController() // Your viewController
    let navigationController = UINavigationController(rootViewController: mainVC)
    self.window.rootViewController = navigationController
    self.window.makeKeyAndVisible()
  } else {
    result(FlutterMethodNotImplemented)
    return
  }
})

它會起作用! 歡呼

注意:但是沒有回到顫振視圖。

所以這是正確的方法。 使用協調器模式的顫振導航

pushViewController僅在您的控制器是navigation stack的一部分時才有效,即如果您的FlutterViewController嵌入在UINavigationController ,那么您可以像這樣從它push另一個控制器:

    self.navigationController?.pushViewController(swiftViewController, animated: true)

第二個選項是:如果FlutterViewController未嵌入UINavigationController ,您可以簡單地從它present另一個控制器,如下所示:

    self.present(swiftViewController, animated: true, completion: nil)

您需要以編程方式或在故事板中將 FlutterViewController 嵌入容器UINavigationController中,然后您將能夠推送您的下一個控制器。

以下是如何以編程方式嵌入的示例:

@interface AppDelegate()
@property (nonatomic, strong) UINavigationController *navigationController;
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];

  UIViewController *flutterViewController = [[FlutterViewController alloc] init];
  self.navigationController = [[UINavigationController alloc] initWithRootViewController:flutterViewController];
  [self.navigationController setNavigationBarHidden:YES];

  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  self.window.rootViewController = self.navigationController;
  [self.window makeKeyAndVisible];

  return true;
}

- (void)pushExample {
  UIViewController *viewController = [[UIViewController alloc] init];
  [self.navigationController pushViewController:viewController animated:true];
}

@end

需要時(例如點擊按鈕)調用pushExample 您也可以在此視頻中查看“故事板”方式

也許你可以看看webview插件。 與您的描述類似,它們啟動了一個新的 Activity 或 UIViewController。 顯然,您不需要啟動網絡視圖。

編寫自定義平台特定代碼

帶有按鈕的小部件。 點擊按鈕應該推送依賴消息以將視圖控制器推送到 iOS 應用程序。

class BodyWidget extends StatelessWidget {

  static const platform = const MethodChannel('samples.flutter.dev/navigation_channel');

  Future<void> _pushOnNative() async {
    try {
      Map parameters = Map();
      parameters["title"] = "Contact Details";
      parameters["name"] = "Bang Operator";
      parameters["so_profile_exists"] = true;
      await platform.invokeMethod('push',[parameters]);
    } on PlatformException catch (e) {
      print("Failed to communicate level: '${e.message}'.");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Center(
        child: FlatButton(
          textColor: Colors.white,
          color: Colors.red,
          onPressed: _pushOnNative,
          child: Text('Push Me'),
        )
    );
  }
}

在 iOS 應用端,我們需要觀察通道samples.flutter.dev/navigation_channel的方法 'push'。 我們也可以從 flutter 端傳遞參數,在這個例子中,我們傳遞一個 Map(Dart),它作為 NSDictionary(Obj-C) 接收

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];

  FlutterViewController *controller = (FlutterViewController*)self.window.rootViewController;
  UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];

  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  self.window.rootViewController = navigationController;
  [navigationController setNavigationBarHidden:YES animated:YES];
  [self.window makeKeyAndVisible];

  [self setupNavigationChannelCallbacksOnMessenger:controller
                           forNavigationController:navigationController];


  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (void)setupNavigationChannelCallbacksOnMessenger:(id<FlutterBinaryMessenger>)messenger
                           forNavigationController:(UINavigationController *)navigationController {
  FlutterMethodChannel* pushChannel = [FlutterMethodChannel
                                       methodChannelWithName:@"samples.flutter.dev/navigation_channel"
                                       binaryMessenger:messenger];

  [pushChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
    if ([call.method isEqualToString:@"push"] && [self getDictionaryFromArguments:call.arguments]) {
      NSDictionary *parameters = [self getDictionaryFromArguments:call.arguments];
      [self pushContactScreenWithInfo:parameters onNaivgationController:navigationController];
      result(@(true));
    } else {
      result(FlutterMethodNotImplemented);
    }
  }];
}

- (NSDictionary *)getDictionaryFromArguments:(id)arguments {
  if (![arguments isKindOfClass:[NSArray class]]) {
    return nil;
  }
  NSArray *argumentsArray = (NSArray *)arguments;
  if (argumentsArray.firstObject == nil || ![argumentsArray.firstObject isKindOfClass:[NSDictionary class]]) {
    return nil;
  }
  return (NSDictionary *)argumentsArray.firstObject;
}

- (void)pushContactScreenWithInfo:(NSDictionary *)info
          onNaivgationController:(UINavigationController *)navigationContorller {
  UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
  ContactViewController *controller = [storyboard instantiateViewControllerWithIdentifier:@"ContactViewController"];
  [navigationContorller pushViewController:controller animated:YES];
  [controller view];
  [controller configureWithInfo:info];
}

在 Swift 中,我們可以使用方法通道從 Flutter 動作事件中打開原生 iOS viewController,在 Flutter 中,您需要添加以下幾行來觸發原生 iOS 方法。 在您的操作方法中添加這些行

var platform = const MethodChannel('navigation');
final String result = await platform.invokeMethod('IOS');

在 iOS 中,在 AppDelegate 應用程序方法中添加以下幾行。

let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let methodChannel = FlutterMethodChannel(name: "navigation", binaryMessenger:controller.binaryMessenger)
navigationController = UINavigationController(rootViewController: controller)
navigationController.setNavigationBarHidden(true, animated: false)
self.window!.rootViewController = navigationController
self.window!.makeKeyAndVisible()
methodChannel.setMethodCallHandler({
    (call: FlutterMethodCall, result: @escaping FlutterResult) -> 
    Void in
if call.method == "IOS" {
      let vc = "Your viewController"(nibName: "Your 
      viewController", bundle: nil)
      navigationController.pushViewController(vc, animated: 
     false)
} else {
         result(FlutterMethodNotImplemented)
         return
}
})

本機視圖控制器后退按鈕操作。

self.navigationController?.popViewController(animated: true)

謝謝。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM