Skip to content

Commit

Permalink
fix maxLines usage and support dynamic content height
Browse files Browse the repository at this point in the history
  • Loading branch information
henryleunghk committed Dec 2, 2021
1 parent e53eb29 commit e9c6f14
Show file tree
Hide file tree
Showing 12 changed files with 73 additions and 82 deletions.
14 changes: 0 additions & 14 deletions .vscode/launch.json

This file was deleted.

4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 1.1.1

* fix maxLines usage and support dynamic content height

## 1.1.0

* support customizations
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Hope you find it useful and happy coding! 🎉🎉🎉
| `focusNode` | FocusNode | Defines the keyboard focus for this widget (https://api.flutter.dev/flutter/material/TextField/focusNode.html) | null |
| `textAlign` | TextAlign | How the text should be aligned horizontally (https://api.flutter.dev/flutter/material/TextField/textAlign.html) | TextAlign.start |
| `minLines` | int | Minimum number of lines of text input widget | 1 |
| `maxLines` | int | Maximum number of lines of text input body, 0 for no limit | 1 |
| `maxLines` | int | The maximum number of lines to show at one time, wrapping if necessary (https://api.flutter.dev/flutter/material/TextField/maxLines.html) | 1 |

## More examples

Expand Down
2 changes: 1 addition & 1 deletion example/ios/Flutter/Flutter.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

Pod::Spec.new do |s|
s.name = 'Flutter'
s.version = '1.1.0'
s.version = '1.0.0'
s.summary = 'High-performance, high-fidelity mobile apps.'
s.homepage = 'https://flutter.io'
s.license = { :type => 'MIT' }
Expand Down
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
PODS:
- Flutter (1.0.0)
- flutter_native_text_input (1.1.0):
- flutter_native_text_input (1.1.1):
- Flutter

DEPENDENCIES:
Expand All @@ -15,7 +15,7 @@ EXTERNAL SOURCES:

SPEC CHECKSUMS:
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_native_text_input: 43306ad878f964a10fceb4703f59128fe2c3e627
flutter_native_text_input: ad58457f1edbc889ed73bef09bfa6fd920817f8a

PODFILE CHECKSUM: 8e679eca47255a8ca8067c4c67aab20e64cb974d

Expand Down
4 changes: 2 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class HomePage extends StatelessWidget {
color: Colors.black54,
),
placeholderStyle: TextStyle(
fontSize: 14,
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black12,
),
Expand All @@ -84,7 +84,7 @@ class HomePage extends StatelessWidget {
color: Colors.black54,
),
placeholderStyle: TextStyle(
fontSize: 14,
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black12,
),
Expand Down
2 changes: 1 addition & 1 deletion example/lib/more_use_case_listing_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class _MoreUseCaseListingPageState extends State<MoreUseCaseListingPage> {
title: "Multiline Text Input",
child: NativeTextInput(
minLines: 3,
maxLines: 0,
maxLines: 5,
onChanged: _onChangeText,
onSubmitted: _onSubmittedText,
)),
Expand Down
14 changes: 12 additions & 2 deletions ios/Classes/NativeTextInput.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ @implementation NativeInputField {
int64_t _viewId;
FlutterMethodChannel* _channel;
NativeTextInputDelegate* _delegate;

float _containerWidth;
}


Expand All @@ -26,9 +28,11 @@ - (instancetype)initWithFrame:(CGRect)frame
_textView.keyboardAppearance = [self keyboardAppearanceFromString:args[@"keyboardAppearance"]];
_textView.keyboardType = [self keyboardTypeFromString:args[@"keyboardType"]];
_textView.textAlignment = [self textAlignmentFromString:args[@"textAlign"]];
_textView.textContainer.maximumNumberOfLines = [args[@"maxLines"] intValue];
_textView.textContainer.lineBreakMode = NSLineBreakByCharWrapping;

if ([args[@"maxLines"] intValue] == 1) {
_textView.textContainer.maximumNumberOfLines = 1;
}
if (@available(iOS 10.0, *)) {
_textView.textContentType = [self textContentTypeFromString:args[@"textContentType"]];
}
Expand All @@ -46,6 +50,8 @@ - (instancetype)initWithFrame:(CGRect)frame
_textView.font = _delegate.font;
}

_containerWidth = [args[@"width"] floatValue];

__weak __typeof__(self) weakSelf = self;
[_channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[weakSelf onMethodCall:call result:result];
Expand All @@ -55,7 +61,11 @@ - (instancetype)initWithFrame:(CGRect)frame
}

- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([[call method] isEqualToString:@"getLineHeight"]) {
if ([[call method] isEqualToString:@"getContentHeight"]) {
CGSize boundSize = CGSizeMake(_containerWidth, MAXFLOAT);
CGSize size = [_textView sizeThatFits: boundSize];
result([NSNumber numberWithFloat: size.height]);
} else if ([[call method] isEqualToString:@"getLineHeight"]) {
result([NSNumber numberWithFloat: _textView.font.lineHeight]);
} else if ([[call method] isEqualToString:@"unfocus"]) {
[self onUnFocus:call result:result];
Expand Down
38 changes: 12 additions & 26 deletions ios/Classes/NativeTextInputDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ @implementation NativeTextInputDelegate {
float _placeholderFontSize;
UIFontWeight _placeholderFontWeight;
UIColor* _placeholderFontColor;

CGRect _previousRect;
int _currentLineIndex;
}

- (instancetype)initWithChannel:(FlutterMethodChannel*)channel arguments:(id _Nullable)args {
Expand Down Expand Up @@ -54,8 +51,6 @@ - (instancetype)initWithChannel:(FlutterMethodChannel*)channel arguments:(id _Nu
if (self) {
_channel = channel;
_args = args;
_previousRect = CGRectZero;
_currentLineIndex = 1;
}
return self;
}
Expand Down Expand Up @@ -109,28 +104,20 @@ - (void)textViewDidBeginEditing:(UITextView *)textView {
textView.textColor = _fontColor;
textView.font = self.font;
}

if (textView.textContainer.maximumNumberOfLines == 1) {
textView.textContainer.lineBreakMode = NSLineBreakByCharWrapping;
}

[_channel invokeMethod:@"inputStarted"
arguments:nil];
}

- (void)textViewDidChange:(UITextView *)textView {
UITextPosition *position = [textView endOfDocument];
CGRect currentRect = [textView caretRectForPosition:position];

if (_previousRect.origin.y == 0.0 ) { _previousRect = currentRect; }

if (currentRect.origin.y > _previousRect.origin.y) {
_currentLineIndex += 1;
} else if (currentRect.origin.y < _previousRect.origin.y) {
_currentLineIndex -= 1;
}

_previousRect = currentRect;

textView.textColor = textView.text == 0 ? _placeholderFontColor : _fontColor;
textView.font = textView.text == 0 ? self.placeholderFont : self.font;

[_channel invokeMethod:@"inputValueChanged" arguments:@{ @"text": textView.text, @"currentLine": [NSNumber numberWithInt: _currentLineIndex] }];
[_channel invokeMethod:@"inputValueChanged" arguments:@{ @"text": textView.text }];
}

- (void)textViewDidEndEditing:(UITextView *)textView {
Expand All @@ -139,6 +126,11 @@ - (void)textViewDidEndEditing:(UITextView *)textView {
textView.textColor = _placeholderFontColor;
textView.font = self.placeholderFont;
}

if (textView.textContainer.maximumNumberOfLines == 1) {
textView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail;
}

[_channel invokeMethod:@"inputFinished"
arguments:@{ @"text": textView.text }];
}
Expand All @@ -150,14 +142,8 @@ - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range r
) {
[textView resignFirstResponder];
return false;
} else if (textView.textContainer.maximumNumberOfLines == 0) {
return true;
} else {
NSUInteger existingLines = [textView.text componentsSeparatedByString:@"\n"].count;
NSUInteger newLines = [text componentsSeparatedByString:@"\n"].count;
NSUInteger linesAfterChange = existingLines + newLines - 1;
return linesAfterChange <= textView.textContainer.maximumNumberOfLines;
}
return true;
}

@end
2 changes: 1 addition & 1 deletion ios/flutter_native_text_input.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
Pod::Spec.new do |s|
s.name = 'flutter_native_text_input'
s.version = '1.1.0'
s.version = '1.1.1'
s.summary = 'Native text input for Flutter'
s.description = <<-DESC
Native text input for Flutter
Expand Down
67 changes: 36 additions & 31 deletions lib/flutter_native_text_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ class _NativeTextInputState extends State<NativeTextInput> {
widget.focusNode ?? (_focusNode ??= FocusNode());

bool get _isMultiline => widget.maxLines == 0 || widget.maxLines > 1;
int? _currentLineIndex = 1;
double _lineHeight = 22.0;
double _contentHeight = 22.0;

@override
void initState() {
Expand All @@ -169,16 +169,18 @@ class _NativeTextInputState extends State<NativeTextInput> {
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
minHeight: _minHeight(),
maxHeight: _maxHeight(),
minHeight: _minHeight,
maxHeight: _maxHeight,
),
child: Container(
decoration: widget.decoration,
child: UiKitView(
viewType: "flutter_native_text_input",
creationParamsCodec: const StandardMessageCodec(),
creationParams: _buildCreationParams(),
onPlatformViewCreated: _createMethodChannel,
child: LayoutBuilder(
builder: (context, layout) => Container(
decoration: widget.decoration,
child: UiKitView(
viewType: "flutter_native_text_input",
creationParamsCodec: const StandardMessageCodec(),
creationParams: _buildCreationParams(layout),
onPlatformViewCreated: _createMethodChannel,
),
),
),
);
Expand All @@ -193,10 +195,17 @@ class _NativeTextInputState extends State<NativeTextInput> {
setState(() {});
}
});
_channel.invokeMethod("getContentHeight").then((value) {
if (value != null) {
_contentHeight = value;
setState(() {});
}
});
}

Map<String, dynamic> _buildCreationParams() {
Map<String, dynamic> _buildCreationParams(BoxConstraints constraints) {
Map<String, dynamic> params = {
"width": constraints.maxWidth,
"text": _effectiveController.text,
"placeholder": widget.placeholder ?? "",
"textContentType": widget.textContentType?.toString(),
Expand Down Expand Up @@ -286,17 +295,16 @@ class _NativeTextInputState extends State<NativeTextInput> {
"NativeTextInput._onMethodCall: No handler for ${call.method}");
}

double _minHeight() {
double height = widget.minLines * _lineHeight + 16;
return height > 36 ? height : 36;
}
double get _minHeight => (widget.minLines * _lineHeight) + 18;

double _maxHeight() {
return _isMultiline
? (_lineHeight * _currentLineIndex! > _minHeight()
? _lineHeight * _currentLineIndex!
: _minHeight())
: _minHeight();
double get _maxHeight {
if (!_isMultiline) return _minHeight;
if (_contentHeight > _minHeight && widget.maxLines > 0) {
double maxLineHeight = widget.maxLines * _lineHeight + 14;
return _contentHeight > maxLineHeight ? maxLineHeight : _contentHeight;
}
if (_contentHeight > _minHeight) return _contentHeight;
return _minHeight;
}

// input control methods
Expand All @@ -316,17 +324,14 @@ class _NativeTextInputState extends State<NativeTextInput> {
void _inputValueChanged(String? text, int? lineIndex) {
if (text != null) {
_effectiveController.text = text;
if (_isMultiline &&
_currentLineIndex != lineIndex &&
lineIndex! <= widget.maxLines) {
setState(() {
_currentLineIndex = lineIndex;
});
} else {
_currentLineIndex = 0;
}

if (widget.onChanged != null) widget.onChanged!(text);

_channel.invokeMethod("getContentHeight").then((value) {
if (value != null && value != _contentHeight) {
_contentHeight = value;
setState(() {});
}
});
}
}

Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: flutter_native_text_input
description: Native text input for Flutter. Currently iOS-only with the use of UITextView.

version: 1.1.0
version: 1.1.1
homepage: https://github.com/henryleunghk/flutter-native-text-input

environment:
Expand Down

0 comments on commit e9c6f14

Please sign in to comment.