在集成了flutter_boost后,实现了flutter页面和iOS页面之间的互相跳转。如果我们又想在flutter页面中内嵌iOSView,我们需要怎么做?
native.dart,flutter混合原生view界面import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
/// flutter混合原生view
class CMNativePage extends StatelessWidget {
const CMNativePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: IOSCompositionWidget()
),
);
}
}
class IOSCompositionWidget extends StatelessWidget {
const IOSCompositionWidget({super.key});
@override
Widget build(BuildContext context) {
// This is used in the platform side to register the view.
const String viewType = 'custom_platform_view';
// Pass parameters to the platform side.
final Map<String, dynamic> creationParams = {'content': 'Flutter传给IOSView的参数'};
return UiKitView(
viewType: viewType,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
);
}
}
main.dart的路由表中,增加nativePage。供iOS原生进行跳转'nativePage': (settings, uniqueId) {
return PageRouteBuilder<dynamic>(
settings: settings,
pageBuilder: (_, __, ___) {
return const CMNativePage();
});
},
FLNativeView和FLNativeViewFactoryFLNativeView.h
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface FLNativeViewFactory : NSObject <FlutterPlatformViewFactory>
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
@end
@interface FLNativeView : NSObject <FlutterPlatformView>
@property (nonatomic, strong) UILabel *label;
- (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
@end
NS_ASSUME_NONNULL_END
FLNativeView.m
#import "FLNativeView.h"
@implementation FLNativeViewFactory {
NSObject<FlutterBinaryMessenger> *_messenger;
}
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
self = [super init];
if (self) {
_messenger = messenger;
}
return self;
}
- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args {
return [[FLNativeView alloc] initWithFrame:frame viewIdentifier:viewId arguments:args binaryMessenger:_messenger];
}
-(NSObject<FlutterMessageCodec> *)createArgsCodec{
return [FlutterStandardMessageCodec sharedInstance];
}
@end
@implementation FLNativeView
- (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
if (self = [super init]) {
self.label = [UILabel new];
self.label.textColor = [UIColor redColor];
NSDictionary *dict = (NSDictionary *)args;
NSString *textValue = dict[@"content"];
self.label.text = [NSString stringWithFormat:@"我是iOS View,传值:%@", textValue];
}
return self;
}
- (nonnull UIView *)view {
return self.label;
}
@end
FLNativeViewFactory中的createArgsCodec方法一定不能遗漏,否则会导致传值不成功。类型也一定要和Dart部分的native.dart->IOSCompositionWidget-> UiKitView-> creationParamsCodec保持一致。否则会导致崩溃:
AppDelegate.h:修改继承为FlutterAppDelegate,并删除window属性,因为FlutterAppDelegate中已经自带window属性#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>
@interface AppDelegate : FlutterAppDelegate
@end
AppDelegate.m中引入头文件#import "FLNativeView.h"
#import "GeneratedPluginRegistrant.h"
AppDelegate.m中注册插件,注意这里有非常大的坑。官方文档中是这么写的:- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
NSObject<FlutterPluginRegistrar>* registrar = [self registrarForPlugin:@"plugin-name"];
FLNativeViewFactory* factory = [[FLNativeViewFactory alloc] initWithMessenger:registrar.messenger];
[[self registrarForPlugin:@"<plugin-name>"] registerViewFactory:factory withId:@"<platform-view-type>"];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
这样写本身是没问题的,但是在引入flutter_boost的情况下,就不能这么写了!正确的做法是,需要等flutter_boost初始化完成后,用FlutterEngine对插件进行初始化!代码如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 初始化window
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *vc = [ViewController new];
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:vc];
self.window.rootViewController = navigation;
[self.window makeKeyAndVisible];
self.window.backgroundColor = [UIColor whiteColor];
// 初始化FlutterBoost
BoostDelegate *delegate = [BoostDelegate sharedInstance];
delegate.navigationController = (UINavigationController *)self.window.rootViewController;
[[FlutterBoost instance] setup:application delegate:delegate callback:^(FlutterEngine *engine) {
// 初始化Flutter内嵌iOSView插件
NSObject<FlutterPluginRegistrar> *registrar = [engine registrarForPlugin:@"custom_platform_view_plugin"];
FLNativeViewFactory *factory = [[FLNativeViewFactory alloc] initWithMessenger:registrar.messenger];
[registrar registerViewFactory:factory withId:@"custom_platform_view"];
}];
return YES;
}
如果按照官方相同的写法,跳转过去会一直是一个空白页面,不会有原生组件嵌入其中。这个问题,我查了很久网上都没有相关资料,希望能帮到后面遇到坑的人~
- 其中
withId:xxx,xxx代表控件的ID,需要和Dart部分的IOSCompositionWidget中的viewType保持一致。命名为:custom_platform_view- 其中
registrarForPlugin:xxx,xxx代表插件的ID。命名为:custom_platform_view_plugin
ViewController.m测试页面中,增加跳转Flutter页面的按钮和跳转方法- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UIButton *pushFlutterNativePageButton = [UIButton buttonWithType:UIButtonTypeSystem];
pushFlutterNativePageButton.frame = CGRectMake(100, 300, 300, 100);
[pushFlutterNativePageButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[pushFlutterNativePageButton setTitle:@"跳转到Flutter混合原生view界面" forState:UIControlStateNormal];
[pushFlutterNativePageButton addTarget:self action:@selector(pushFlutterNativePage) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:pushFlutterNativePageButton];
}
// 跳转Flutter混合原生view界面
- (void)pushFlutterNativePage{
FlutterBoostRouteOptions *options = [FlutterBoostRouteOptions new];
options.pageName = @"nativePage";
options.arguments = @{@"animated": @(YES)};
options.completion = ^(BOOL completion) {
};
[[FlutterBoost instance] open:options];
options.onPageFinished = ^(NSDictionary *dic) {
NSLog(@"%@", dic);
};
}

pod install,重新将FlutterModule导入到项目中。运行iOS项目,跳转后得到正确结果:
这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel
我一直很高兴地使用DelayedJob习惯用法:foo.send_later(:bar)这会调用DelayedJob进程中对象foo的方法bar。我一直在使用DaemonSpawn在我的服务器上启动DelayedJob进程。但是...如果foo抛出异常,Hoptoad不会捕获它。这是任何这些包中的错误...还是我需要更改某些配置...或者我是否需要在DS或DJ中插入一些异常处理来调用Hoptoad通知程序?回应下面的第一条评论。classDelayedJobWorker 最佳答案 尝试monkeypatchingDelayed::W
我最近决定从我的系统中卸载RVM。在thispage提出的一些论点说服我:实际上,我的决定是,我根本不想担心Ruby的多个版本。我只想使用1.9.2-p290版本而不用担心其他任何事情。但是,当我在我的Mac上运行ruby--version时,它告诉我我的版本是1.8.7。我四处寻找如何简单地从我的Mac上卸载这个Ruby,但奇怪的是我没有找到任何东西。似乎唯一想卸载Ruby的人运行linux,而使用Mac的每个人都推荐RVM。如何从我的Mac上卸载Ruby1.8.7?我想升级到1.9.2-p290版本,并且我希望我的系统上只有一个版本。 最佳答案
前置步骤我们都操作完了,这篇开始介绍jenkins的集成。话不多说,看操作1、登录进入jenkins后会让你选择安装插件,选择第一个默认的就行。安装完成后设置账号密码,重新登录。2、配置JDK和Git都需要执行路径,所以需要先把执行路径找到,先进入服务器的docker容器,2.1JDK的路径root@69eef9ee86cf:/usr/bin#echo$JAVA_HOME/usr/local/openjdk-82.2Git的路径root@69eef9ee86cf:/#whichgit/usr/bin/git3、先配置JDK和Git。点击:ManageJenkins>>GlobalToolCon
我正在学习Rails,对Sinatra和Merb知之甚少。我想知道您会在哪些情况下使用Merb/Sinatra。感谢您的反馈! 最佳答案 Sinatra是一个比Rails更小、更轻的框架。如果你想让一些东西快速运行,只需发送几个URL并返回一些简单的内容,就可以使用它。看看Sinatrahomepage;这就是启动和运行“Hello,World”所需的全部内容,而在Rails中,您需要生成整个项目结构、设置Controller和View、设置路由等等(我还没有有一段时间写了一个Rails应用程序,所以我不知道“Hello,World
s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成
假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl
因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实