我是廣告,點擊一下吧!
標籤
#Flutter (15) 、 #PHP (9) 、 #Laravel (7) 、 #Dart (5) 、 #MySQL (5) 、 #Mac (4) 、 #VS Code (2) 、 #IDE (2) 、 #List (2) 、 #Android (2) 、 #Carbon (2) 、 #Linux (2) 、 #Shell Script (2) 、 #MySQL 效能 (1) 、 #Pagination (1) 、 #Cursor Pagination (1) 、 #LaTeX (1) 、 #個人空間 (1) 、 #Android Splash Screen (1) 、 #createFromTimestamp (1) 、 #資安 (1) 、 #Google Maps Static API (1) 、 #Mac M1 (1) 、 #floorMonth (1) 、 #subMonthNoOverflow (1) 、 #addMonthNoOverflow (1) 、 #subMonth (1) 、 #addMonth (1) 、 #keytool (1) 、 #Play App Signing (1)在 Flutter 中使用 markdown_widget 與 flutter_math_fork,讓 Markdown 支援 LaTeX 數學公式渲染。
dependencies:
markdown_widget: ^2.3.2+8
flutter_math_fork: ^0.7.0
import 'package:flutter/material.dart';
import 'package:markdown_widget/markdown_widget.dart';
import 'package:flutter_math_fork/flutter_math.dart';
import 'package:markdown/markdown.dart' as m;
SpanNodeGeneratorWithTag latexGenerator =
SpanNodeGeneratorWithTag(tag: _latexTag, generator: (e, config, visitor) => LatexNode(e.attributes, e.textContent, config));
const _latexTag = 'latex';
class LatexSyntax extends m.InlineSyntax {
LatexSyntax() : super(r'(\$\$[\s\S]+\$\$)|(\$.+?\$)');
@override
bool onMatch(m.InlineParser parser, Match match) {
final input = match.input;
final matchValue = input.substring(match.start, match.end);
String content = '';
bool isInline = true;
const blockSyntax = '\$\$';
const inlineSyntax = '\$';
if (matchValue.startsWith(blockSyntax) && matchValue.endsWith(blockSyntax) && (matchValue != blockSyntax)) {
content = matchValue.substring(2, matchValue.length - 2);
isInline = false;
} else if (matchValue.startsWith(inlineSyntax) && matchValue.endsWith(inlineSyntax) && matchValue != inlineSyntax) {
content = matchValue.substring(1, matchValue.length - 1);
}
m.Element el = m.Element.text(_latexTag, matchValue);
el.attributes['content'] = content;
el.attributes['isInline'] = '$isInline';
parser.addNode(el);
return true;
}
}
class LatexNode extends SpanNode {
final Map<String, String> attributes;
final String textContent;
final MarkdownConfig config;
LatexNode(this.attributes, this.textContent, this.config);
@override
InlineSpan build() {
final content = attributes['content'] ?? '';
final isInline = attributes['isInline'] == 'true';
final style = parentStyle ?? config.p.textStyle;
if (content.isEmpty) return TextSpan(style: style, text: textContent);
final latex = Math.tex(
content,
mathStyle: MathStyle.text,
textStyle: style.copyWith(color: Colors.black),
textScaleFactor: 1,
onErrorFallback: (error) {
return Text(textContent, style: style.copyWith(color: Colors.red));
},
);
return WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: !isInline
? Container(
width: double.infinity,
margin: EdgeInsets.symmetric(vertical: 16),
child: Center(child: latex),
)
: latex,
);
}
}
import 'package:project_name/latex.dart';
import 'package:markdown_widget/markdown_widget.dart';
......
MarkdownWidget(
data: '''\$\$f(X,n) = X_n + X_{n-1}\$\$
\$\$
M =
\\begin{bmatrix}
\\frac{5}{6} & \\frac{1}{6} & 0 \\\\[0.3em]
\\frac{5}{6} & 0 & \\frac{1}{6} \\\\[0.3em]
0 & \\frac{5}{6} & \\frac{1}{6}
\\end{bmatrix}
\$\$''',
markdownGenerator: MarkdownGenerator(
inlineSyntaxList: [LatexSyntax()],
generators: [latexGenerator],
),
),
......
在寫 Futtler 時常常一些變數是希望在 APP 關閉前可以隨手取得,這時使用單例模式 (Singleton) 可以很方便的存取。
使用 Factory constructor 方式即可完成 Dart 中的 Singleton
class SingletonClass {
static final SingletonClass _singleton = SingletonClass._init();
factory SingletonClass() => _singleton;
SingletonClass._init();
}
其他語言通常都是有叫做 filter()
之類的 function,但在 Dart 想過濾 List 中的某些值時是使用 where()
,滿特別的命名。
但 where()
回傳的是 Iterable
型別,所以必須再呼叫 toList()
轉回 List
型別。
void main() {
List<int> list = [87, 8787];
print(list.where((e) => e > 100).toList()); // [8787]
print(list.where((e) => e < 100).toList()); // [87]
}
試一試吧:https://dartpad.dev/?id=8281264511bc4db31bbdc5c4379c042d
使用一些套件時發現必須呼叫套件底層的 Function,這時候就要利用 GlobalKey。
宣告一個 GlobalKey
final GlobalKey<MyState> _myKey = GlobalKey();
加入到需要呼叫的 Widget
MyWidget(
key: _myKey,
),
Widget State 內的 Function 必須是 Public
class MyState extends State<MyWidget> {
foo() {
// some code
}
}
呼叫
_myKey.currentState!.foo();
最近把 List 存到 BLoC 發現在 A 頁面取出後對這 List 操作後,B 頁面也會跟著被改變,是因為 Dart 物件預設是 call by reference。
void main() {
List<int> aList = [8787];
List<int> bList = aList;
print('aList: $aList');// aList: [8787]
print('bList: $bList');// bList: [8787]
bList.add(87);
print('aList: $aList');// aList: [8787, 87]
print('bList: $bList');// bList: [8787, 87]
}
只要在給值的時候使用加上 toList()
即可
void main() {
List<int> aList = [8787];
- List<int> bList = aList;
+ List<int> bList = aList.toList();
print('aList: $aList');// aList: [8787]
print('bList: $bList');// bList: [8787]
bList.add(87);
print('aList: $aList');// aList: [8787]
print('bList: $bList');// bList: [8787, 87]
}
試一試吧:https://dartpad.dev/?id=26d30bcd783277c83d00041279de673e