> For the complete documentation index, see [llms.txt](https://docs.mychips.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.mychips.io/ios/sdk-native/sdk-native-customizations.md).

# 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)
