# SDK Native - Customizations

## Native SDK — Customizations

> **Prerequisite:** Complete the [Native SDK - Quick Start](/ios/sdk-native.md) first.

These customizations require **no custom cell class** — you configure the built-in default renderer or extend it with small tweaks.

***

### 1. Configuration Options

#### 1.1 Scroll Direction

```swift
// Horizontal (default)
adView.setOrientation(.horizontal)

// Vertical list
adView.setOrientation(.vertical)
```

<figure><img src="/files/U7cfOCrayZHgA7SwNMss" alt="" width="308"><figcaption></figcaption></figure>

#### 1.2 Maximum Number of Campaigns

```swift
adView.setMaxCampaigns(5)   // Show at most 5 campaigns
adView.setMaxCampaigns(0)   // Show all (default)
```

#### 1.3 Open Campaign Details In-App

By default, tapping a campaign opens in Safari. To keep users inside your app:

```swift
MCOfferwallSDK.shared.setOpenInApp(true)
```

When `openInApp` is `true`, the SDK presents `MCWebViewController` from the nearest `UIViewController` in the responder chain. For tighter control, you can pin the presenting view controller explicitly:

```swift
adView.presentingController = self   // 'self' is your UIViewController
```

***

### 2. Change the Currency Icon

The default renderer shows a coin icon next to the reward value.

<figure><img src="/files/cS0ENLiiqrcaAWMqdILq" alt="" width="133"><figcaption></figcaption></figure>

You can replace it in two ways:

**Option A: Set a custom URL**

```swift
let renderer = MCDefaultAdRenderer()
renderer.setCurrencyIconUrl("https://example.com/my_coin.png")
adView.setRenderer(renderer)
adView.load()
```

**Option B: Use a local asset**

To use an image from your app's asset catalog, disable the URL-based icon and set the image in `configure(cell:campaign:at:)`:

```swift
import UIKit
import MyChipsSdk

final class GemRenderer: MCDefaultAdRenderer {
    override init() {
        super.init()
        // Disable the default CDN icon — we'll set our own below.
        setCurrencyIconUrl("")
    }

    override func configure(cell: UICollectionViewCell, campaign: MCCampaign, at index: Int) {
        super.configure(cell: cell, campaign: campaign, at: index)
        if let cell = cell as? MCDefaultAdCell {
            cell.currencyImageView.image = UIImage(named: "ic_gem")
        }
    }
}

adView.setRenderer(GemRenderer())
adView.load()
```

> **Important:** Call `setCurrencyIconUrl("")` when using a local asset. This prevents the default CDN icon from loading asynchronously and overwriting your image.

***

### 3. Customize Text Colors

By default the name and reward labels use `UIColor.label`, so they adapt automatically to the system light/dark theme. If you want to brand them, subclass `MCDefaultAdRenderer` and override the colors after the default binding:

```swift
final class BrandedRenderer: MCDefaultAdRenderer {
    override func configure(cell: UICollectionViewCell, campaign: MCCampaign, at index: Int) {
        super.configure(cell: cell, campaign: campaign, at: index)
        if let cell = cell as? MCDefaultAdCell {
            cell.rewardLabel.textColor = UIColor(red: 0x19/255, green: 0x76/255, blue: 0xD2/255, alpha: 1) // Blue
        }
    }
}

adView.setRenderer(BrandedRenderer())
```

> **Dark mode tip:** when you pick a custom text color, prefer a `UIColor(dynamicProvider:)` — or a pair of asset-catalog colors — so your brand remains readable in both appearances. The card sits directly on the host's background, so hardcoded dark colors will disappear in dark mode.

#### Default Cell Subviews

| Property                  | Type          | Description       |
| ------------------------- | ------------- | ----------------- |
| `cell.thumbnailImageView` | `UIImageView` | Campaign image    |
| `cell.nameLabel`          | `UILabel`     | Campaign name     |
| `cell.rewardLabel`        | `UILabel`     | Reward value      |
| `cell.currencyImageView`  | `UIImageView` | Currency icon     |
| `cell.promoBadge`         | `PaddedLabel` | Promo badge       |
| `cell.progressBadge`      | `PaddedLabel` | In Progress badge |

All subviews are `public` on `MCDefaultAdCell`; cast the cell with `cell as? MCDefaultAdCell` to access them.

***

### 4. Custom Loading View

By default, the SDK shows a pulsing skeleton placeholder while loading:

<figure><img src="/files/Ob59btVGjMZ5IbhiVRdA" alt="" width="134"><figcaption></figcaption></figure>

You can replace it:

```swift
// Simple spinner
let spinner = UIActivityIndicatorView(style: .medium)
spinner.startAnimating()
adView.setLoadingView(spinner)
```

Or something more complex with text as well:

```swift
// Spinner + text, centered
let loading = UIView()
let stack = UIStackView()
stack.axis = .vertical
stack.alignment = .center
stack.spacing = 8
stack.translatesAutoresizingMaskIntoConstraints = false
loading.addSubview(stack)

let spinner = UIActivityIndicatorView(style: .medium)
spinner.startAnimating()
stack.addArrangedSubview(spinner)

let label = UILabel()
label.text = "Loading offers..."
label.textColor = .gray
stack.addArrangedSubview(label)

NSLayoutConstraint.activate([
    stack.centerXAnchor.constraint(equalTo: loading.centerXAnchor),
    stack.centerYAnchor.constraint(equalTo: loading.centerYAnchor)
])

adView.setLoadingView(loading)
```

<figure><img src="/files/YU5J2duHb7zcIxxfm9Bk" alt="" width="170"><figcaption></figcaption></figure>

Pass `nil` to restore the default skeleton:

```swift
adView.setLoadingView(nil)
```

***

### 5. Custom Click Handler

Override the default click behavior per-view:

```swift
adView.onCampaignClick = { campaign, position in
    // Your custom logic: show a dialog, navigate, etc.
    MCOfferwallSDK.shared.onClick(campaign: campaign, from: self) // or handle it yourself
}
```

> **Tip:** You can configure the default click behavior globally without writing a custom click handler. Call `MCOfferwallSDK.shared.setOpenInApp(true)` to open campaign details in an in-app WebView instead of Safari. See the Open Campaign Details In-App.

***

### 6. Loading Lifecycle Listener

Monitor loading state for your own UI logic:

```swift
adView.loadingListener = MCNativeAdView.LoadingListener(
    onLoadingStarted: {
        // Called when load() begins
    },
    onCampaignsLoaded: { count in
        // Called when campaigns arrive (count may be 0)
    },
    onError: { error in
        // Called if the fetch fails
    }
)
```

***

### Next Steps

* Need a completely different card design? See [Custom Layouts →](/ios/sdk-native/sdk-native-custom-layout.md)
* Need the full data reference? See [Data Reference →](/ios/sdk-native/sdk-native-data-reference.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.mychips.io/ios/sdk-native/sdk-native-customizations.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
