wurong
2 years ago
11 changed files with 279 additions and 744 deletions
After Width: | Height: | Size: 786 B |
After Width: | Height: | Size: 946 B |
After Width: | Height: | Size: 640 B |
@ -1,53 +0,0 @@ |
|||||||
import 'package:extended_text/extended_text.dart'; |
|
||||||
import 'package:flutter/material.dart'; |
|
||||||
|
|
||||||
///emoji/image text |
|
||||||
class EmojiText extends SpecialText { |
|
||||||
static const String flag = "["; |
|
||||||
final int start; |
|
||||||
EmojiText(TextStyle textStyle, {this.start}) |
|
||||||
: super(EmojiText.flag, "]", textStyle); |
|
||||||
|
|
||||||
@override |
|
||||||
InlineSpan 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, |
|
||||||
fit: BoxFit.fill, |
|
||||||
margin: EdgeInsets.only(left: 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/images/emoji"; |
|
||||||
|
|
||||||
static EmojiUitl _instance; |
|
||||||
static EmojiUitl get instance { |
|
||||||
if (_instance == null) _instance = new EmojiUitl._(); |
|
||||||
return _instance; |
|
||||||
} |
|
||||||
|
|
||||||
EmojiUitl._() { |
|
||||||
for (int i = 1; i < 100; i++) { |
|
||||||
_emojiMap["[$i]"] = "$_emojiFilePath/sg$i.png"; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,466 +0,0 @@ |
|||||||
import 'package:flutter/material.dart'; |
|
||||||
import 'package:huixiang/message/im/im_view/triangle_painter.dart'; |
|
||||||
|
|
||||||
const double _kMenuScreenPadding = 8.0; |
|
||||||
|
|
||||||
class MagicPop extends StatefulWidget { |
|
||||||
MagicPop({ |
|
||||||
@required this.onValueChanged, |
|
||||||
@required this.actions, |
|
||||||
@required this.child, |
|
||||||
this.pressType = PressType.longPress, |
|
||||||
this.pageMaxChildCount = 5, |
|
||||||
this.backgroundColor = Colors.black, |
|
||||||
this.menuWidth = 250, |
|
||||||
this.menuHeight = 42, |
|
||||||
}) : assert(onValueChanged != null), |
|
||||||
assert(actions != null && actions.length > 0), |
|
||||||
assert(child != null); |
|
||||||
|
|
||||||
final ValueChanged<int> onValueChanged; |
|
||||||
final List<String> actions; |
|
||||||
final Widget child; |
|
||||||
final PressType pressType; // 点击方式 长按 还是单击 |
|
||||||
final int pageMaxChildCount; |
|
||||||
final Color backgroundColor; |
|
||||||
final double menuWidth; |
|
||||||
final double menuHeight; |
|
||||||
|
|
||||||
@override |
|
||||||
_WPopupMenuState createState() => _WPopupMenuState(); |
|
||||||
} |
|
||||||
|
|
||||||
class _WPopupMenuState extends State<MagicPop> { |
|
||||||
@override |
|
||||||
Widget build(BuildContext context) { |
|
||||||
return GestureDetector( |
|
||||||
child: widget.child, |
|
||||||
onTap: () { |
|
||||||
if (widget.pressType == PressType.singleClick) { |
|
||||||
onTap(); |
|
||||||
} |
|
||||||
}, |
|
||||||
onLongPress: () { |
|
||||||
if (widget.pressType == PressType.longPress) { |
|
||||||
onTap(); |
|
||||||
} |
|
||||||
}, |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
void onTap() { |
|
||||||
Navigator.push( |
|
||||||
context, |
|
||||||
_PopupMenuRoute(context, widget.actions, widget.pageMaxChildCount, |
|
||||||
widget.backgroundColor, widget.menuWidth, widget.menuHeight)) |
|
||||||
.then((index) { |
|
||||||
widget.onValueChanged(index); |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
enum PressType { |
|
||||||
// 长按 |
|
||||||
longPress, |
|
||||||
// 单击 |
|
||||||
singleClick, |
|
||||||
} |
|
||||||
|
|
||||||
class _PopupMenuRoute extends PopupRoute { |
|
||||||
final BuildContext btnContext; |
|
||||||
double _height; |
|
||||||
double _width; |
|
||||||
final List<String> actions; |
|
||||||
final int _pageMaxChildCount; |
|
||||||
final Color backgroundColor; |
|
||||||
final double menuWidth; |
|
||||||
final double menuHeight; |
|
||||||
|
|
||||||
_PopupMenuRoute(this.btnContext, this.actions, this._pageMaxChildCount, |
|
||||||
this.backgroundColor, this.menuWidth, this.menuHeight) { |
|
||||||
_height = btnContext.size.height; |
|
||||||
_width = btnContext.size.width; |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
Animation<double> createAnimation() { |
|
||||||
return CurvedAnimation( |
|
||||||
parent: super.createAnimation(), |
|
||||||
curve: Curves.linear, |
|
||||||
reverseCurve: const Interval(0.0, 2.0 / 3.0), |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
Color get barrierColor => null; |
|
||||||
|
|
||||||
@override |
|
||||||
bool get barrierDismissible => true; |
|
||||||
|
|
||||||
@override |
|
||||||
String get barrierLabel => null; |
|
||||||
|
|
||||||
@override |
|
||||||
Widget buildPage(BuildContext context, Animation<double> animation, |
|
||||||
Animation<double> secondaryAnimation) { |
|
||||||
return _MenuPopWidget(this.btnContext, _height, _width, actions, |
|
||||||
_pageMaxChildCount, backgroundColor, menuWidth, menuHeight); |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
Duration get transitionDuration => Duration(milliseconds: 300); |
|
||||||
} |
|
||||||
|
|
||||||
class _MenuPopWidget extends StatefulWidget { |
|
||||||
final BuildContext btnContext; |
|
||||||
final double _height; |
|
||||||
final double _width; |
|
||||||
final List<String> actions; |
|
||||||
final int _pageMaxChildCount; |
|
||||||
final Color backgroundColor; |
|
||||||
final double menuWidth; |
|
||||||
final double menuHeight; |
|
||||||
|
|
||||||
_MenuPopWidget( |
|
||||||
this.btnContext, |
|
||||||
this._height, |
|
||||||
this._width, |
|
||||||
this.actions, |
|
||||||
this._pageMaxChildCount, |
|
||||||
this.backgroundColor, |
|
||||||
this.menuWidth, |
|
||||||
this.menuHeight); |
|
||||||
|
|
||||||
@override |
|
||||||
__MenuPopWidgetState createState() => __MenuPopWidgetState(); |
|
||||||
} |
|
||||||
|
|
||||||
class __MenuPopWidgetState extends State<_MenuPopWidget> { |
|
||||||
int _curPage = 0; |
|
||||||
final double _arrowWidth = 40; |
|
||||||
final double _separatorWidth = 1; |
|
||||||
final double _triangleHeight = 10; |
|
||||||
|
|
||||||
RenderBox button; |
|
||||||
RenderBox overlay; |
|
||||||
RelativeRect position; |
|
||||||
|
|
||||||
@override |
|
||||||
void initState() { |
|
||||||
super.initState(); |
|
||||||
button = widget.btnContext.findRenderObject(); |
|
||||||
overlay = Overlay.of(widget.btnContext).context.findRenderObject(); |
|
||||||
position = RelativeRect.fromRect( |
|
||||||
Rect.fromPoints( |
|
||||||
button.localToGlobal(Offset.zero, ancestor: overlay), |
|
||||||
button.localToGlobal(Offset.zero, ancestor: overlay), |
|
||||||
), |
|
||||||
Offset.zero & overlay.size, |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
Widget build(BuildContext context) { |
|
||||||
// 这里计算出来 当前页的 child 一共有多少个 |
|
||||||
int _curPageChildCount = |
|
||||||
(_curPage + 1) * widget._pageMaxChildCount > widget.actions.length |
|
||||||
? widget.actions.length % widget._pageMaxChildCount |
|
||||||
: widget._pageMaxChildCount; |
|
||||||
|
|
||||||
double _curArrowWidth = 0; |
|
||||||
int _curArrowCount = 0; // 一共几个箭头 |
|
||||||
|
|
||||||
if (widget.actions.length > widget._pageMaxChildCount) { |
|
||||||
// 数据长度大于 widget._pageMaxChildCount |
|
||||||
if (_curPage == 0) { |
|
||||||
// 如果是第一页 |
|
||||||
_curArrowWidth = _arrowWidth; |
|
||||||
_curArrowCount = 1; |
|
||||||
} else { |
|
||||||
// 如果不是第一页 则需要也显示左箭头 |
|
||||||
_curArrowWidth = _arrowWidth * 2; |
|
||||||
_curArrowCount = 2; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
double _curPageWidth = widget.menuWidth + |
|
||||||
(_curPageChildCount - 1 + _curArrowCount) * _separatorWidth + |
|
||||||
_curArrowWidth; |
|
||||||
|
|
||||||
// ignore: unused_element |
|
||||||
Widget view() { |
|
||||||
var isInverted = (position.top + |
|
||||||
(MediaQuery.of(context).size.height - |
|
||||||
position.top - |
|
||||||
position.bottom) / |
|
||||||
2.0 - |
|
||||||
(widget.menuHeight + _triangleHeight)) < |
|
||||||
(widget.menuHeight + _triangleHeight) * 2; |
|
||||||
|
|
||||||
var pain = CustomPaint( |
|
||||||
size: Size(_curPageWidth, _triangleHeight), |
|
||||||
painter: TrianglePainter( |
|
||||||
color: widget.backgroundColor, |
|
||||||
position: position, |
|
||||||
isInverted: true, |
|
||||||
size: button.size), |
|
||||||
); |
|
||||||
|
|
||||||
var row = Row( |
|
||||||
mainAxisSize: MainAxisSize.min, |
|
||||||
children: <Widget>[ |
|
||||||
// 左箭头:判断是否是第一页,如果是第一页则不显示 |
|
||||||
_curPage == 0 |
|
||||||
? Container( |
|
||||||
height: widget.menuHeight, |
|
||||||
) |
|
||||||
: InkWell( |
|
||||||
onTap: () { |
|
||||||
setState(() { |
|
||||||
_curPage--; |
|
||||||
}); |
|
||||||
}, |
|
||||||
child: Container( |
|
||||||
width: _arrowWidth, |
|
||||||
height: widget.menuHeight, |
|
||||||
child: Image.asset( |
|
||||||
'images/left_white.png', |
|
||||||
fit: BoxFit.none, |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
// 左箭头:判断是否是第一页,如果是第一页则不显示 |
|
||||||
_curPage == 0 |
|
||||||
? Container( |
|
||||||
height: widget.menuHeight, |
|
||||||
) |
|
||||||
: Container( |
|
||||||
width: 1, |
|
||||||
height: widget.menuHeight, |
|
||||||
color: Colors.grey, |
|
||||||
), |
|
||||||
|
|
||||||
// 中间是ListView |
|
||||||
_buildList(_curPageChildCount, _curPageWidth, _curArrowWidth, |
|
||||||
_curArrowCount), |
|
||||||
|
|
||||||
// 右箭头:判断是否有箭头,如果有就显示,没有就不显示 |
|
||||||
_curArrowCount > 0 |
|
||||||
? Container( |
|
||||||
width: 1, |
|
||||||
color: Colors.grey, |
|
||||||
height: widget.menuHeight, |
|
||||||
) |
|
||||||
: Container( |
|
||||||
height: widget.menuHeight, |
|
||||||
), |
|
||||||
_curArrowCount > 0 |
|
||||||
? InkWell( |
|
||||||
onTap: () { |
|
||||||
if ((_curPage + 1) * widget._pageMaxChildCount < |
|
||||||
widget.actions.length) |
|
||||||
setState(() { |
|
||||||
_curPage++; |
|
||||||
}); |
|
||||||
}, |
|
||||||
child: Container( |
|
||||||
width: _arrowWidth, |
|
||||||
height: widget.menuHeight, |
|
||||||
child: Image.asset( |
|
||||||
(_curPage + 1) * widget._pageMaxChildCount >= |
|
||||||
widget.actions.length |
|
||||||
? 'images/right_gray.png' |
|
||||||
: 'images/right_white.png', |
|
||||||
fit: BoxFit.none, |
|
||||||
), |
|
||||||
), |
|
||||||
) |
|
||||||
: Container( |
|
||||||
height: widget.menuHeight, |
|
||||||
), |
|
||||||
], |
|
||||||
); |
|
||||||
|
|
||||||
return Material( |
|
||||||
color: Colors.transparent, |
|
||||||
child: Column( |
|
||||||
mainAxisSize: MainAxisSize.min, |
|
||||||
children: <Widget>[ |
|
||||||
isInverted ? pain : Container(), |
|
||||||
Expanded( |
|
||||||
child: Stack( |
|
||||||
children: <Widget>[ |
|
||||||
ClipRRect( |
|
||||||
borderRadius: BorderRadius.all(Radius.circular(5)), |
|
||||||
child: Container( |
|
||||||
color: widget.backgroundColor, |
|
||||||
height: widget.menuHeight, |
|
||||||
), |
|
||||||
), |
|
||||||
row, |
|
||||||
], |
|
||||||
), |
|
||||||
), |
|
||||||
isInverted |
|
||||||
? Container() |
|
||||||
: CustomPaint( |
|
||||||
size: Size(_curPageWidth, _triangleHeight), |
|
||||||
painter: TrianglePainter( |
|
||||||
color: widget.backgroundColor, |
|
||||||
position: position, |
|
||||||
size: button.size), |
|
||||||
), |
|
||||||
], |
|
||||||
), |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
return MediaQuery.removePadding( |
|
||||||
context: context, |
|
||||||
removeTop: true, |
|
||||||
removeBottom: true, |
|
||||||
removeLeft: true, |
|
||||||
removeRight: true, |
|
||||||
child: Builder( |
|
||||||
builder: (BuildContext context) { |
|
||||||
return CustomSingleChildLayout( |
|
||||||
// 这里计算偏移量 |
|
||||||
delegate: _PopupMenuRouteLayout( |
|
||||||
position, |
|
||||||
widget.menuHeight + _triangleHeight, |
|
||||||
Directionality.of(widget.btnContext), |
|
||||||
widget._width, |
|
||||||
widget.menuWidth), |
|
||||||
child: SizedBox( |
|
||||||
height: widget.menuHeight + _triangleHeight, |
|
||||||
width: _curPageWidth, |
|
||||||
child: view()), |
|
||||||
); |
|
||||||
}, |
|
||||||
), |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
Widget _buildList(int _curPageChildCount, double _curPageWidth, |
|
||||||
double _curArrowWidth, int _curArrowCount) { |
|
||||||
return ListView.separated( |
|
||||||
shrinkWrap: true, |
|
||||||
physics: NeverScrollableScrollPhysics(), |
|
||||||
scrollDirection: Axis.horizontal, |
|
||||||
itemCount: _curPageChildCount, |
|
||||||
itemBuilder: (BuildContext context, int index) { |
|
||||||
return InkWell( |
|
||||||
onTap: () { |
|
||||||
Navigator.pop( |
|
||||||
context, _curPage * widget._pageMaxChildCount + index); |
|
||||||
}, |
|
||||||
child: SizedBox( |
|
||||||
width: (_curPageWidth - |
|
||||||
_curArrowWidth - |
|
||||||
(_curPageChildCount - 1 + _curArrowCount) * |
|
||||||
_separatorWidth) / |
|
||||||
_curPageChildCount, |
|
||||||
height: widget.menuHeight, |
|
||||||
child: Center( |
|
||||||
child: Text( |
|
||||||
widget.actions[_curPage * widget._pageMaxChildCount + index], |
|
||||||
style: TextStyle(color: Colors.white, fontSize: 16), |
|
||||||
), |
|
||||||
), |
|
||||||
), |
|
||||||
); |
|
||||||
}, |
|
||||||
separatorBuilder: (BuildContext context, int index) { |
|
||||||
return Container( |
|
||||||
width: 1, |
|
||||||
height: widget.menuHeight, |
|
||||||
color: Colors.grey, |
|
||||||
); |
|
||||||
}, |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Positioning of the menu on the screen. |
|
||||||
class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { |
|
||||||
_PopupMenuRouteLayout(this.position, this.selectedItemOffset, |
|
||||||
this.textDirection, this.width, this.menuWidth); |
|
||||||
|
|
||||||
// Rectangle of underlying button, relative to the overlay's dimensions. |
|
||||||
final RelativeRect position; |
|
||||||
|
|
||||||
// The distance from the top of the menu to the middle of selected item. |
|
||||||
// |
|
||||||
// This will be null if there's no item to position in this way. |
|
||||||
final double selectedItemOffset; |
|
||||||
|
|
||||||
// Whether to prefer going to the left or to the right. |
|
||||||
final TextDirection textDirection; |
|
||||||
|
|
||||||
final double width; |
|
||||||
final double menuWidth; |
|
||||||
|
|
||||||
// We put the child wherever position specifies, so long as it will fit within |
|
||||||
// the specified parent size padded (inset) by 8. If necessary, we adjust the |
|
||||||
// child's position so that it fits. |
|
||||||
|
|
||||||
@override |
|
||||||
BoxConstraints getConstraintsForChild(BoxConstraints constraints) { |
|
||||||
// The menu can be at most the size of the overlay minus 8.0 pixels in each |
|
||||||
// direction. |
|
||||||
return BoxConstraints.loose(constraints.biggest - |
|
||||||
const Offset(_kMenuScreenPadding * 2.0, _kMenuScreenPadding * 2.0)); |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
Offset getPositionForChild(Size size, Size childSize) { |
|
||||||
// size: The size of the overlay. |
|
||||||
// childSize: The size of the menu, when fully open, as determined by |
|
||||||
// getConstraintsForChild. |
|
||||||
|
|
||||||
// Find the ideal vertical position. |
|
||||||
double y; |
|
||||||
if (selectedItemOffset == null) { |
|
||||||
y = position.top; |
|
||||||
} else { |
|
||||||
y = position.top + |
|
||||||
(size.height - position.top - position.bottom) / 2.0 - |
|
||||||
selectedItemOffset; |
|
||||||
} |
|
||||||
|
|
||||||
// Find the ideal horizontal position. |
|
||||||
double x; |
|
||||||
if (position.left > position.right) { |
|
||||||
// Menu button is closer to the right edge, so grow to the left, aligned to the right edge. |
|
||||||
// x = childSize.width - (size.width - position.right); |
|
||||||
x = position.left + width - childSize.width; |
|
||||||
} else if (position.left < position.right) { |
|
||||||
// Menu button is closer to the left edge, so grow to the right, aligned to the left edge. |
|
||||||
if (width > childSize.width) { |
|
||||||
x = position.left + (childSize.width - menuWidth) / 2; |
|
||||||
} else |
|
||||||
x = position.left; |
|
||||||
} else { |
|
||||||
x = position.right - width / 2 - childSize.width / 2; |
|
||||||
} |
|
||||||
// Avoid going outside an area defined as the rectangle 8.0 pixels from the |
|
||||||
// edge of the screen in every direction. |
|
||||||
if (x < _kMenuScreenPadding) |
|
||||||
x = _kMenuScreenPadding; |
|
||||||
else if (x + childSize.width > size.width - _kMenuScreenPadding) |
|
||||||
x = size.width - childSize.width - _kMenuScreenPadding; |
|
||||||
if (y < _kMenuScreenPadding) |
|
||||||
y = _kMenuScreenPadding; |
|
||||||
else if (y + childSize.height > size.height - _kMenuScreenPadding) |
|
||||||
y = size.height - childSize.height; |
|
||||||
else if (y < childSize.height * 2) { |
|
||||||
y = position.top + childSize.height; |
|
||||||
} |
|
||||||
return Offset(x, y); |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
bool shouldRelayout(_PopupMenuRouteLayout oldDelegate) { |
|
||||||
return position != oldDelegate.position; |
|
||||||
} |
|
||||||
} |
|
@ -1,55 +0,0 @@ |
|||||||
import 'package:extended_text/extended_text.dart'; |
|
||||||
import 'package:flutter/cupertino.dart'; |
|
||||||
import 'package:flutter/material.dart'; |
|
||||||
|
|
||||||
import 'package:flutter/services.dart';import 'package:huixiang/message/im/im_view/text_span_builder.dart'; |
|
||||||
|
|
||||||
import 'magic_pop.dart'; |
|
||||||
|
|
||||||
class TextItemContainer extends StatefulWidget { |
|
||||||
final String text; |
|
||||||
final String action; |
|
||||||
final bool isMyself; |
|
||||||
|
|
||||||
TextItemContainer({this.text, this.action, this.isMyself = true}); |
|
||||||
|
|
||||||
@override |
|
||||||
_TextItemContainerState createState() => _TextItemContainerState(); |
|
||||||
} |
|
||||||
|
|
||||||
class _TextItemContainerState extends State<TextItemContainer> { |
|
||||||
TextSpanBuilder _spanBuilder = TextSpanBuilder(); |
|
||||||
|
|
||||||
@override |
|
||||||
Widget build(BuildContext context) { |
|
||||||
return MagicPop( |
|
||||||
onValueChanged: (int value) { |
|
||||||
switch (value) { |
|
||||||
case 0: |
|
||||||
Clipboard.setData(new ClipboardData(text: widget.text)); |
|
||||||
break; |
|
||||||
case 3: |
|
||||||
break; |
|
||||||
} |
|
||||||
}, |
|
||||||
pressType: PressType.longPress, |
|
||||||
actions: ['复制', '转发', '收藏', '撤回', '删除'], |
|
||||||
child: new Container( |
|
||||||
// width: widget.text.length > 24 ? (MediaQuery.of(context).size.width - 66) - 100 : null, |
|
||||||
// padding: EdgeInsets.all(5.0), |
|
||||||
// decoration: BoxDecoration( |
|
||||||
// color: widget.isMyself ? Color(0xff98E165) : Colors.white, |
|
||||||
// borderRadius: BorderRadius.all(Radius.circular(5.0)), |
|
||||||
// ), |
|
||||||
// margin: EdgeInsets.only(right: 7.0), |
|
||||||
child: ExtendedText( |
|
||||||
widget.text ?? '文字为空', |
|
||||||
maxLines: 99, |
|
||||||
overflow: TextOverflow.ellipsis, |
|
||||||
specialTextSpanBuilder: _spanBuilder, |
|
||||||
style: TextStyle(fontSize: 17,color: Colors.white), |
|
||||||
), |
|
||||||
), |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
@ -1,33 +0,0 @@ |
|||||||
import 'package:extended_text_library/extended_text_library.dart'; |
|
||||||
import 'package:flutter/material.dart'; |
|
||||||
|
|
||||||
import 'emoji_text.dart'; |
|
||||||
|
|
||||||
class TextSpanBuilder extends SpecialTextSpanBuilder { |
|
||||||
final bool showAtBackground; |
|
||||||
|
|
||||||
TextSpanBuilder({ |
|
||||||
this.showAtBackground: false, |
|
||||||
}); |
|
||||||
|
|
||||||
@override |
|
||||||
TextSpan build(String data, {TextStyle textStyle, onTap}) { |
|
||||||
TextSpan result = super.build(data, textStyle: textStyle, onTap: onTap); |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
@override |
|
||||||
SpecialText createSpecialText(String flag, |
|
||||||
{TextStyle textStyle, SpecialTextGestureTapCallback onTap, int index}) { |
|
||||||
if (flag == null || flag == "") return null; |
|
||||||
|
|
||||||
if (isStart(flag, EmojiText.flag)) { |
|
||||||
return EmojiText(textStyle, start: index - (EmojiText.flag.length - 1)); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
class SpecialTextStyle { |
|
||||||
TextRange textRange; |
|
||||||
} |
|
Loading…
Reference in new issue