extended_text_field 相關文章
最近有客戶Alex提出Flutter輸入框需要支持支持圖片和特殊文字樣式询枚,就跟QQ垫卤,微信,微博一樣藤乙,可以插入表情媒殉,@xxx或者一個話題. 每天追更,每天都在群里@我(FlutterCandies QQ群:181398081),就差點就把他禁言了盅粪。但是我沒有這樣做,客戶就是上帝苞氮,因為之前做過Extended Text湾揽,假裝感覺應該很簡單,悄悄在空閑的時候就動手做起來了。
本篇只介紹下用法库物,下一篇再講講開發(fā)中的辛酸歷程霸旗,先上效果圖。
使用步驟
關注民晒,點贊精居,轉發(fā),送飛機
pub 搜索 extended_text_field
github 地址:extended_text_field
定義自己的特殊文字
比如表情
我這里定義的格式是比如[1]潜必,就代表是表情1(就是你對應的表情圖片).
class EmojiText extends SpecialText {
static const String flag = "[";
final int start;
EmojiText(TextStyle textStyle, {this.start})
: super(EmojiText.flag, "]", textStyle);
@override
TextSpan finishText() {
// TODO: implement finishText
var key = toString();
if (EmojiUitl.instance.emojiMap.containsKey(key)) {
//fontsize id define image height
//size = 30.0/26.0 * fontSize
final double size = 20.0;
///fontSize 26 and text height =30.0
//final double fontSize = 26.0;
return ImageSpan(AssetImage(EmojiUitl.instance.emojiMap[key]),
actualText: key,
imageWidth: size,
imageHeight: size,
start: start,
deleteAll: true,
fit: BoxFit.fill,
margin: EdgeInsets.only(left: 2.0, top: 2.0, right: 2.0));
}
return TextSpan(text: toString(), style: textStyle);
}
}
class EmojiUitl {
final Map<String, String> _emojiMap = new Map<String, String>();
Map<String, String> get emojiMap => _emojiMap;
final String _emojiFilePath = "assets";
static EmojiUitl _instance;
static EmojiUitl get instance {
if (_instance == null) _instance = new EmojiUitl._();
return _instance;
}
EmojiUitl._() {
for (int i = 1; i < 49; i++) {
_emojiMap["[$i]"] = "$_emojiFilePath/$i.png";
}
}
}
再舉一個
比如 @法的空間
以@為開始標志靴姿,空格為結束標志
class AtText extends SpecialText {
static const String flag = "@";
final int start;
/// whether show background for @somebody
final bool showAtBackground;
final BuilderType type;
AtText(TextStyle textStyle, SpecialTextGestureTapCallback onTap,
{this.showAtBackground: false, this.type, this.start})
: super(flag, " ", textStyle, onTap: onTap);
@override
TextSpan finishText() {
// TODO: implement finishText
TextStyle textStyle =
this.textStyle?.copyWith(color: Colors.blue, fontSize: 16.0);
final String atText = toString();
if (type == BuilderType.extendedText)
return TextSpan(
text: atText,
style: textStyle,
recognizer: TapGestureRecognizer()
..onTap = () {
if (onTap != null) onTap(atText);
});
return showAtBackground
? BackgroundTextSpan(
background: Paint()..color = Colors.blue.withOpacity(0.15),
text: atText,
actualText: atText,
start: start,
deleteAll: false,
style: textStyle,
recognizer: type == BuilderType.extendedText
? (TapGestureRecognizer()
..onTap = () {
if (onTap != null) onTap(atText);
})
: null)
: SpecialTextSpan(
text: atText,
actualText: atText,
start: start,
deleteAll: false,
style: textStyle,
recognizer: type == BuilderType.extendedText
? (TapGestureRecognizer()
..onTap = () {
if (onTap != null) onTap(atText);
})
: null);
}
}
定義文字解析幫助類
必須實現(xiàn)createSpecialText方法,這樣才知道你有哪些特殊文字
一個是build的方法磁滚,可選實現(xiàn)佛吓。如果你自己實現(xiàn)了要注意,特殊TextSpan必須放在返回的TextSpan的children里面垂攘,我只會遍歷這一層维雇,不會再去查找children的children了。
class MySpecialTextSpanBuilder extends SpecialTextSpanBuilder {
/// whether show background for @somebody
final bool showAtBackground;
final BuilderType type;
MySpecialTextSpanBuilder(
{this.showAtBackground: false, this.type: BuilderType.extendedText});
@override
TextSpan build(String data, {TextStyle textStyle, onTap}) {
// TODO: implement build
var textSpan = super.build(data, textStyle: textStyle, onTap: onTap);
//for performance, make sure your all SpecialTextSpan are only in textSpan.children
//extended_text_field will only check SpecialTextSpan in textSpan.children
return textSpan;
}
@override
SpecialText createSpecialText(String flag,
{TextStyle textStyle, SpecialTextGestureTapCallback onTap, int index}) {
if (flag == null || flag == "") return null;
// TODO: implement createSpecialText
///index is end index of start flag, so text start index should be index-(flag.length-1)
if (isStart(flag, AtText.flag)) {
return AtText(textStyle, onTap,
start: index - (AtText.flag.length - 1),
showAtBackground: showAtBackground,
type: type);
} else if (isStart(flag, EmojiText.flag)) {
return EmojiText(textStyle, start: index - (EmojiText.flag.length - 1));
} else if (isStart(flag, DollarText.flag)) {
return DollarText(textStyle, onTap,
start: index - (DollarText.flag.length - 1), type: type);
} else if (isStart(flag, ImageText.flag)) {
return ImageText(textStyle,
start: index - (ImageText.flag.length - 1), type: type, onTap: onTap);
}
return null;
}
}
enum BuilderType { extendedText, extendedTextField }
使用ExtendedTextField
是不是炒雞簡單晒他,這樣你的文字就會自動轉換為對應的特殊文字類型了
ExtendedTextField(
specialTextSpanBuilder: MySpecialTextSpanBuilder(
showAtBackground: true, type: BuilderType.extendedTextField),
限制
跟readme上面講的一樣吱型,有三種限制。
- 不支持文字從右到左陨仅,也就是不支持TextDirection.rtl津滞。原因是TextPainter 給的圖片的位置,非常奇怪掂名,完全沒法搞据沈。當然我會繼續(xù)跟進,也許哪天官方修好了呢饺蔑?
- 不支持那種密碼的輸入樣式解析成特殊TextSpan锌介,也就是不支持obscureText 為true。沒啥好解釋猾警,文字都變成******了孔祸,也沒必要解析了。
- 代碼是基于flutter 版本1.5.7发皿,可能在不同的flutter 版本下面會出現(xiàn)編譯錯誤崔慧,如果出現(xiàn),希望老板們能根據(jù)自己的版本進行更正穴墅。我這邊不太可能都適配到每個flutter 版本惶室,我會盡量讓extended_text_field 在flutter 的穩(wěn)定版本上面沒有錯誤温自,希望諒解。
最后放上 extended_text_field皇钞,如果你有什么不明白或者對這個方案有什么改進的地方悼泌,請告訴我,歡迎加入Flutter Candies夹界,一起生產(chǎn)可愛的Flutter 小糖果(QQ群:181398081)
Flutter Candies全家桶
最最后放上Flutter Candies全家桶馆里,真香。
custom flutter candies(widgets) for you to easily build flutter app, enjoy it.