refactor(#173): widget NineSliceAsset réutilisable (cartes + bandeau)
Presets cards/bandeau, cache images, appliqué au sélecteur couple. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -24,12 +24,4 @@ enum CardColorHorizontal {
|
|||||||
|
|
||||||
final String path;
|
final String path;
|
||||||
const CardColorHorizontal(this.path);
|
const CardColorHorizontal(this.path);
|
||||||
|
|
||||||
/// Zone centrale extensible en pixels source (~1024×512).
|
|
||||||
/// Coins source ≈ 160×90 — mappés ensuite à une taille logique fixe.
|
|
||||||
static const Rect centerSlice = Rect.fromLTRB(160, 90, 864, 422);
|
|
||||||
|
|
||||||
/// Taille logique des coins (indépendante de la largeur d’écran).
|
|
||||||
static const double cornerWidth = 56;
|
|
||||||
static const double cornerHeight = 40;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:p_tits_pas/models/card_assets.dart';
|
|
||||||
import 'package:p_tits_pas/models/carte_bulle.dart';
|
import 'package:p_tits_pas/models/carte_bulle.dart';
|
||||||
import 'package:p_tits_pas/services/api/cards_service.dart';
|
import 'package:p_tits_pas/services/api/cards_service.dart';
|
||||||
import 'package:p_tits_pas/widgets/quotidien/nine_slice_asset.dart';
|
import 'package:p_tits_pas/widgets/quotidien/nine_slice_asset.dart';
|
||||||
@@ -288,11 +287,8 @@ class _BulleTile extends StatelessWidget {
|
|||||||
final treated = card.statut == CarteStatut.traitee;
|
final treated = card.statut == CarteStatut.traitee;
|
||||||
return Opacity(
|
return Opacity(
|
||||||
opacity: treated ? 0.55 : 1,
|
opacity: treated ? 0.55 : 1,
|
||||||
child: NineSliceAsset(
|
child: NineSliceAsset.card(
|
||||||
assetPath: card.backgroundAsset,
|
assetPath: card.backgroundAsset,
|
||||||
centerSlice: CardColorHorizontal.centerSlice,
|
|
||||||
cornerWidth: CardColorHorizontal.cornerWidth,
|
|
||||||
cornerHeight: CardColorHorizontal.cornerHeight,
|
|
||||||
constraints: const BoxConstraints(minHeight: 96),
|
constraints: const BoxConstraints(minHeight: 96),
|
||||||
padding: const EdgeInsets.fromLTRB(20, 14, 20, 14),
|
padding: const EdgeInsets.fromLTRB(20, 14, 20, 14),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:google_fonts/google_fonts.dart';
|
|||||||
import 'package:p_tits_pas/models/couple_garde.dart';
|
import 'package:p_tits_pas/models/couple_garde.dart';
|
||||||
import 'package:p_tits_pas/services/api/api_config.dart';
|
import 'package:p_tits_pas/services/api/api_config.dart';
|
||||||
import 'package:p_tits_pas/widgets/common/auth_network_image.dart';
|
import 'package:p_tits_pas/widgets/common/auth_network_image.dart';
|
||||||
|
import 'package:p_tits_pas/widgets/quotidien/nine_slice_asset.dart';
|
||||||
import 'package:p_tits_pas/widgets/quotidien/quotidien_theme.dart';
|
import 'package:p_tits_pas/widgets/quotidien/quotidien_theme.dart';
|
||||||
|
|
||||||
/// Rôle qui consulte le bandeau : côté parent (enfant | nounou) ou côté AM
|
/// Rôle qui consulte le bandeau : côté parent (enfant | nounou) ou côté AM
|
||||||
@@ -174,14 +175,10 @@ class _CoupleCard extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Container(
|
return NineSliceAsset.bandeau(
|
||||||
|
assetPath: QuotidienTheme
|
||||||
|
.bandeauColors[colorIndex % QuotidienTheme.bandeauColors.length],
|
||||||
height: 90,
|
height: 90,
|
||||||
decoration: BoxDecoration(
|
|
||||||
image: DecorationImage(
|
|
||||||
image: AssetImage(QuotidienTheme.bandeauColors[colorIndex % QuotidienTheme.bandeauColors.length]),
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
@@ -190,7 +187,8 @@ class _CoupleCard extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.only(right: 12),
|
padding: const EdgeInsets.only(right: 12),
|
||||||
child: _MembreTile(
|
child: _MembreTile(
|
||||||
photoUrl: couple.enfant.photoUrl,
|
photoUrl: couple.enfant.photoUrl,
|
||||||
name: (couple.enfant.prenom != null && couple.enfant.prenom!.isNotEmpty)
|
name: (couple.enfant.prenom != null &&
|
||||||
|
couple.enfant.prenom!.isNotEmpty)
|
||||||
? couple.enfant.prenom!
|
? couple.enfant.prenom!
|
||||||
: couple.enfant.displayName(fallback: 'Enfant'),
|
: couple.enfant.displayName(fallback: 'Enfant'),
|
||||||
fallbackIcon: Icons.child_care,
|
fallbackIcon: Icons.child_care,
|
||||||
@@ -215,12 +213,12 @@ class _CoupleCard extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 28,
|
width: 28,
|
||||||
child: showChevron
|
child: showChevron
|
||||||
? const Icon(
|
? const Icon(
|
||||||
Icons.keyboard_arrow_down,
|
Icons.keyboard_arrow_down,
|
||||||
color: QuotidienTheme.ink,
|
color: QuotidienTheme.ink,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -306,24 +304,22 @@ class _CoupleBandeauSkeleton extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return ColorFiltered(
|
||||||
height: 90,
|
colorFilter: ColorFilter.mode(
|
||||||
decoration: BoxDecoration(
|
Colors.white.withValues(alpha: 0.5),
|
||||||
image: DecorationImage(
|
BlendMode.lighten,
|
||||||
image: const AssetImage(QuotidienTheme.bandeauLime), // Un asset existant
|
),
|
||||||
fit: BoxFit.fill,
|
child: NineSliceAsset.bandeau(
|
||||||
colorFilter: ColorFilter.mode(
|
assetPath: QuotidienTheme.bandeauLime,
|
||||||
Colors.white.withValues(alpha: 0.5),
|
height: 90,
|
||||||
BlendMode.lighten,
|
child: const Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 26,
|
||||||
|
height: 26,
|
||||||
|
child: CircularProgressIndicator(strokeWidth: 2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
alignment: Alignment.center,
|
|
||||||
child: const SizedBox(
|
|
||||||
width: 26,
|
|
||||||
height: 26,
|
|
||||||
child: CircularProgressIndicator(strokeWidth: 2),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,14 +329,9 @@ class _CoupleBandeauEmpty extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return NineSliceAsset.bandeau(
|
||||||
|
assetPath: QuotidienTheme.bandeauLime,
|
||||||
height: 90,
|
height: 90,
|
||||||
decoration: const BoxDecoration(
|
|
||||||
image: DecorationImage(
|
|
||||||
image: AssetImage(QuotidienTheme.bandeauLime), // Un asset existant par défaut
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
@@ -369,38 +360,35 @@ class _CoupleBandeauError extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return ColorFiltered(
|
||||||
height: 90,
|
colorFilter: ColorFilter.mode(
|
||||||
decoration: BoxDecoration(
|
QuotidienTheme.coral.withValues(alpha: 0.3),
|
||||||
image: DecorationImage(
|
BlendMode.srcATop,
|
||||||
image: const AssetImage(QuotidienTheme.bandeauLime), // Un asset existant
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
colorFilter: ColorFilter.mode(
|
|
||||||
QuotidienTheme.coral.withValues(alpha: 0.3),
|
|
||||||
BlendMode.srcATop,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
child: NineSliceAsset.bandeau(
|
||||||
child: Row(
|
assetPath: QuotidienTheme.bandeauLime,
|
||||||
children: [
|
height: 90,
|
||||||
const Icon(Icons.error_outline, color: QuotidienTheme.ink),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
const SizedBox(width: 12),
|
child: Row(
|
||||||
Expanded(
|
children: [
|
||||||
child: Text(
|
const Icon(Icons.error_outline, color: QuotidienTheme.ink),
|
||||||
message,
|
const SizedBox(width: 12),
|
||||||
style: GoogleFonts.merriweather(
|
Expanded(
|
||||||
fontSize: 13,
|
child: Text(
|
||||||
color: QuotidienTheme.ink,
|
message,
|
||||||
|
style: GoogleFonts.merriweather(
|
||||||
|
fontSize: 13,
|
||||||
|
color: QuotidienTheme.ink,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
if (onRetry != null)
|
||||||
if (onRetry != null)
|
TextButton(
|
||||||
TextButton(
|
onPressed: onRetry,
|
||||||
onPressed: onRetry,
|
child: const Text('Réessayer'),
|
||||||
child: const Text('Réessayer'),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,42 +3,115 @@ import 'dart:ui' as ui;
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
/// Fond 9-slice dynamique (schéma extensible.png).
|
/// Paramètres de découpe 9-slice (schéma extensible.png).
|
||||||
///
|
class NineSliceSpec {
|
||||||
/// - Coins : taille logique fixe (ne s’étirent pas avec l’écran)
|
|
||||||
/// - Bords H / V + centre : s’étirent pour remplir le widget
|
|
||||||
/// - Pas besoin de fichier `.9.png` Android
|
|
||||||
class NineSliceAsset extends StatefulWidget {
|
|
||||||
final String assetPath;
|
|
||||||
|
|
||||||
/// Zone centrale extensible en pixels source (LTRB du centre).
|
/// Zone centrale extensible en pixels source (LTRB du centre).
|
||||||
final Rect centerSlice;
|
final Rect centerSlice;
|
||||||
|
|
||||||
/// Largeur logique cible des coins gauche / droite.
|
/// Largeur logique fixe des coins gauche / droite.
|
||||||
final double cornerWidth;
|
final double cornerWidth;
|
||||||
|
|
||||||
/// Hauteur logique cible des coins haut / bas.
|
/// Hauteur logique fixe des coins haut / bas.
|
||||||
final double cornerHeight;
|
final double cornerHeight;
|
||||||
|
|
||||||
|
const NineSliceSpec({
|
||||||
|
required this.centerSlice,
|
||||||
|
required this.cornerWidth,
|
||||||
|
required this.cornerHeight,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Bulles / cartes horizontales `card_*_h.png` (~1024×512).
|
||||||
|
static const cards = NineSliceSpec(
|
||||||
|
centerSlice: Rect.fromLTRB(160, 90, 864, 422),
|
||||||
|
cornerWidth: 56,
|
||||||
|
cornerHeight: 40,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Bandeaux couple `bandeau_*.png` (~1024×160).
|
||||||
|
static const bandeau = NineSliceSpec(
|
||||||
|
centerSlice: Rect.fromLTRB(140, 32, 884, 128),
|
||||||
|
cornerWidth: 56,
|
||||||
|
cornerHeight: 28,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is NineSliceSpec &&
|
||||||
|
centerSlice == other.centerSlice &&
|
||||||
|
cornerWidth == other.cornerWidth &&
|
||||||
|
cornerHeight == other.cornerHeight;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(centerSlice, cornerWidth, cornerHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fond pastel extensible réutilisable (cartes, bandeau couple, etc.).
|
||||||
|
///
|
||||||
|
/// Coins à taille logique fixe ; bords H/V + centre s’étirent.
|
||||||
|
/// Pas de fichier `.9.png` Android.
|
||||||
|
class NineSliceAsset extends StatefulWidget {
|
||||||
|
final String assetPath;
|
||||||
|
final NineSliceSpec spec;
|
||||||
final Widget? child;
|
final Widget? child;
|
||||||
final EdgeInsetsGeometry? padding;
|
final EdgeInsetsGeometry? padding;
|
||||||
final BoxConstraints? constraints;
|
final BoxConstraints? constraints;
|
||||||
|
final double? width;
|
||||||
|
final double? height;
|
||||||
|
|
||||||
const NineSliceAsset({
|
const NineSliceAsset({
|
||||||
super.key,
|
super.key,
|
||||||
required this.assetPath,
|
required this.assetPath,
|
||||||
required this.centerSlice,
|
this.spec = NineSliceSpec.cards,
|
||||||
this.cornerWidth = 56,
|
|
||||||
this.cornerHeight = 40,
|
|
||||||
this.child,
|
this.child,
|
||||||
this.padding,
|
this.padding,
|
||||||
this.constraints,
|
this.constraints,
|
||||||
|
this.width,
|
||||||
|
this.height,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Raccourci pour les bulles de la file d’attention.
|
||||||
|
const NineSliceAsset.card({
|
||||||
|
super.key,
|
||||||
|
required this.assetPath,
|
||||||
|
this.child,
|
||||||
|
this.padding,
|
||||||
|
this.constraints,
|
||||||
|
this.width,
|
||||||
|
this.height,
|
||||||
|
}) : spec = NineSliceSpec.cards;
|
||||||
|
|
||||||
|
/// Raccourci pour le bandeau choix enfant / nounou (ou parents).
|
||||||
|
const NineSliceAsset.bandeau({
|
||||||
|
super.key,
|
||||||
|
required this.assetPath,
|
||||||
|
this.child,
|
||||||
|
this.padding,
|
||||||
|
this.constraints,
|
||||||
|
this.width,
|
||||||
|
this.height,
|
||||||
|
}) : spec = NineSliceSpec.bandeau;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<NineSliceAsset> createState() => _NineSliceAssetState();
|
State<NineSliceAsset> createState() => _NineSliceAssetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cache partagé pour éviter de recharger le même PNG à chaque bulle.
|
||||||
|
class _NineSliceImageCache {
|
||||||
|
static final Map<String, Future<ui.Image>> _futures = {};
|
||||||
|
|
||||||
|
static Future<ui.Image> load(String path) {
|
||||||
|
return _futures.putIfAbsent(path, () async {
|
||||||
|
final data = await rootBundle.load(path);
|
||||||
|
final codec = await ui.instantiateImageCodec(
|
||||||
|
data.buffer.asUint8List(),
|
||||||
|
);
|
||||||
|
final frame = await codec.getNextFrame();
|
||||||
|
return frame.image;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _NineSliceAssetState extends State<NineSliceAsset> {
|
class _NineSliceAssetState extends State<NineSliceAsset> {
|
||||||
ui.Image? _image;
|
ui.Image? _image;
|
||||||
String? _loadedPath;
|
String? _loadedPath;
|
||||||
@@ -57,25 +130,12 @@ class _NineSliceAssetState extends State<NineSliceAsset> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_image?.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _load() async {
|
Future<void> _load() async {
|
||||||
final path = widget.assetPath;
|
final path = widget.assetPath;
|
||||||
final data = await rootBundle.load(path);
|
final image = await _NineSliceImageCache.load(path);
|
||||||
final bytes = data.buffer.asUint8List();
|
if (!mounted) return;
|
||||||
final codec = await ui.instantiateImageCodec(bytes);
|
|
||||||
final frame = await codec.getNextFrame();
|
|
||||||
if (!mounted) {
|
|
||||||
frame.image.dispose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_image?.dispose();
|
_image = image;
|
||||||
_image = frame.image;
|
|
||||||
_loadedPath = path;
|
_loadedPath = path;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -85,20 +145,22 @@ class _NineSliceAssetState extends State<NineSliceAsset> {
|
|||||||
final img = _image;
|
final img = _image;
|
||||||
final ready = img != null && _loadedPath == widget.assetPath;
|
final ready = img != null && _loadedPath == widget.assetPath;
|
||||||
|
|
||||||
return Container(
|
return SizedBox(
|
||||||
constraints: widget.constraints,
|
width: widget.width,
|
||||||
child: CustomPaint(
|
height: widget.height,
|
||||||
painter: ready
|
child: Container(
|
||||||
? _NineSlicePainter(
|
constraints: widget.constraints,
|
||||||
image: img!,
|
child: CustomPaint(
|
||||||
centerSlice: widget.centerSlice,
|
painter: ready
|
||||||
cornerWidth: widget.cornerWidth,
|
? _NineSlicePainter(
|
||||||
cornerHeight: widget.cornerHeight,
|
image: img!,
|
||||||
)
|
spec: widget.spec,
|
||||||
: null,
|
)
|
||||||
child: Padding(
|
: null,
|
||||||
padding: widget.padding ?? EdgeInsets.zero,
|
child: Padding(
|
||||||
child: widget.child,
|
padding: widget.padding ?? EdgeInsets.zero,
|
||||||
|
child: widget.child,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -107,15 +169,11 @@ class _NineSliceAssetState extends State<NineSliceAsset> {
|
|||||||
|
|
||||||
class _NineSlicePainter extends CustomPainter {
|
class _NineSlicePainter extends CustomPainter {
|
||||||
final ui.Image image;
|
final ui.Image image;
|
||||||
final Rect centerSlice;
|
final NineSliceSpec spec;
|
||||||
final double cornerWidth;
|
|
||||||
final double cornerHeight;
|
|
||||||
|
|
||||||
_NineSlicePainter({
|
_NineSlicePainter({
|
||||||
required this.image,
|
required this.image,
|
||||||
required this.centerSlice,
|
required this.spec,
|
||||||
required this.cornerWidth,
|
|
||||||
required this.cornerHeight,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -124,8 +182,8 @@ class _NineSlicePainter extends CustomPainter {
|
|||||||
|
|
||||||
final srcW = image.width.toDouble();
|
final srcW = image.width.toDouble();
|
||||||
final srcH = image.height.toDouble();
|
final srcH = image.height.toDouble();
|
||||||
|
final centerSlice = spec.centerSlice;
|
||||||
|
|
||||||
// Découpe source (pixels image) — coins / bords / centre.
|
|
||||||
final srcLeft = centerSlice.left.clamp(0.0, srcW);
|
final srcLeft = centerSlice.left.clamp(0.0, srcW);
|
||||||
final srcTop = centerSlice.top.clamp(0.0, srcH);
|
final srcTop = centerSlice.top.clamp(0.0, srcH);
|
||||||
final srcRight = centerSlice.right.clamp(0.0, srcW);
|
final srcRight = centerSlice.right.clamp(0.0, srcW);
|
||||||
@@ -138,13 +196,12 @@ class _NineSlicePainter extends CustomPainter {
|
|||||||
final srcCenterW = (srcRight - srcLeft).clamp(1.0, srcW);
|
final srcCenterW = (srcRight - srcLeft).clamp(1.0, srcW);
|
||||||
final srcCenterH = (srcBottom - srcTop).clamp(1.0, srcH);
|
final srcCenterH = (srcBottom - srcTop).clamp(1.0, srcH);
|
||||||
|
|
||||||
// Destination : coins à taille logique fixe, plafonnés à la moitié
|
final dstLeftW = spec.cornerWidth.clamp(1.0, size.width / 2);
|
||||||
// pour rester valides sur très petits widgets.
|
final dstRightW = spec.cornerWidth.clamp(1.0, size.width / 2);
|
||||||
final dstLeftW = cornerWidth.clamp(1.0, size.width / 2);
|
final dstTopH = spec.cornerHeight.clamp(1.0, size.height / 2);
|
||||||
final dstRightW = cornerWidth.clamp(1.0, size.width / 2);
|
final dstBottomH = spec.cornerHeight.clamp(1.0, size.height / 2);
|
||||||
final dstTopH = cornerHeight.clamp(1.0, size.height / 2);
|
final dstCenterW =
|
||||||
final dstBottomH = cornerHeight.clamp(1.0, size.height / 2);
|
(size.width - dstLeftW - dstRightW).clamp(0.0, size.width);
|
||||||
final dstCenterW = (size.width - dstLeftW - dstRightW).clamp(0.0, size.width);
|
|
||||||
final dstCenterH =
|
final dstCenterH =
|
||||||
(size.height - dstTopH - dstBottomH).clamp(0.0, size.height);
|
(size.height - dstTopH - dstBottomH).clamp(0.0, size.height);
|
||||||
|
|
||||||
@@ -156,7 +213,7 @@ class _NineSlicePainter extends CustomPainter {
|
|||||||
canvas.drawImageRect(image, src, dst, paint);
|
canvas.drawImageRect(image, src, dst, paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ligne du haut
|
// Haut
|
||||||
draw(
|
draw(
|
||||||
Rect.fromLTWH(0, 0, srcLeftW, srcTopH),
|
Rect.fromLTWH(0, 0, srcLeftW, srcTopH),
|
||||||
Rect.fromLTWH(0, 0, dstLeftW, dstTopH),
|
Rect.fromLTWH(0, 0, dstLeftW, dstTopH),
|
||||||
@@ -170,7 +227,7 @@ class _NineSlicePainter extends CustomPainter {
|
|||||||
Rect.fromLTWH(dstLeftW + dstCenterW, 0, dstRightW, dstTopH),
|
Rect.fromLTWH(dstLeftW + dstCenterW, 0, dstRightW, dstTopH),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ligne du milieu
|
// Milieu
|
||||||
draw(
|
draw(
|
||||||
Rect.fromLTWH(0, srcTop, srcLeftW, srcCenterH),
|
Rect.fromLTWH(0, srcTop, srcLeftW, srcCenterH),
|
||||||
Rect.fromLTWH(0, dstTopH, dstLeftW, dstCenterH),
|
Rect.fromLTWH(0, dstTopH, dstLeftW, dstCenterH),
|
||||||
@@ -184,7 +241,7 @@ class _NineSlicePainter extends CustomPainter {
|
|||||||
Rect.fromLTWH(dstLeftW + dstCenterW, dstTopH, dstRightW, dstCenterH),
|
Rect.fromLTWH(dstLeftW + dstCenterW, dstTopH, dstRightW, dstCenterH),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ligne du bas
|
// Bas
|
||||||
draw(
|
draw(
|
||||||
Rect.fromLTWH(0, srcBottom, srcLeftW, srcBottomH),
|
Rect.fromLTWH(0, srcBottom, srcLeftW, srcBottomH),
|
||||||
Rect.fromLTWH(0, dstTopH + dstCenterH, dstLeftW, dstBottomH),
|
Rect.fromLTWH(0, dstTopH + dstCenterH, dstLeftW, dstBottomH),
|
||||||
@@ -206,9 +263,6 @@ class _NineSlicePainter extends CustomPainter {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool shouldRepaint(covariant _NineSlicePainter oldDelegate) {
|
bool shouldRepaint(covariant _NineSlicePainter oldDelegate) {
|
||||||
return oldDelegate.image != image ||
|
return oldDelegate.image != image || oldDelegate.spec != spec;
|
||||||
oldDelegate.centerSlice != centerSlice ||
|
|
||||||
oldDelegate.cornerWidth != cornerWidth ||
|
|
||||||
oldDelegate.cornerHeight != cornerHeight;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user