Reputation: 33
Here is the image i am trying to build. Tried Stack
with Alignment.topRight
but i need to build a TextField
after the IconButton
that's the bottleneck.
Little details: The grey box is the input field, which i will append some static text at start, as you can see in the pic below. Static Text = Happy Birthday, then the button with cross icon and after that a TextField as shown in the design.
I tried different approaches but not coming-up with accurate results.
Row(
children: [
Container(
margin: const EdgeInsets.only(top: 5, left: 5),
padding: const EdgeInsets.only(top: 10, left: 10, bottom: 10),
decoration:
BoxDecoration(color: Constants.colorWhite.withOpacity(0.90)),
child: Text(Constants.happyBirthday),
),
Container(
margin: const EdgeInsets.only(top: 5, right: 0),
padding:
const EdgeInsets.only(left: 5, top: 10, right: 0, bottom: 10),
decoration:
BoxDecoration(color: Constants.colorWhite.withOpacity(0.50)),
child: Stack(
children: [
Text(widget.userName.toString()),
const Positioned(top: 0, right: 0, child: Icon(Icons.close))
],
)),
Container(
margin: const EdgeInsets.only(top: 5, left: 0),
padding: const EdgeInsets.only(top: 10, left: 10, bottom: 10),
decoration:
BoxDecoration(color: Constants.colorWhite.withOpacity(0.90)),
child: Text('${Constants.happyBirthday} '
'${Constants.happyBirthday}'
'${Constants.happyBirthday}'),
),
],
)
Upvotes: 0
Views: 145
Reputation: 2490
You can create your own TextEditingController
and override buildTextSpan
.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
/// @techbusiness
///
/// NOTE: Needs to be improved. Feel free to play with the styling
/// to get your desired result. This is just to show you the
/// possibility of your design.
class TaggerTextEditingController extends TextEditingController {
TaggerTextEditingController({
this.onPressTag,
this.onDeleteTag,
this.tagger = '@',
this.tagStyle,
this.tagBackgroundColor,
this.deleteIconSize = 15,
super.text,
});
final ValueChanged<String>? onPressTag;
final ValueChanged<String>? onDeleteTag;
final String tagger;
final TextStyle? tagStyle;
final Color? tagBackgroundColor;
final double deleteIconSize;
void _onDeleteTag(String tag) {
text = text.replaceFirst(tag, '');
onDeleteTag?.call(tag.replaceFirst(tagger, ''));
}
WidgetSpan _buildTag(String tag, TextStyle? style) => WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Stack(
clipBehavior: Clip.none,
children: <Widget>[
InkWell(
onTap: () => onPressTag?.call(tag.replaceFirst(tagger, '')),
borderRadius: const BorderRadius.all(Radius.circular(15)),
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(15)),
color: tagBackgroundColor ?? Colors.grey.shade200,
),
child: Text(
tag.replaceFirst(tagger, ''),
style: style,
),
),
),
Positioned(
top: -deleteIconSize / 4,
right: -deleteIconSize / 4,
child: GestureDetector(
onTap: () => _onDeleteTag(tag),
child: Icon(
CupertinoIcons.xmark_circle_fill,
size: deleteIconSize,
color: Colors.red,
),
),
),
],
),
);
@override
TextSpan buildTextSpan({
required BuildContext context,
TextStyle? style,
required bool withComposing,
}) {
final List<TaggerText> texts = TaggerText.getTags(text, tagger);
return TextSpan(
children: texts
.map(
(TaggerText value) => value.isTag
? _buildTag(value.text, tagStyle ?? style)
: TextSpan(
text: value.text,
style: style,
),
)
.toList(),
);
}
}
//------------------------------------------------------------------------------
class TaggerText {
const TaggerText(this.text, this.isTag);
final String text;
final bool isTag;
static List<TaggerText> getTags(String text, String tagger) {
final List<TaggerText> tags = <TaggerText>[];
StringBuffer textPortion = StringBuffer();
String prevChar = '';
bool isTextPortionATag() => textPortion.toString().startsWith(tagger);
void addTaggerText() => tags.add(
TaggerText(textPortion.toString(), isTextPortionATag()),
);
for (final String char in text.characters) {
if (char == tagger && prevChar == ' ') {
addTaggerText();
textPortion.clear();
} else if (char == ' ' && isTextPortionATag()) {
addTaggerText();
textPortion.clear();
}
textPortion.write(char);
prevChar = char;
}
if (textPortion.isNotEmpty) {
addTaggerText();
}
return tags;
}
}
How to use.
TextField(
controller: TaggerTextEditingController(),
maxLines: 5,
),
Upvotes: 1