[解決済み] Widgetの高さを取得するには?
質問
の仕組みがわかりません。
LayoutBuilder
は、Widgetの高さを取得するために使用されます。
ウィジェットのリストを表示し、その高さを取得して、特殊なスクロール効果を計算する必要があります。私はパッケージを開発しており、他の開発者がウィジェットを提供しています(私はそれらを制御しません)。私は、LayoutBuilderが高さを取得するために使用できることを読みました。
非常に単純なケースですが、WidgetをLayoutBuilder.builderでラップしてStackに配置しようとしましたが、いつも次のようになります。
minHeight
0.0
と
maxHeight
INFINITY
. LayoutBuilderの使い方が間違っているのでしょうか?
EDIT : LayoutBuilderはダメみたいですね。というのを発見しました。 CustomSingleChildLayout で、ほぼ解決しています。
そのデリゲートを拡張し、ウィジェットの高さを
getPositionForChild(Size size, Size childSize)
メソッドを使用します。しかし、最初に呼び出されるメソッドは
Size getSize(BoxConstraints constraints)
で、制約として、ListViewにこのCustomSingleChildLayoutsを敷いているので、0からINFINITYになります。
私の問題は、SingleChildLayoutDelegateの
getSize
は、ビューの高さを返す必要があるように動作します。その時、子供の高さはわかりません。私は、constraints.smallest(これは0であり、高さは0です)か、constraints.biggest(これは無限大であり、アプリをクラッシュさせます)を返すことしかできません。
ドキュメントにはこうも書いてある。
...しかし、親のサイズは子のサイズに依存することはできません。
と、変な制約がありますね。
解決方法は?
ウィジェットの画面上のサイズ/位置を取得するために
GlobalKey
を取得し、その
BuildContext
を検索し、その中から
RenderBox
には、そのウィジェットのグローバルな位置とレンダリングサイズが含まれます。
ただ、一つ気をつけなければならないことがあります。ウィジェットがレンダリングされていない場合、そのコンテキストは存在しないかもしれません。そのため
ListView
ウィジェットは、潜在的に可視である場合にのみレンダリングされるからです。
もう一つの問題は、ウィジェットの
RenderBox
の間に
build
の呼び出しは、ウィジェットがまだレンダリングされていないためです。
しかし、ビルド中にサイズを取得する必要がある場合はどうすればいいのでしょうか! どうすればいいのでしょうか?
1つだけ、クールなウィジェットがあります。
Overlay
とその
OverlayEntry
.
これらはウィジェットを他のすべてのものの上に表示するために使用されます (スタックに似ています)。
しかし、最もクールなことは、それらが別の
build
のフローで構築されています。
後
通常のウィジェットです。
これには1つ、とてもクールな意味があるんです。
OverlayEntry
は、実際のウィジェットツリーのウィジェットに依存する大きさを持つことができます。
しかし、OverlayEntryは手動で再構築する必要があるのではないでしょうか?
はい、そうです。でも、もうひとつ気をつけなければならないことがあります。
ScrollController
に渡される
Scrollable
と同様のリスナーブルです。
AnimationController
.
つまり
AnimatedBuilder
と
ScrollController
を使用すると、スクロール時にウィジェットを自動的に再構築する素敵な効果があります。このシチュエーションにぴったりでしょう?
すべてを組み合わせて例として
次の例では、ウィジェットに続くオーバーレイが
ListView
と同じ高さを共有します。
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final controller = ScrollController();
OverlayEntry sticky;
GlobalKey stickyKey = GlobalKey();
@override
void initState() {
if (sticky != null) {
sticky.remove();
}
sticky = OverlayEntry(
builder: (context) => stickyBuilder(context),
);
SchedulerBinding.instance.addPostFrameCallback((_) {
Overlay.of(context).insert(sticky);
});
super.initState();
}
@override
void dispose() {
sticky.remove();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
controller: controller,
itemBuilder: (context, index) {
if (index == 6) {
return Container(
key: stickyKey,
height: 100.0,
color: Colors.green,
child: const Text("I'm fat"),
);
}
return ListTile(
title: Text(
'Hello $index',
style: const TextStyle(color: Colors.white),
),
);
},
),
);
}
Widget stickyBuilder(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: (_,Widget child) {
final keyContext = stickyKey.currentContext;
if (keyContext != null) {
// widget is visible
final box = keyContext.findRenderObject() as RenderBox;
final pos = box.localToGlobal(Offset.zero);
return Positioned(
top: pos.dy + box.size.height,
left: 50.0,
right: 50.0,
height: box.size.height,
child: Material(
child: Container(
alignment: Alignment.center,
color: Colors.purple,
child: const Text("^ Nah I think you're okay"),
),
),
);
}
return Container();
},
);
}
}
備考 :
別画面に移動するときは、以下のように呼び出すと、付箋が表示されたままになります。
sticky.remove();
関連
-
[解決済み] FlutterでButtonを無効にするには?
-
[解決済み] 画面サイズ、現在のウェブページ、ブラウザウィンドウのサイズを取得する
-
[解決済み] Androidで画面の大きさをピクセル単位で取得する方法
-
[解決済み] Flutterでウィジェットにボーダーを追加するには?
-
[解決済み】メッセージ「flutter run: 接続されたデバイスがありません"
-
[解決済み】FlutterでStatefulWidgetにデータを渡して、その状態のままアクセスする方法
-
[解決済み】Flutter: 未処理の例外です。バインディングが初期化される前にServicesBinding.defaultBinaryMessengerにアクセスされました。
-
[解決済み] キーボードが表示されると、Flutterのウィジェットがリサイズされます。これを防ぐにはどうしたらよいですか?
-
[解決済み] アップバーのタイトルを中央揃えにする方法
-
[解決済み] フラッターは2つのアイテムを左と右の両極端に配置します。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Flutter TextButton splashColor プロパティ
-
flutter TextField 入力ボックスコンポーネント
-
flutter,コマンド PhaseScriptExecution が 0 以外の終了コードで失敗しました。
-
[解決済み] FlutterでListViewをColumnに追加する方法とは?
-
[解決済み】起動ロックを解除するために別のflutterコマンドを待機する
-
[解決済み】行の中のテキストフィールドでレイアウト例外が発生する。Unable to calculate size
-
[解決済み】Flutter: 未処理の例外です。バインディングが初期化される前にServicesBinding.defaultBinaryMessengerにアクセスされました。
-
[解決済み] ボタンの幅を親と同じにするには?
-
[解決済み] フラッター : 垂直中心柱
-
[解決済み] Flutter FirestoreでD8が発生:要求されたクラスを単一のdexファイルに収められない (# methods: 71610 > 65536) in Android Studio