Open7
flutter雑記
flutterのprividerはカウンターのサンプルしかないので他の構造の時のやりかたが全然頭に入ってこない。のだが、試行錯誤の末にようやくわかった。
- 画面を横断するデータはclass T extends ChangeNotifier する必要がある。※ここではそういうことにする
- データの入れ方は、アプリ実装者の都合で構わない。StatelessWidget::build()が呼ばれたときに帳尻があえば良い
- MatrialApp の直下あたりで ChangeNotifierProvider<T>(create:T) で括り付ける。※ここではそういうことにする
- 以降、StatelessWidgetで作る。
- 画面更新では、StatefulWidget/Stateとは別の機構をつかうため、
- Provider.of<T>(BuilderContext) で、上でくくりつけたデータを取り出す。
- Consumer<T>()の説明をしてる例が非常に多いが、慣れないうちは無名関数の段が増えて判りにくくなるので、Provider.ofを会得してから移行していけばええんやで。
- of<T>の時点でlistnerの登録が行われている。
- 画面更新に直接関係ないデータ参照は Provider.of<T>(context, listen: false) を付ける(文字通り listener非対象となる )
- データ更新は、T の中身を更新したのち、T::notifyListeners() を呼ぶ
- のだがこれはprotectedなので、たいていのサンプルでは、setterで同時に実施する。
- なれないうちは notify() => notifyListers() から呼んでもええんやで※ここではそういうことにする
- Provider.of<T>(listen:true)の参照をしてるところに更新がかかる
- 前述の通りBuilderContext 経由で T が取り出せるので、画面を横断してデータを共通化できるという筋書き。
- 複数系統の更新タイミングがある場合、別のTを用意して使い分ける。
以前習作で造っただけで、大変なことになったので、もうちょっと何とかなりませんかねという話。
全部網羅する気はありません。
局所的
Widgetに対して適切な拡張メソッドを造っておき、メソッドチェインで構築する。
Dart extensions to flatten Flutter's deep nested widget trees
extension WidgetModifier on Widget {
Widget cornerRadius(BorderRadiusGeometry radius) {
return ClipRRect(
borderRadius: radius,
child: this,
);
}
こういうを色々造っておけば
Widget build(BuildContext context) {
return Text('Hello, World!', style: Theme.of(context).textTheme.headline4)
.padding()
.background(Colors.lightBlue)
.cornerRadius(BorderRadius.all(Radius.circular(8.0)))
.padding(EdgeInsets.symmetric(horizontal: 8, vertical: 16))
.background(Colors.purple);
}
こう出来るよねと。
ソースはかなり素敵に観えるが、内部で結局 child:this してるのでソースの絵面と親子関係が逆転する。拡張メソッドの設計にセンスと知見が要りそう。
全体的
How to do nested navigation in Flutter - Stack Overflow
なんとなくしか理解できてない
final _libraryScreen = GlobalKey<NavigatorState>();
に
children: <Widget>[
Navigator(
key: _libraryScreen,
onGenerateRoute: (route) => MaterialPageRoute(
settings: route,
builder: (context) => LibraryScreen(),
),
),
としておいて
void _onTap(int val, BuildContext context) {
if (_currentIndex == val) {
switch (val) {
case 0:
_libraryScreen.currentState.popUntil((route) => route.isFirst);
break;
こうする
syncspec.py
import json
from ruamel.yaml import YAML
from ruamel.yaml.comments import CommentedMap
def get_versions_from_lock(lock_file_path):
with open(lock_file_path, 'r', encoding='utf-8') as f:
lock_data = json.load(f)
packages = lock_data.get('packages', {})
versions = {pkg: details['version'] for pkg, details in packages.items()}
return versions
def update_pubspec_yaml(pubspec_path, versions):
yaml = YAML()
yaml.preserve_quotes = True
yaml.indent(mapping=2, sequence=4, offset=2)
with open(pubspec_path, 'r', encoding='utf-8') as f:
data = yaml.load(f)
# 依存関係が記載されているセクションを特定
dependencies = data.get('dependencies', CommentedMap())
dev_dependencies = data.get('dev_dependencies', CommentedMap())
# 依存関係を更新
for dep in dependencies:
if dep in versions:
# 既にバージョン指定がある場合は更新、ない場合は追加
current = dependencies[dep]
if isinstance(current, dict):
# バージョン指定が複雑な場合(例えば git など)はスキップ
continue
dependencies[dep] = versions[dep]
# 開発依存関係を更新
for dep in dev_dependencies:
if dep in versions:
current = dev_dependencies[dep]
if isinstance(current, dict):
continue
dev_dependencies[dep] = versions[dep]
# 更新されたデータを `pubspec.yaml` に書き戻す
with open(pubspec_path, 'w', encoding='utf-8') as f:
yaml.dump(data, f)
def main():
lock_file = 'pubspec.lock'
pubspec_file = 'pubspec.yaml'
versions = get_versions_from_lock(lock_file)
update_pubspec_yaml(pubspec_file, versions)
print(f"'{pubspec_file}' を更新しました。")
if __name__ == "__main__":
main()