Fix: RenderFlex-Overflow in NowPlayingScreen während der Öffnen-Geste

Bug (Code-Review, verifiziert): _Angaben (Titel/Künstler/Fortschritt/
Controls) hat eine intrinsische Mindesthöhe, die während der Öffnen-Geste
(progress zwischen ~0.3 und ~1.0, siehe main.dart Positioned.fromRect mit
Rect.lerp Mini-/Vollbild-Player) das noch kleinere, interpolierte
Rechteck übersteigt — Flutter meldete dann "RenderFlex overflowed" bei
praktisch jeder normalen Öffnen-Geste.

Fix: der Inhalt-Slot (in beiden responsiven Zweigen — Row nebeneinander
und Column untereinander) steckt jetzt in
ClipRect(child: ConstrainedBox(maxHeight: raum.maxHeight - Lücke,
child: OverflowBox(maxHeight: infinity, fit: deferToChild, child: _Angaben))).
ConstrainedBox deckelt nur, was OverflowBox nach AUSSEN als eigene Größe
meldet (verhindert, dass der umgebende Row/Column selbst überläuft);
OverflowBox gibt _Angaben davon unabhängig weiterhin unbegrenzte Höhe
(verhindert, dass _Angaben intern überläuft) — überschüssiger Inhalt wird
vom ClipRect während der kurzen, ohnehin noch recht durchsichtigen
Übergangsphase einfach nicht gemalt statt eine Overflow-Warnung
auszulösen. Bei ausreichend Platz (Endzustand progress==1) ist
raum.maxHeight groß genug, dass nichts geklemmt wird — die Optik bleibt
dort unverändert (now_playing_heart_test.dart bestätigt das weiterhin).

Test zuerst (RED: "RenderFlex overflowed by 13 pixels" reproduziert, mit
NowPlayingScreen in einem echten, interpolierten Zwischenrechteck bei
progress≈0.4 auf Basis der HomeShell-Rect-Formel): test/player/
now_playing_screen_overflow_test.dart.

Volle Suite (626 Tests) grün.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SM6e73V9ZethPiqHSocxUA
This commit is contained in:
Hermes (Server)
2026-08-29 15:55:52 +02:00
co-authored by Claude Sonnet 5
parent 0fe624d1e8
commit bc58438262
2 changed files with 166 additions and 1 deletions
+38 -1
View File
@@ -3,6 +3,7 @@ import 'dart:ui' show lerpDouble;
import 'package:audio_service/audio_service.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart' show OverflowBoxFit;
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
@@ -61,7 +62,43 @@ class NowPlayingScreen extends StatelessWidget {
return LayoutBuilder(
builder: (context, raum) {
final nebeneinander = raum.maxWidth > raum.maxHeight;
final inhalt = _Angaben(item: item, handler: handler);
// Während der Öffnen-Geste ist das interpolierte
// Rechteck (main.dart, Rect.lerp Mini-/Vollbild-
// Player) oft noch kleiner, als _Angaben an
// Mindesthöhe braucht — ohne diese Kapselung meldet
// Flutter dann "RenderFlex overflowed" (im Row-Zweig
// unten bekäme _Angaben selbst eine zu knappe Höhe
// zugeteilt, im Column-Zweig überschreitet Lücke +
// _Angaben-Eigenhöhe zusammen die verfügbare Höhe).
// ConstrainedBox AUSSEN um OverflowBox deckelt, was
// OverflowBox nach außen als eigene Größe meldet,
// hart auf das von raum bekannte Maß; OverflowBox
// selbst gibt ihrem Kind (_Angaben) über
// maxHeight: infinity davon UNABHÄNGIG weiterhin
// unbegrenzte Höhe — _Angaben behält so seine
// natürliche Größe, der überschüssige Teil wird
// vom ClipRect einfach nicht gemalt statt eine
// Overflow-Warnung auszulösen. Läge die Deckelung
// stattdessen INNEN (zwischen OverflowBox und
// _Angaben), bekäme _Angaben selbst zu wenig Höhe
// und liefe intern über. Bei ausreichend Platz
// (Endzustand progress==1) ist raum.maxHeight groß
// genug, dass nichts geklemmt wird — die Optik
// bleibt dort unverändert.
final inhalt = ClipRect(
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: (raum.maxHeight - MeloSpace.lg)
.clamp(0.0, double.infinity),
),
child: OverflowBox(
alignment: Alignment.center,
maxHeight: double.infinity,
fit: OverflowBoxFit.deferToChild,
child: _Angaben(item: item, handler: handler),
),
),
);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: nebeneinander