GridView Multiple Item Types

To display grid items with varied layouts in the same GridView, use a Conditional Builder as the child template. This allows you to create dynamic grids where different items can have completely different visual representations—perfect for product catalogs with featured items, photo galleries with different media types, or dashboards with mixed widgets.

An example showing a GridView with different item types: featured items, regular items, and promotional tiles.
Use Conditional Builder to render different layouts per grid item type.

When to Use This Pattern

Use this approach when your grid contains items of different types that need different visual layouts:

  • Product catalogs - Mix regular products, featured products, and promotional banners

  • Photo galleries - Display photos, videos, and placeholders with different layouts

  • Dashboards - Combine metric cards, charts, and quick action tiles

  • App launchers - Show apps, folders, and widgets with varied presentations

  • Category grids - Mix category cards, promotional tiles, and navigation items

How It Works

The key is to include a type identifier in your data source, then use a Conditional Builder to check that type and render the appropriate layout for each grid item.

Step-by-Step Implementation

1. Structure Your Data Source

Your data array should include a property that identifies the item type:

[
  {
    "type": "regular",
    "name": "Product 1",
    "image": "product1.jpg",
    "price": 29.99
  },
  {
    "type": "featured",
    "name": "Premium Product",
    "image": "featured.jpg",
    "price": 99.99,
    "badge": "Best Seller"
  },
  {
    "type": "promo",
    "title": "Special Offer",
    "description": "50% Off This Week",
    "ctaText": "Shop Now"
  }
]

The type field determines which layout to render for each grid item.

2. Add a Conditional Builder as the GridView Child

  1. Select your GridView widget

  2. Add a Conditional Builder as the single child

  3. The Conditional Builder will be repeated for each item in the data source

3. Create Conditions Based on Item Type

In the Conditional Builder, add conditions that check the type property of currentItem:

Condition 1: ${isEqual(currentItem.type, 'regular')}

  • Build a standard product card layout

Condition 2: ${isEqual(currentItem.type, 'featured')}

  • Build an enhanced featured product layout with badge

Condition 3: ${isEqual(currentItem.type, 'promo')}

  • Build a promotional banner layout

Default Case:

  • Optionally add a fallback layout for unknown types

Example Layouts

Regular Product Card

Card:
  Column:
    Image:
      URL: ${currentItem.image}
      Aspect Ratio: 1.0
    
    Padding:
      Column:
        Text:
          Text: ${currentItem.name}
          Weight: Bold
        
        Text:
          Text: ${concat("$", currentItem.price)}
          Color: Primary
Card:
  Stack:
    Image:
      URL: ${currentItem.image}
      Aspect Ratio: 1.0
    
    Positioned (Top-right badge):
      Container:
        Background: Gold
        Text: ${currentItem.badge}
    
    Positioned (Bottom):
      Container:
        Background: Semi-transparent
        Column:
          Text: ${currentItem.name}
          Text: ${concat("$", currentItem.price)}

Promotional Banner

Card:
  Background: Gradient
  Center:
    Column:
      Icon: local_offer
      Text:
        Text: ${currentItem.title}
        Size: Large
      Text:
        Text: ${currentItem.description}
      Button:
        Text: ${currentItem.ctaText}

Advanced Patterns

Spanning Multiple Grid Cells

Note that in GridView, all items occupy the same grid cell size determined by the Cross Axis Count and Child Aspect Ratio. You cannot make a single item span multiple columns or rows like in traditional CSS Grid.

Workaround: If you need items to span multiple cells, consider:

  • Using a Wrap widget with custom-sized children

  • Using a Column with Rows for custom layouts

  • Implementing a custom layout using Positioned widgets inside a Stack

Dynamic Item Sizing Within Constraints

While all grid items have the same cell size, you can vary the content size within each cell:

Conditional Builder:
  Condition: ${isEqual(currentItem.type, 'large')}
  
  True:
    Card (fills entire cell):
      Image: Full cell
  
  False:
    Card (padded, smaller):
      Padding: 8px
      Image: Smaller image with padding

Mixed Aspect Ratios

If you need dramatically different aspect ratios, consider using different GridViews stacked vertically or use a ListView with Rows containing varied numbers of items.

Grid Layout Considerations

Maintaining Visual Balance

When using multiple item types in a grid:

  • Keep proportions consistent: Even with different layouts, maintain visual weight balance

  • Use consistent spacing: Keep padding and margins uniform across item types

  • Align baselines: Try to align text and key elements across different item types

  • Color harmony: Use a consistent color palette even with varied layouts

Ordering Strategy

Consider how you order mixed item types:

[
  {"type": "regular", ...},
  {"type": "regular", ...},
  {"type": "featured", ...},  // Featured item after 2 regulars
  {"type": "regular", ...},
  {"type": "promo", ...},      // Promo after 4 items
  ...
]

Strategic placement of special items creates visual interest without overwhelming the grid.

Accessing currentItem in Each Branch

Remember that ${currentItem} and ${index} are available in all branches of the Conditional Builder:

  • Regular items: ${currentItem.name}, ${currentItem.price}

  • Featured items: ${currentItem.badge}, ${currentItem.discount}

  • Promo items: ${currentItem.title}, ${currentItem.ctaText}

  • All items: ${index} for position-based logic

Using Index for Patterns

Conditional Builder:
  Condition: ${isEqual(modulo(sum(index, 1), 6), 0)}
  
  True:
    // Every 6th item is a promotional banner
    PromoCard
  
  False:
    // Regular product layout
    ProductCard

Best Practices

  • Keep type identifiers consistent: Use clear, predictable type names like "regular", "featured", "promo"

  • Handle unknown types gracefully: Always include a default case in your Conditional Builder

  • Maintain grid cohesion: Even with varied layouts, keep items visually connected through consistent spacing, colors, and sizing

  • Test different screen sizes: Ensure layouts work well with different Cross Axis Counts

  • Limit variety: Too many different item types can create visual chaos; stick to 2-4 types maximum

  • Use type for functionality: Different types can have different tap behaviors or navigation destinations

Performance Considerations

  • Conditional Builder is lightweight: It doesn't significantly impact performance; only one branch renders per item

  • Optimize complex layouts: If some item types are heavy (e.g., with videos), consider lazy loading or placeholders

  • Cache images: Use image caching for better scroll performance

  • Keep templates efficient: Even with varied layouts, maintain lightweight widget trees

Common Use Cases

Product Grid with Ads

[
  {"type": "product", "name": "Item 1", ...},
  {"type": "product", "name": "Item 2", ...},
  {"type": "product", "name": "Item 3", ...},
  {"type": "ad", "title": "Special Offer", ...},
  {"type": "product", "name": "Item 4", ...},
  ...
]
[
  {"type": "photo", "url": "photo1.jpg", ...},
  {"type": "photo", "url": "photo2.jpg", ...},
  {"type": "video", "url": "video1.mp4", "thumbnail": "thumb1.jpg", ...},
  {"type": "photo", "url": "photo3.jpg", ...},
  ...
]

Dashboard with Widgets

[
  {"type": "metric", "title": "Sales", "value": "1,234", ...},
  {"type": "chart", "chartType": "line", "data": [...], ...},
  {"type": "metric", "title": "Users", "value": "567", ...},
  {"type": "action", "title": "Quick Action", "icon": "add", ...},
  ...
]

Last updated