sports_ground 1.2.0
sports_ground: ^1.2.0 copied to clipboard
A comprehensive Flutter package for creating beautiful, interactive sports grounds with drag-and-drop players, team management, and realistic field rendering.
import 'package:flutter/material.dart';
import 'package:sports_ground/sports_ground.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sports Ground Examples',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
useMaterial3: true,
),
home: const ExampleHomePage(),
);
}
}
class ExampleHomePage extends StatelessWidget {
const ExampleHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sports Ground Examples'),
backgroundColor: Colors.green.shade800,
foregroundColor: Colors.white,
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
_buildSportCard(
context,
'Rugby Ground',
'Interactive rugby field with player management',
Icons.sports_rugby,
Colors.green,
() => Navigator.push(
context,
MaterialPageRoute(builder: (context) => const RugbyExample()),
),
),
const SizedBox(height: 16),
_buildComingSoonCard(
'Football Ground', Icons.sports_soccer, Colors.blue),
const SizedBox(height: 16),
_buildComingSoonCard(
'Basketball Court', Icons.sports_basketball, Colors.orange),
const SizedBox(height: 16),
_buildSportCard(
context,
'Tennis Court',
'Professional tennis court with realistic surfaces',
Icons.sports_tennis,
Colors.purple,
() => Navigator.push(
context,
MaterialPageRoute(builder: (context) => const TennisExample()),
),
),
],
),
);
}
Widget _buildSportCard(
BuildContext context,
String title,
String description,
IconData icon,
Color color,
VoidCallback onTap,
) {
return Card(
elevation: 4,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: color.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: color, size: 32),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
description,
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
),
],
),
),
Icon(Icons.arrow_forward_ios, color: Colors.grey[400]),
],
),
),
),
);
}
Widget _buildComingSoonCard(String title, IconData icon, Color color) {
return Card(
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: Colors.grey, size: 32),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.grey[600],
),
),
const SizedBox(height: 4),
Text(
'Coming Soon',
style: TextStyle(
fontSize: 14,
color: Colors.grey[500],
fontStyle: FontStyle.italic,
),
),
],
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: Colors.orange.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
),
child: Text(
'Soon',
style: TextStyle(
fontSize: 12,
color: Colors.orange[700],
fontWeight: FontWeight.w600,
),
),
),
],
),
),
);
}
}
class TennisExample extends StatefulWidget {
const TennisExample({super.key});
@override
State<TennisExample> createState() => _TennisExampleState();
}
class _TennisExampleState extends State<TennisExample> {
late List<TennisPlayer> homePlayers;
late List<TennisPlayer> awayPlayers;
late TennisScore score;
TennisCourtSurface courtSurface = TennisCourtSurface.hard;
TennisMatchType matchType = TennisMatchType.singlesMen;
TennisViewAngle viewAngle = TennisViewAngle.top;
@override
void initState() {
super.initState();
_initializePlayers();
_initializeScore();
}
void _initializePlayers() {
homePlayers = [
TennisPlayer(
id: 'h1',
name: 'Rafael Nadal',
fieldPosition: const Offset(200, 150),
isHomeTeam: true,
stats: {
'Aces': 12,
'Winners': 28,
'Unforced Errors': 15,
'Break Points': '3/5',
},
),
];
awayPlayers = [
TennisPlayer(
id: 'a1',
name: 'Novak Djokovic',
fieldPosition: const Offset(200, 450),
isHomeTeam: false,
stats: {
'Aces': 8,
'Winners': 22,
'Unforced Errors': 12,
'Break Points': '2/4',
},
),
];
}
void _initializeScore() {
score = TennisScore(
homeGames: 6,
awayGames: 4,
homeSets: 2,
awaySets: 1,
homePoints: '30',
awayPoints: '15',
currentSet: 4,
setHistory: [
[6, 4],
[4, 6],
[7, 5],
],
);
}
@override
Widget build(BuildContext context) {
return TennisGround(
homePlayers: homePlayers,
awayPlayers: awayPlayers,
homeTeamName: 'Nadal',
awayTeamName: 'Djokovic',
homeTeamColor: Colors.orange,
awayTeamColor: Colors.blue,
score: score,
courtSurface: courtSurface,
matchType: matchType,
viewAngle: viewAngle,
onPlayerTap: (player) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Selected ${player.name}'),
duration: const Duration(seconds: 1),
),
);
},
onSurfaceChange: (surface) {
setState(() {
courtSurface = surface;
});
},
onViewAngleChange: (angle) {
setState(() {
viewAngle = angle;
});
},
);
}
}
class RugbyExample extends StatefulWidget {
const RugbyExample({super.key});
@override
State<RugbyExample> createState() => _RugbyExampleState();
}
class _RugbyExampleState extends State<RugbyExample> {
late List<RugbyPlayer> homeTeam;
late List<RugbyPlayer> awayTeam;
int homeScore = 15;
int awayScore = 12;
@override
void initState() {
super.initState();
_initializeTeams();
}
void _initializeTeams() {
homeTeam = [
RugbyPlayer(
id: 'h1',
name: 'John Smith',
position: 'Fullback',
jerseyNumber: 15,
fieldPosition: const Offset(200, 80),
isHomeTeam: true,
stats: {'Tries': 3, 'Tackles': 12, 'Passes': 45},
),
RugbyPlayer(
id: 'h2',
name: 'Mike Johnson',
position: 'Wing',
jerseyNumber: 14,
fieldPosition: const Offset(100, 100),
isHomeTeam: true,
stats: {'Tries': 5, 'Tackles': 8, 'Passes': 23},
),
RugbyPlayer(
id: 'h3',
name: 'David Wilson',
position: 'Centre',
jerseyNumber: 13,
fieldPosition: const Offset(150, 130),
isHomeTeam: true,
stats: {'Tries': 2, 'Tackles': 15, 'Passes': 67},
),
RugbyPlayer(
id: 'h4',
name: 'Chris Brown',
position: 'Centre',
jerseyNumber: 12,
fieldPosition: const Offset(250, 130),
isHomeTeam: true,
stats: {'Tries': 1, 'Tackles': 18, 'Passes': 52},
),
RugbyPlayer(
id: 'h5',
name: 'Tom Davis',
position: 'Wing',
jerseyNumber: 11,
fieldPosition: const Offset(300, 100),
isHomeTeam: true,
stats: {'Tries': 4, 'Tackles': 6, 'Passes': 19},
),
RugbyPlayer(
id: 'h6',
name: 'Alex Miller',
position: 'Fly-half',
jerseyNumber: 10,
fieldPosition: const Offset(200, 160),
isHomeTeam: true,
stats: {'Tries': 2, 'Tackles': 10, 'Passes': 89},
),
RugbyPlayer(
id: 'h7',
name: 'Sam Taylor',
position: 'Scrum-half',
jerseyNumber: 9,
fieldPosition: const Offset(200, 190),
isHomeTeam: true,
stats: {'Tries': 1, 'Tackles': 14, 'Passes': 156},
),
];
awayTeam = [
RugbyPlayer(
id: 'a1',
name: 'James Anderson',
position: 'Fullback',
jerseyNumber: 15,
fieldPosition: const Offset(200, 520),
isHomeTeam: false,
stats: {'Tries': 2, 'Tackles': 16, 'Passes': 38},
),
RugbyPlayer(
id: 'a2',
name: 'Robert Lee',
position: 'Wing',
jerseyNumber: 14,
fieldPosition: const Offset(100, 500),
isHomeTeam: false,
stats: {'Tries': 3, 'Tackles': 9, 'Passes': 21},
),
RugbyPlayer(
id: 'a3',
name: 'Paul White',
position: 'Centre',
jerseyNumber: 13,
fieldPosition: const Offset(150, 470),
isHomeTeam: false,
stats: {'Tries': 1, 'Tackles': 20, 'Passes': 43},
),
RugbyPlayer(
id: 'a4',
name: 'Mark Green',
position: 'Centre',
jerseyNumber: 12,
fieldPosition: const Offset(250, 470),
isHomeTeam: false,
stats: {'Tries': 0, 'Tackles': 22, 'Passes': 56},
),
RugbyPlayer(
id: 'a5',
name: 'Steve Clark',
position: 'Wing',
jerseyNumber: 11,
fieldPosition: const Offset(300, 500),
isHomeTeam: false,
stats: {'Tries': 2, 'Tackles': 7, 'Passes': 18},
),
RugbyPlayer(
id: 'a6',
name: 'Kevin Hall',
position: 'Fly-half',
jerseyNumber: 10,
fieldPosition: const Offset(200, 440),
isHomeTeam: false,
stats: {'Tries': 1, 'Tackles': 11, 'Passes': 72},
),
RugbyPlayer(
id: 'a7',
name: 'Ryan Young',
position: 'Scrum-half',
jerseyNumber: 9,
fieldPosition: const Offset(200, 410),
isHomeTeam: false,
stats: {'Tries': 0, 'Tackles': 13, 'Passes': 134},
),
];
}
@override
Widget build(BuildContext context) {
return RugbyGround(
homeTeam: homeTeam,
awayTeam: awayTeam,
homeTeamName: 'Lions',
awayTeamName: 'Eagles',
homeTeamColor: Colors.blue,
awayTeamColor: Colors.red,
homeScore: homeScore,
awayScore: awayScore,
onPlayerTap: (player) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Tapped on ${player.name} (#${player.jerseyNumber})'),
duration: const Duration(seconds: 1),
),
);
},
onPlayerDrag: (player, position) {
// Handle player position updates
},
);
}
}