2

New developer here, need some expertise. I am attempting to create a custom staggered grid view that also allows each tile to be tappable and goes to different pages.

I have tried using inkwell but I cant seem to do that for each individual tile. That then leads to Gesture detector. I can wrap the entire grid view to be tappable with gesture detector, however that makes the entire grid tap-able and all goes to one single page.

Any idea how I can make each individual tile tappable to then link it to another page? When ever I try to do it for each, it completely breaks the layout. Makes each tile the same size. I then tried making each tile size customizable but that didnt work. I attempted to use chatGPT to make it all customizable but it cant quite get there. Ignore the top image asset.

Any and all help is appreciated. Even if I need to use something else to build what il looking to do. See example image of its current state.

actual state of app now, screenshot of phone

using visual studio on windows

dependencies: flutter: sdk: flutter

cupertino_icons: ^1.0.2 google_fonts: ^5.1.0 flutter_staggered_grid_view: ^0.7.0

I have tried using chat GPT to ask it do make each tile tappable, keep the original tile size, each tile points to a different page but I keep going down a web and ever longer code base and it eventually cant gat to what I need it to do.

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  google_fonts: ^5.1.0
  flutter_staggered_grid_view: ^0.7.0

import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:google_fonts/google_fonts.dart';

class FantasyHome extends StatelessWidget {
  const FantasyHome({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('new app'),
        centerTitle: true,
      ),
      body: Column(
        children: [
          Image.asset(
            'assets/images/bannerbig.png',
            fit: BoxFit.cover,
            width: double.infinity,
          ),
          Expanded(
            child: SingleChildScrollView(
              child: GestureDetector(
                // Wraped the StaggeredGrid with GestureDetector
                onTap: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => PointsPage(),
                    ),
                  );
                },
                child: StaggeredGrid.count(
                  crossAxisCount: 4,
                  mainAxisSpacing: 4,
                  crossAxisSpacing: 4,
                  children: const [
                    StaggeredGridTile.count(
                      crossAxisCellCount: 2,
                      mainAxisCellCount: 2,
                      child: Tile(
                        index: 0,
                        color: Color.fromARGB(255, 255, 255, 255),
                        customText: '50\npoints',
                        fontSize: 30,
                      ),
                    ),
                    StaggeredGridTile.count(
                      crossAxisCellCount: 2,
                      mainAxisCellCount: 1,
                      child: Tile(
                        index: 1,
                        color: Color.fromARGB(255, 129, 173, 180),
                        customText: 'Leagues',
                      ),
                    ),
                    StaggeredGridTile.count(
                      crossAxisCellCount: 1,
                      mainAxisCellCount: 1,
                      child: Tile(
                        index: 2,
                        color: Colors.green,
                        customText: 'Stats',
                      ),
                    ),
                    StaggeredGridTile.count(
                      crossAxisCellCount: 1,
                      mainAxisCellCount: 1,
                      child: Tile(
                        index: 3,
                        color: Colors.red,
                        customText: 'Custom Text for Tile 3',
                      ),
                    ),
                    StaggeredGridTile.count(
                      crossAxisCellCount: 4,
                      mainAxisCellCount: 2,
                      child: Tile(
                        index: 4,
                        color: Colors.purple,
                        customText: 'Custom Text for Tile 4',
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class Tile extends StatelessWidget {
  final int index;
  final Color color;
  final double fontSize;
  final String? customText;

  const Tile({
    required this.index,
    required this.color,
    this.fontSize = 15, // Provide a default value for fontSize.
    this.customText,
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Card(
      color: color,
      child: Center(
        child: Text(
          customText ?? 'Tile $index',
          style: GoogleFonts.openSans(
            fontSize: fontSize,
            color: const Color.fromARGB(255, 0, 0, 0),
          ),
        ),
      ),
    );
  }
}

// Placeholder page for demonstration purposes.
class PointsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Points Page')),
      body: Center(child: Text('Points Page Content')),
    );
  }
}

from the comment I tried this: 

import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:google_fonts/google_fonts.dart';

class FantasyHome extends StatelessWidget {
  const FantasyHome({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('new app'),
        centerTitle: true,
      ),
      body: Column(
        children: [
          Image.asset(
            'assets/images/bannerbig.png',
            fit: BoxFit.cover,
            width: double.infinity,
          ),
          Expanded(
            child: SingleChildScrollView(
              child: GestureDetector(
                // Wrap the StaggeredGrid with GestureDetector
                onTap: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => PointsPage(),
                    ),
                  );
                },
                child: StaggeredGridView.countBuilder(
                  crossAxisCount: 4,
                  itemCount: 4,
                  mainAxisSpacing: 4,
                  crossAxisSpacing: 4,
                  staggeredTileBuilder: (index) => StaggeredTile.fit(2),
                  itemBuilder: (context, index) {
                    return GestureDetector(
                      onTap: () {
                        switch (index) {
                          case 0:
                            Navigator.pushNamed(context, '/tile1');
                            break;
                          case 1:
                            Navigator.pushNamed(context, '/tile2');
                            break;
                          case 2:
                            Navigator.pushNamed(context, '/tile3');
                            break;
                          case 3:
                            Navigator.pushNamed(context, '/tile4');
                            break;
                        }
                      },
                      child: Tile(
                        index: index,
                        color: index == 0
                            ? Color.fromARGB(255, 255, 255, 255)
                            : index == 1
                                ? Color.fromARGB(255, 129, 173, 180)
                                : index == 2
                                    ? Colors.green
                                    : Colors.red,
                        customText: index == 0 ? '50\npoints' : 'Custom Text for Tile $index',
                        fontSize: index == 0 ? 30 : 15,
                      ),
                    );
                  },
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class Tile extends StatelessWidget {
  final int index;
  final Color color;
  final double fontSize;
  final String? customText;

  const Tile({
    required this.index,
    required this.color,
    this.fontSize = 15, // Provide a default value for fontSize.
    this.customText,
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Card(
      color: color,
      child: Center(
        child: Text(
          customText ?? 'Tile $index',
          style: GoogleFonts.openSans(
            fontSize: fontSize,
            color: const Color.fromARGB(255, 0, 0, 0),
          ),
        ),
      ),
    );
  }
}

// Placeholder page for demonstration purposes.
class PointsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Points Page')),
      body: Center(child: Text('Points Page Content')),
    );
  }
}

void main() {
  runApp(MaterialApp(
    home: FantasyHome(),
    routes: {
      // Define routes for individual pages
      '/tile1': (context) => TilePage(tile: tiles[0]),
      '/tile2': (context) => TilePage(tile: tiles[1]),
      '/tile3': (context) => TilePage(tile: tiles[2]),
      '/tile4': (context) => TilePage(tile: tiles[3]),
    },
  ));
}

// Sample data for the tiles
final List<TileModel> tiles = [
  TileModel(title: 'Tile 1', description: 'Description for Tile 1'),
  TileModel(title: 'Tile 2', description: 'Description for Tile 2'),
  TileModel(title: 'Tile 3', description: 'Description for Tile 3'),
  TileModel(title: 'Tile 4', description: 'Description for Tile 4'),
];

class TileModel {
  final String title;
  final String description;

  TileModel({required this.title, required this.description});
}

class TilePage extends StatelessWidget {
  final TileModel tile;

  TilePage({required this.tile});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(tile.title)),
      body: Center(
        child: Text(tile.description),
      ),
    );
  }
}


But that made this happen: enter image description here

Ben2522
  • 21
  • 3
  • 1
    How does making each tile tappable break the layout? That should be the go-to way. Like, let every tile handle its own callback or so. Are you saying there's no way to customize the UI of each tile independently when the tiles are tappable? – Obum Jul 30 '23 at 22:49
  • hi. im saying that when I add gesture detector to rach time, it completley breaks the layout. I will update the question to show the result. – Ben2522 Jul 31 '23 at 07:45

1 Answers1

2

In your Tile widget, wrap the Card with a GestureDetector or InkWell and set the onTap handler to do what you want when tapped.

GestureDetector and InkWell are both 'invisible' widgets that will not change the layout or appearance of your app. Use InkWell if you want the material splash of colour when tapped, otherwise use GestureDetector.

pgs
  • 13,385
  • 2
  • 25
  • 17
  • See attached edited question code and image to show what happens. Let me know if you know what I did wrong. Thanks for your help – Ben2522 Jul 31 '23 at 07:47
  • Why did you put a GestureDetector around the StaggeredGridView? You should only need one around each Tile (my preference is to have it in the Tile). – pgs Jul 31 '23 at 23:45