@@ -60,6 +60,8 @@ @interface FlutterSecureTextInputView : FlutterTextInputView
60
60
61
61
@interface FlutterTextInputPlugin ()
62
62
@property (nonatomic , assign ) FlutterTextInputView* activeView;
63
+ @property (nonatomic , assign ) UIView* keyboardViewContainer;
64
+ @property (nonatomic , assign ) CGRect keyboardRect;
63
65
@property (nonatomic , readonly )
64
66
NSMutableDictionary <NSString*, FlutterTextInputView*>* autofillContext;
65
67
@@ -2315,4 +2317,186 @@ - (void)testSetPlatformViewClient {
2315
2317
XCTAssertNil (activeView.superview , @" activeView must be removed from view hierarchy." );
2316
2318
}
2317
2319
2320
+ - (void )testInteractiveKeyboardAfterUserScrollWillResignFirstResponder {
2321
+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
2322
+ [UIApplication.sharedApplication.keyWindow addSubview: inputView];
2323
+
2324
+ [inputView setTextInputClient: 123 ];
2325
+ [inputView reloadInputViews ];
2326
+ [inputView becomeFirstResponder ];
2327
+ XCTAssert (inputView.isFirstResponder );
2328
+
2329
+ CGRect keyboardFrame = CGRectMake (0 , 500 , 500 , 500 );
2330
+ [NSNotificationCenter .defaultCenter
2331
+ postNotificationName: UIKeyboardWillShowNotification
2332
+ object: nil
2333
+ userInfo: @{UIKeyboardFrameEndUserInfoKey : @(keyboardFrame)}];
2334
+ FlutterMethodCall* onPointerMoveCall =
2335
+ [FlutterMethodCall methodCallWithMethodName: @" TextInput.onPointerMoveForInteractiveKeyboard"
2336
+ arguments: @{@" pointerY" : @(500 )}];
2337
+ [textInputPlugin handleMethodCall: onPointerMoveCall
2338
+ result: ^(id _Nullable result){
2339
+ }];
2340
+ XCTAssertFalse (inputView.isFirstResponder );
2341
+ }
2342
+
2343
+ - (void )testInteractiveKeyboardAfterUserScrollToTopOfKeyboardWillTakeScreenshot {
2344
+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
2345
+ [UIApplication.sharedApplication.keyWindow addSubview: inputView];
2346
+
2347
+ [inputView setTextInputClient: 123 ];
2348
+ [inputView reloadInputViews ];
2349
+ [inputView becomeFirstResponder ];
2350
+ if (textInputPlugin.keyboardViewContainer .subviews .count != 0 ) {
2351
+ for (UIView* subView in textInputPlugin.keyboardViewContainer .subviews ) {
2352
+ [subView removeFromSuperview ];
2353
+ }
2354
+ }
2355
+ XCTAssert (textInputPlugin.keyboardViewContainer .subviews .count == 0 );
2356
+ CGRect keyboardFrame = CGRectMake (0 , 500 , 500 , 500 );
2357
+ [NSNotificationCenter .defaultCenter
2358
+ postNotificationName: UIKeyboardWillShowNotification
2359
+ object: nil
2360
+ userInfo: @{UIKeyboardFrameEndUserInfoKey : @(keyboardFrame)}];
2361
+ FlutterMethodCall* onPointerMoveCall =
2362
+ [FlutterMethodCall methodCallWithMethodName: @" TextInput.onPointerMoveForInteractiveKeyboard"
2363
+ arguments: @{@" pointerY" : @(510 )}];
2364
+ [textInputPlugin handleMethodCall: onPointerMoveCall
2365
+ result: ^(id _Nullable result){
2366
+ }];
2367
+ XCTAssertFalse (textInputPlugin.keyboardViewContainer .subviews .count == 0 );
2368
+ for (UIView* subView in textInputPlugin.keyboardViewContainer .subviews ) {
2369
+ [subView removeFromSuperview ];
2370
+ }
2371
+ }
2372
+
2373
+ - (void )testInteractiveKeyboardScreenshotWillBeMovedDownAfterUserScroll {
2374
+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
2375
+ [UIApplication.sharedApplication.keyWindow addSubview: inputView];
2376
+
2377
+ [inputView setTextInputClient: 123 ];
2378
+ [inputView reloadInputViews ];
2379
+ [inputView becomeFirstResponder ];
2380
+
2381
+ CGRect keyboardFrame = CGRectMake (0 , 500 , 500 , 500 );
2382
+ [NSNotificationCenter .defaultCenter
2383
+ postNotificationName: UIKeyboardWillShowNotification
2384
+ object: nil
2385
+ userInfo: @{UIKeyboardFrameEndUserInfoKey : @(keyboardFrame)}];
2386
+ FlutterMethodCall* onPointerMoveCall =
2387
+ [FlutterMethodCall methodCallWithMethodName: @" TextInput.onPointerMoveForInteractiveKeyboard"
2388
+ arguments: @{@" pointerY" : @(510 )}];
2389
+ [textInputPlugin handleMethodCall: onPointerMoveCall
2390
+ result: ^(id _Nullable result){
2391
+ }];
2392
+ XCTAssert (textInputPlugin.keyboardViewContainer .subviews .count == 1 );
2393
+
2394
+ XCTAssertEqual (textInputPlugin.keyboardViewContainer .frame .origin .y , keyboardFrame.origin .y );
2395
+
2396
+ FlutterMethodCall* onPointerMoveCallMove =
2397
+ [FlutterMethodCall methodCallWithMethodName: @" TextInput.onPointerMoveForInteractiveKeyboard"
2398
+ arguments: @{@" pointerY" : @(600 )}];
2399
+ [textInputPlugin handleMethodCall: onPointerMoveCallMove
2400
+ result: ^(id _Nullable result){
2401
+ }];
2402
+ XCTAssert (textInputPlugin.keyboardViewContainer .subviews .count == 1 );
2403
+ CGFloat newHeight = 600 ;
2404
+ XCTAssertEqual (textInputPlugin.keyboardViewContainer .frame .origin .y , newHeight);
2405
+
2406
+ for (UIView* subView in textInputPlugin.keyboardViewContainer .subviews ) {
2407
+ [subView removeFromSuperview ];
2408
+ }
2409
+ }
2410
+
2411
+ - (void )testInteractiveKeyboardScreenshotWillBeMovedUpAfterUserScroll {
2412
+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
2413
+ [UIApplication.sharedApplication.keyWindow addSubview: inputView];
2414
+
2415
+ [inputView setTextInputClient: 123 ];
2416
+ [inputView reloadInputViews ];
2417
+ [inputView becomeFirstResponder ];
2418
+
2419
+ CGRect keyboardFrame = CGRectMake (0 , 500 , 500 , 500 );
2420
+ [NSNotificationCenter .defaultCenter
2421
+ postNotificationName: UIKeyboardWillShowNotification
2422
+ object: nil
2423
+ userInfo: @{UIKeyboardFrameEndUserInfoKey : @(keyboardFrame)}];
2424
+ FlutterMethodCall* onPointerMoveCall =
2425
+ [FlutterMethodCall methodCallWithMethodName: @" TextInput.onPointerMoveForInteractiveKeyboard"
2426
+ arguments: @{@" pointerY" : @(500 )}];
2427
+ [textInputPlugin handleMethodCall: onPointerMoveCall
2428
+ result: ^(id _Nullable result){
2429
+ }];
2430
+ XCTAssert (textInputPlugin.keyboardViewContainer .subviews .count == 1 );
2431
+ XCTAssertEqual (textInputPlugin.keyboardViewContainer .frame .origin .y , keyboardFrame.origin .y );
2432
+
2433
+ FlutterMethodCall* onPointerMoveCallMove =
2434
+ [FlutterMethodCall methodCallWithMethodName: @" TextInput.onPointerMoveForInteractiveKeyboard"
2435
+ arguments: @{@" pointerY" : @(600 )}];
2436
+ [textInputPlugin handleMethodCall: onPointerMoveCallMove
2437
+ result: ^(id _Nullable result){
2438
+ }];
2439
+ XCTAssert (textInputPlugin.keyboardViewContainer .subviews .count == 1 );
2440
+ CGFloat newHeight = 600 ;
2441
+ XCTAssertEqual (textInputPlugin.keyboardViewContainer .frame .origin .y , newHeight);
2442
+
2443
+ FlutterMethodCall* onPointerMoveCallBackUp =
2444
+ [FlutterMethodCall methodCallWithMethodName: @" TextInput.onPointerMoveForInteractiveKeyboard"
2445
+ arguments: @{@" pointerY" : @(10 )}];
2446
+ [textInputPlugin handleMethodCall: onPointerMoveCallBackUp
2447
+ result: ^(id _Nullable result){
2448
+ }];
2449
+ XCTAssert (textInputPlugin.keyboardViewContainer .subviews .count == 1 );
2450
+ XCTAssertEqual (textInputPlugin.keyboardViewContainer .frame .origin .y , keyboardFrame.origin .y );
2451
+ for (UIView* subView in textInputPlugin.keyboardViewContainer .subviews ) {
2452
+ [subView removeFromSuperview ];
2453
+ }
2454
+ }
2455
+
2456
+ - (void )testInteractiveKeyboardFindFirstResponderRecursive {
2457
+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
2458
+ [UIApplication.sharedApplication.keyWindow addSubview: inputView];
2459
+ [inputView setTextInputClient: 123 ];
2460
+ [inputView reloadInputViews ];
2461
+ [inputView becomeFirstResponder ];
2462
+
2463
+ UIView* firstResponder = UIApplication.sharedApplication .keyWindow .flt_firstResponder ;
2464
+ XCTAssertEqualObjects (inputView, firstResponder);
2465
+ }
2466
+
2467
+ - (void )testInteractiveKeyboardFindFirstResponderRecursiveInMultipleSubviews {
2468
+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
2469
+ FlutterTextInputView* subInputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
2470
+ FlutterTextInputView* otherSubInputView =
2471
+ [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
2472
+ FlutterTextInputView* subFirstResponderInputView =
2473
+ [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
2474
+ [subInputView addSubview: subFirstResponderInputView];
2475
+ [inputView addSubview: subInputView];
2476
+ [inputView addSubview: otherSubInputView];
2477
+ [UIApplication.sharedApplication.keyWindow addSubview: inputView];
2478
+ [inputView setTextInputClient: 123 ];
2479
+ [inputView reloadInputViews ];
2480
+ [subInputView setTextInputClient: 123 ];
2481
+ [subInputView reloadInputViews ];
2482
+ [otherSubInputView setTextInputClient: 123 ];
2483
+ [otherSubInputView reloadInputViews ];
2484
+ [subFirstResponderInputView setTextInputClient: 123 ];
2485
+ [subFirstResponderInputView reloadInputViews ];
2486
+ [subFirstResponderInputView becomeFirstResponder ];
2487
+
2488
+ UIView* firstResponder = UIApplication.sharedApplication .keyWindow .flt_firstResponder ;
2489
+ XCTAssertEqualObjects (subFirstResponderInputView, firstResponder);
2490
+ }
2491
+
2492
+ - (void )testInteractiveKeyboardFindFirstResponderIsNilRecursive {
2493
+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
2494
+ [UIApplication.sharedApplication.keyWindow addSubview: inputView];
2495
+ [inputView setTextInputClient: 123 ];
2496
+ [inputView reloadInputViews ];
2497
+
2498
+ UIView* firstResponder = UIApplication.sharedApplication .keyWindow .flt_firstResponder ;
2499
+ XCTAssertNil (firstResponder);
2500
+ }
2501
+
2318
2502
@end
0 commit comments