> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adrop.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Banner Ads

> Learn how to implement banner ads in your Flutter app.

## Overview

Banner ads are rectangular ads displayed in a portion of the screen. They can be easily implemented using the `AdropBannerView` widget.

### Key Features

* Can be fixed at the top, bottom, or middle of the screen
* Supports image and video ads
* Handle ad events through callbacks
* Provides ad metadata (creative ID, campaign ID, etc.)

<Note>
  Use the test unit ID for development: `PUBLIC_TEST_UNIT_ID_320_100`
</Note>

***

## AdropBannerView

### Constructor

```dart theme={null}
AdropBannerView({
  required String unitId,
  AdropBannerListener? listener,
})
```

**Parameters**

| Parameter  | Type                  | Required | Description                               |
| ---------- | --------------------- | -------- | ----------------------------------------- |
| `unitId`   | `String`              | Y        | Unit ID created in the Ad Control Console |
| `listener` | `AdropBannerListener` | N        | Ad event listener                         |

### Properties

| Property       | Type            | Description              |
| -------------- | --------------- | ------------------------ |
| `creativeSize` | `CreativeSize?` | Ad creative size         |
| `adSize`       | `Size?`         | Banner view size setting |

### Methods

| Method      | Return Type    | Description        |
| ----------- | -------------- | ------------------ |
| `load()`    | `Future<void>` | Loads the ad       |
| `dispose()` | `Future<void>` | Releases resources |

***

## Basic Usage

```dart theme={null}
import 'package:flutter/material.dart';
import 'package:adrop_ads_flutter/adrop_ads_flutter.dart';

class BannerExample extends StatefulWidget {
  const BannerExample({super.key});

  @override
  State<BannerExample> createState() => _BannerExampleState();
}

class _BannerExampleState extends State<BannerExample> {
  bool isLoaded = false;
  late AdropBannerView bannerView;

  @override
  void initState() {
    super.initState();

    bannerView = AdropBannerView(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropBannerListener(
        onAdReceived: (unitId, metadata) {
          debugPrint('Banner ad received: $unitId');
          setState(() {
            isLoaded = true;
          });
        },
        onAdClicked: (unitId, metadata) {
          debugPrint('Banner ad clicked: $unitId');
        },
        onAdImpression: (unitId, metadata) {
          debugPrint('Banner ad impression: $unitId');
        },
        onAdFailedToReceive: (unitId, errorCode) {
          debugPrint('Banner ad failed: $unitId, $errorCode');
          setState(() {
            isLoaded = false;
          });
        },
      ),
    );

    // Load ad
    bannerView.load();
  }

  @override
  void dispose() {
    bannerView.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Banner Ad Example')),
      body: Column(
        children: [
          // Main content
          Expanded(
            child: Center(
              child: const Text('Main Content'),
            ),
          ),
          // Banner ad
          if (isLoaded)
            SizedBox(
              width: MediaQuery.of(context).size.width,
              height: 80,
              child: bannerView,
            ),
        ],
      ),
    );
  }
}
```

***

## AdropBannerListener

A listener that handles banner ad events.

### Callbacks

```dart theme={null}
AdropBannerListener(
  onAdReceived: (String unitId, Map<String, dynamic>? metadata) {
    // Ad received successfully
  },
  onAdClicked: (String unitId, Map<String, dynamic>? metadata) {
    // Ad clicked
  },
  onAdImpression: (String unitId, Map<String, dynamic>? metadata) {
    // Ad impression
  },
  onAdFailedToReceive: (String unitId, AdropErrorCode errorCode) {
    // Ad failed to receive
  },
  onAdVideoStart: (String unitId) {
    // Video ad started playing
  },
  onAdVideoEnd: (String unitId) {
    // Video ad finished playing
  },
)
```

### Callback Descriptions

| Callback              | Description                             |
| --------------------- | --------------------------------------- |
| `onAdReceived`        | Called when ad is received successfully |
| `onAdClicked`         | Called when ad is clicked               |
| `onAdImpression`      | Called when ad is displayed             |
| `onAdFailedToReceive` | Called when ad fails to load            |
| `onAdVideoStart`      | Called when video ad starts playing     |
| `onAdVideoEnd`        | Called when video ad finishes playing   |

### Metadata

You can receive metadata in the `onAdReceived`, `onAdClicked`, and `onAdImpression` callbacks.

```dart theme={null}
onAdReceived: (unitId, metadata) {
  debugPrint('Creative ID: ${metadata?['creativeId']}');
  debugPrint('Transaction ID: ${metadata?['txId']}');
  debugPrint('Campaign ID: ${metadata?['campaignId']}');
  debugPrint('Destination URL: ${metadata?['destinationURL']}');
  debugPrint('Browser Target: ${metadata?['browserTarget']}');
}
```

| Field            | Type     | Description                               |
| ---------------- | -------- | ----------------------------------------- |
| `creativeId`     | `String` | Creative ID                               |
| `txId`           | `String` | Transaction ID                            |
| `campaignId`     | `String` | Campaign ID                               |
| `destinationURL` | `String` | Destination URL                           |
| `browserTarget`  | `int?`   | Browser target (0: external, 1: internal) |

<Note>
  Creative size is accessed via `bannerView.creativeSize?.width` and `bannerView.creativeSize?.height`, not through metadata.
</Note>

***

## Ad Sizes

Banner ads require specifying container size according to the unit settings.

### Common Banner Sizes

| Size      | Test Unit ID                  | Usage         |
| --------- | ----------------------------- | ------------- |
| 320 x 50  | `PUBLIC_TEST_UNIT_ID_320_50`  | Small banner  |
| 320 x 100 | `PUBLIC_TEST_UNIT_ID_320_100` | Medium banner |

### Fixed Size Usage

```dart theme={null}
SizedBox(
  width: 320,
  height: 100,
  child: bannerView,
)
```

### Fit to Screen Width

```dart theme={null}
SizedBox(
  width: MediaQuery.of(context).size.width,
  height: 80,
  child: bannerView,
)
```

### Size Configuration

You can explicitly set the banner view size using the `adSize` property.

```dart theme={null}
@override
void initState() {
  super.initState();

  bannerView = AdropBannerView(
    unitId: 'YOUR_UNIT_ID',
    listener: AdropBannerListener(
      onAdReceived: (unitId, metadata) {
        setState(() {
          isLoaded = true;
        });
      },
    ),
  );

  // Set size after context is ready
  WidgetsBinding.instance.addPostFrameCallback((_) {
    bannerView.adSize = Size(
      MediaQuery.of(context).size.width,
      80,
    );
  });
}
```

***

## Error Handling

Implement proper error handling when ad loading fails.

```dart theme={null}
class _BannerExampleState extends State<BannerExample> {
  bool isLoaded = false;
  AdropErrorCode? errorCode;
  late AdropBannerView bannerView;

  @override
  void initState() {
    super.initState();

    bannerView = AdropBannerView(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropBannerListener(
        onAdReceived: (unitId, metadata) {
          setState(() {
            isLoaded = true;
            errorCode = null;
          });
        },
        onAdFailedToReceive: (unitId, error) {
          setState(() {
            isLoaded = false;
            errorCode = error;
          });
        },
      ),
    );

    bannerView.load();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        if (isLoaded)
          SizedBox(
            width: MediaQuery.of(context).size.width,
            height: 80,
            child: bannerView,
          )
        else if (errorCode != null)
          Text('Ad load failed: ${errorCode?.code}'),
      ],
    );
  }

  @override
  void dispose() {
    bannerView.dispose();
    super.dispose();
  }
}
```

***

## Best Practices

### 1. Release Resources

Always call `dispose()` when the banner view is no longer needed.

```dart theme={null}
@override
void dispose() {
  bannerView.dispose();
  super.dispose();
}
```

### 2. Refresh Ads

You can refresh ads as needed.

```dart theme={null}
void refreshAd() {
  setState(() {
    isLoaded = false;
  });
  bannerView.load();
}
```

### 3. Conditional Rendering

Hide the banner area or show a placeholder until the ad loads.

```dart theme={null}
Widget buildBanner() {
  if (isLoaded) {
    return SizedBox(
      width: MediaQuery.of(context).size.width,
      height: 80,
      child: bannerView,
    );
  } else if (isLoading) {
    return const SizedBox(
      height: 80,
      child: Center(child: CircularProgressIndicator()),
    );
  } else {
    return const SizedBox.shrink();
  }
}
```

### 4. Managing Multiple Banners

When using multiple banners, manage each state separately.

```dart theme={null}
class _MultiBannerState extends State<MultiBanner> {
  late AdropBannerView topBanner;
  late AdropBannerView bottomBanner;
  bool isTopLoaded = false;
  bool isBottomLoaded = false;

  @override
  void initState() {
    super.initState();

    topBanner = AdropBannerView(
      unitId: 'TOP_UNIT_ID',
      listener: AdropBannerListener(
        onAdReceived: (_, __) => setState(() => isTopLoaded = true),
      ),
    );

    bottomBanner = AdropBannerView(
      unitId: 'BOTTOM_UNIT_ID',
      listener: AdropBannerListener(
        onAdReceived: (_, __) => setState(() => isBottomLoaded = true),
      ),
    );

    topBanner.load();
    bottomBanner.load();
  }

  @override
  void dispose() {
    topBanner.dispose();
    bottomBanner.dispose();
    super.dispose();
  }

  // ...
}
```

***

## Complete Example

```dart theme={null}
import 'package:flutter/material.dart';
import 'package:adrop_ads_flutter/adrop_ads_flutter.dart';

class BannerAdPage extends StatefulWidget {
  const BannerAdPage({super.key});

  @override
  State<BannerAdPage> createState() => _BannerAdPageState();
}

class _BannerAdPageState extends State<BannerAdPage> {
  static const double bannerHeight = 80;
  bool isLoaded = false;
  bool isLoading = false;
  AdropErrorCode? errorCode;
  late AdropBannerView bannerView;

  @override
  void initState() {
    super.initState();

    bannerView = AdropBannerView(
      unitId: 'PUBLIC_TEST_UNIT_ID_320_100', // Test unit ID
      listener: AdropBannerListener(
        onAdReceived: (unitId, metadata) {
          debugPrint('Ad received successfully');
          debugPrint('Creative ID: ${metadata?['creativeId']}');
          debugPrint('Campaign ID: ${metadata?['campaignId']}');
          debugPrint('Creative size: ${bannerView.creativeSize?.width}x${bannerView.creativeSize?.height}');
          setState(() {
            isLoaded = true;
            isLoading = false;
            errorCode = null;
          });
        },
        onAdClicked: (unitId, metadata) {
          debugPrint('Ad clicked: ${metadata?['destinationURL']}');
        },
        onAdImpression: (unitId, metadata) {
          debugPrint('Ad impression: ${metadata?['creativeId']}');
        },
        onAdFailedToReceive: (unitId, error) {
          debugPrint('Ad failed: $error');
          setState(() {
            isLoaded = false;
            isLoading = false;
            errorCode = error;
          });
        },
      ),
    );

    WidgetsBinding.instance.addPostFrameCallback((_) {
      bannerView.adSize = Size(
        MediaQuery.of(context).size.width,
        bannerHeight,
      );
    });
  }

  void loadAd() {
    setState(() {
      isLoading = true;
      errorCode = null;
    });
    bannerView.load();
  }

  @override
  void dispose() {
    bannerView.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Banner Ad Example'),
      ),
      body: SafeArea(
        child: Column(
          children: [
            // Load button
            Padding(
              padding: const EdgeInsets.all(16),
              child: ElevatedButton(
                onPressed: isLoading ? null : loadAd,
                child: Text(isLoading ? 'Loading...' : 'Load Banner Ad'),
              ),
            ),

            // Status display
            if (errorCode != null)
              Padding(
                padding: const EdgeInsets.all(16),
                child: Text(
                  'Error: ${errorCode?.code}',
                  style: const TextStyle(color: Colors.red),
                ),
              ),

            // Main content
            const Expanded(
              child: Center(
                child: Text('Main Content Area'),
              ),
            ),

            // Banner ad
            Container(
              width: MediaQuery.of(context).size.width,
              height: bannerHeight,
              color: Colors.grey[200],
              child: isLoaded
                  ? bannerView
                  : isLoading
                      ? const Center(child: CircularProgressIndicator())
                      : const Center(child: Text('Ad Area')),
            ),
          ],
        ),
      ),
    );
  }
}
```

***

## Backfill Ads

When backfill ads are enabled, backfill ads are automatically loaded when direct ads are unavailable. Backfill ad loading is handled automatically by the SDK. You can handle backfill-related errors using the `backfillNoFill` error code.

```dart theme={null}
bannerView = AdropBannerView(
  unitId: 'YOUR_UNIT_ID',
  listener: AdropBannerListener(
    onAdReceived: (unitId, metadata) {
      debugPrint('Ad loaded');
      setState(() {
        isLoaded = true;
      });
    },
    onAdFailedToReceive: (unitId, errorCode) {
      switch (errorCode) {
        case AdropErrorCode.adNoFill:
          debugPrint('No direct ad available');
          break;
        case AdropErrorCode.backfillNoFill:
          debugPrint('No backfill ad available either');
          // Hide ad area
          break;
        default:
          debugPrint('Ad load failed: ${errorCode.code}');
      }
    },
  ),
);
```

<Note>
  Banner ad metadata only includes the `creativeId`, `txId`, `campaignId`, `destinationURL`, and `browserTarget` fields. Backfill ads cannot be distinguished through metadata. You can detect backfill ad failures using the `backfillNoFill` error code.
</Note>

<Note>
  To use backfill ads, add the backfill dependency to native platforms. See [Getting Started](/sdk/flutter/overview).
</Note>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Native Ads" href="/sdk/flutter/native">
    Implement customizable native ads that match your UI
  </Card>

  <Card title="Interstitial Ads" href="/sdk/flutter/interstitial">
    Implement full-screen interstitial ads
  </Card>

  <Card title="Popup Ads" href="/sdk/flutter/popup">
    Implement popup-style ads
  </Card>

  <Card title="Reference" href="/sdk/flutter/reference">
    View types, methods, and error codes
  </Card>
</CardGroup>
