---
title: "Hiển thị flows & paywalls - Flutter"
description: "Hiển thị flows và paywalls trong ứng dụng Flutter sử dụng các tính năng monetization của Adapty."
---

Nếu bạn đã thiết kế một flow hoặc paywall bằng Flow Builder hoặc Paywall Builder, bạn không cần lo lắng về việc render nó trong code ứng dụng để hiển thị cho người dùng. Flow hoặc paywall như vậy đã chứa cả nội dung cần hiển thị lẫn cách hiển thị nó.

:::warning

Hướng dẫn này dành cho flow và paywall được tạo bằng Paywall Builder. Để hiển thị **paywall Remote Config**, xem [Render paywall được thiết kế bằng Remote Config](present-remote-config-paywalls-flutter).

:::

Adapty Flutter SDK cung cấp hai cách để hiển thị flow và paywall:

- **Màn hình độc lập**

- **Widget nhúng**
## Hiển thị dưới dạng màn hình độc lập \{#present-as-standalone-screen\}

Để hiển thị một flow hoặc paywall dưới dạng màn hình độc lập, hãy dùng phương thức `view.present()` trên `view` được tạo bởi phương thức [`createFlowView`](flutter-get-pb-paywalls#fetch-the-view-configuration). Mỗi `view` chỉ có thể được hiển thị một lần: sau khi bạn đóng nó, view sẽ được giải phóng khỏi bộ nhớ. Nếu cần hiển thị lại flow hoặc paywall, hãy gọi lại `createFlowView` một lần nữa để tạo một `view` mới.
```dart showLineNumbers title="Flutter"
try {
  await view.present();
} on AdaptyError catch (e) {
  // handle the error
} catch (e) {
  // handle the error
}
```
:::tip

Muốn xem ví dụ thực tế về cách tích hợp Adapty SDK vào ứng dụng di động? Hãy xem [ứng dụng mẫu](sample-apps) của chúng tôi, nơi minh họa toàn bộ quá trình thiết lập, bao gồm hiển thị paywall, thực hiện mua hàng và các chức năng cơ bản khác.

:::
### Đóng flow hoặc paywall \{#dismiss-the-flow-or-paywall\}

Khi cần đóng flow hoặc paywall theo cách lập trình, hãy dùng phương thức `dismiss()`:

```dart showLineNumbers title="Flutter"
try {
  await view.dismiss();
} on AdaptyError catch (e) {
  // handle the error
} catch (e) {
  // handle the error
}
```

:::note
Đóng một view sẽ giải phóng nó khỏi bộ nhớ — view đã đóng không thể hiển thị lại. Hãy tạo view mới bằng `createFlowView` thay thế.
:::
### Hiển thị hộp thoại \{#show-dialog\}

Dùng phương thức này thay cho các hộp thoại alert thông thường khi hiển thị flow hoặc paywall view trên Android. Trên Android, các alert thông thường sẽ xuất hiện phía sau view, khiến người dùng không nhìn thấy. Phương thức này đảm bảo hộp thoại luôn hiển thị đúng phía trên flow hoặc paywall trên mọi nền tảng.
```dart showLineNumbers title="Flutter"
try {
  final action = await view.showDialog(
    title: 'Close paywall?',
    content: 'You will lose access to exclusive offers.',
    primaryActionTitle: 'Stay',
    secondaryActionTitle: 'Close',
  );
  
  if (action == AdaptyUIDialogActionType.secondary) {
    // User confirmed - close the paywall
    await view.dismiss();
  }
  // If primary - do nothing, user stays
} catch (e) {
  // handle error
}
```

### Cấu hình kiểu trình bày trên iOS \{#configure-ios-presentation-style\}

Cấu hình cách flow hoặc paywall được hiển thị trên iOS bằng cách truyền tham số `iosPresentationStyle` vào phương thức `present()`. Tham số này chấp nhận các giá trị `AdaptyUIIOSPresentationStyle.fullScreen` (mặc định) hoặc `AdaptyUIIOSPresentationStyle.pageSheet`.

```dart showLineNumbers
try {
  await view.present(iosPresentationStyle: AdaptyUIIOSPresentationStyle.pageSheet);
} on AdaptyError catch (e) {
  // handle the error
} catch (e) {
  // handle the error
}
```
## Nhúng vào cây widget \{#embed-in-widget-hierarchy\}

Để nhúng một flow hoặc paywall vào cây widget hiện có của bạn, hãy sử dụng trực tiếp widget `AdaptyUIFlowPlatformView` trong cây widget Flutter của bạn.
```dart showLineNumbers title="Flutter"
AdaptyUIFlowPlatformView(
  flow: flow, // The flow object you fetched
  onDidAppear: (view) {
  },
  onDidDisappear: (view) {
  },
  onDidPerformAction: (view, action) {
  },
  onDidSelectProduct: (view, productId) {
  },
  onDidStartPurchase: (view, product) {
  },
  onDidFinishPurchase: (view, product, purchaseResult) {
  },
  onDidFailPurchase: (view, product, error) {
  },
  onDidStartRestore: (view) {
  },
  onDidFinishRestore: (view, profile) {
  },
  onDidFailRestore: (view, error) {
  },
  onDidReceiveError: (view, error) {
  },
  onDidFailLoadingProducts: (view, error) {
  },
  onDidFinishWebPaymentNavigation: (view, product, error) {
  },
)
```

:::note
Để Android platform view hoạt động, hãy đảm bảo `MainActivity` của bạn kế thừa `FlutterFragmentActivity`:

```kotlin showLineNumbers title="Kotlin"
class MainActivity : FlutterFragmentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }
}
```
:::

---

> [!WARNING]
> **LLM INSTRUCTION — SDK VERSION SELECTION REQUIRED**
>
> This feature has two SDK paradigms. Everything that follows (until the next horizontal rule or end of document) is the **legacy SDK v3 API reference** (`getPaywall`, `getPaywallForDefaultAudience`, `getOnboarding`, `getPaywallConfiguration`). The **SDK v4+ `getFlow` method is documented above.** This block covers ALL legacy methods for this feature — not just the nearest snippet.
>
> **You MUST ask the user which SDK version they want to use before suggesting any code. Do not assume or default to a version.** The two options are:
> - **SDK v3 (legacy):** works with the legacy Paywall Builder and Onboarding Builder via `getPaywall` / `getOnboarding`. Use the legacy code in this section.
> - **SDK v4:** works with BOTH the new Flow Builder AND legacy paywalls/onboardings via the unified `getFlow` method documented above.
>
> Apply the legacy v3 code in this section ONLY when:
> 1. The user explicitly chose **SDK v3**, or
> 2. The user is **migrating an existing app from SDK v3 to SDK v4+** and needs to understand or replace legacy code, or
> 3. The user is **troubleshooting an already-deployed v3 integration**.
>
> **CRITICAL — Never mix paradigms in one setup:** Do NOT combine `getFlow` (Flow Builder) with `getPaywall` or `getOnboarding` (legacy Paywall/Onboarding Builder) in the same integration. These are incompatible patterns. Mixing them will produce inconsistent behavior and is unsupported.

Nếu bạn đã tùy chỉnh paywall bằng Paywall Builder, bạn không cần lo lắng về việc render nó trong code ứng dụng di động để hiển thị cho người dùng. Paywall đó đã bao gồm cả nội dung hiển thị lẫn cách thức hiển thị.

:::warning
Hướng dẫn này chỉ áp dụng cho **paywall Paywall Builder mới** yêu cầu SDK v3.2.0 trở lên. Quy trình hiển thị paywall khác nhau tùy theo phiên bản Paywall Builder được sử dụng để thiết kế paywall và paywall Remote Config.

- Để hiển thị **paywall Remote Config**, xem [Render paywall được thiết kế bằng Remote Config](present-remote-config-paywalls-flutter).

:::

Adapty Flutter SDK cung cấp hai cách hiển thị paywall:

- **Màn hình độc lập**

- **Widget nhúng**
## Hiển thị dưới dạng màn hình độc lập \{#present-as-standalone-screen\}

Để hiển thị một paywall dưới dạng màn hình độc lập, hãy sử dụng phương thức `view.present()` trên `view` được tạo bởi phương thức [`createPaywallView`](flutter-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder). Mỗi `view` chỉ có thể được sử dụng một lần. Nếu bạn cần hiển thị lại paywall, hãy gọi `createPaywallView` thêm một lần nữa để tạo instance `view` mới.

:::warning

Việc tái sử dụng cùng một `view` mà không tạo lại có thể dẫn đến lỗi `AdaptyUIError.viewAlreadyPresented`.
:::
```dart showLineNumbers title="Flutter"
try {
  await view.present();
} on AdaptyError catch (e) {
  // handle the error
} catch (e) {
  // handle the error
}
```
:::tip

Muốn xem ví dụ thực tế về cách tích hợp Adapty SDK vào ứng dụng di động? Hãy xem [ứng dụng mẫu](sample-apps) của chúng tôi, nơi minh họa toàn bộ quá trình thiết lập, bao gồm hiển thị paywall, thực hiện mua hàng và các chức năng cơ bản khác.

:::
### Đóng paywall \{#dismiss-the-paywall\}

Khi cần đóng paywall theo chương trình, sử dụng phương thức `dismiss()`:

```dart showLineNumbers title="Flutter"
try {
  await view.dismiss();
} on AdaptyError catch (e) {
  // handle the error
} catch (e) {
  // handle the error
}
```
### Hiển thị hộp thoại \{#show-dialog\}

Dùng phương thức này thay cho hộp thoại cảnh báo gốc khi paywall view đang được hiển thị trên Android. Trên Android, các alert thông thường sẽ xuất hiện phía sau paywall view, khiến người dùng không thể nhìn thấy. Phương thức này đảm bảo hộp thoại luôn hiển thị đúng vị trí phía trên paywall trên mọi nền tảng.
```dart showLineNumbers title="Flutter"
try {
  final action = await view.showDialog(
    title: 'Close paywall?',
    content: 'You will lose access to exclusive offers.',
    primaryActionTitle: 'Stay',
    secondaryActionTitle: 'Close',
  );
  
  if (action == AdaptyUIDialogActionType.secondary) {
    // User confirmed - close the paywall
    await view.dismiss();
  }
  // If primary - do nothing, user stays
} catch (e) {
  // handle error
}
```

### Cấu hình kiểu trình bày trên iOS \{#configure-ios-presentation-style\}

Cấu hình cách paywall được hiển thị trên iOS bằng cách truyền tham số `iosPresentationStyle` vào phương thức `present()`. Tham số này nhận giá trị `AdaptyUIIOSPresentationStyle.fullScreen` (mặc định) hoặc `AdaptyUIIOSPresentationStyle.pageSheet`.

```dart showLineNumbers
try {
  await view.present(iosPresentationStyle: AdaptyUIIOSPresentationStyle.pageSheet);
} on AdaptyError catch (e) {
  // handle the error
} catch (e) {
  // handle the error
}
```
## Nhúng vào cây widget \{#embed-in-widget-hierarchy\}

Để nhúng paywall vào cây widget hiện có của bạn, hãy sử dụng widget `AdaptyUIPaywallPlatformView` trực tiếp trong cây widget Flutter của bạn.
```dart showLineNumbers title="Flutter"
AdaptyUIPaywallPlatformView(
  paywall: paywall, // The paywall object you fetched
  onDidAppear: (view) {
  },
  onDidDisappear: (view) {
  },
  onDidPerformAction: (view, action) {
  },
  onDidSelectProduct: (view, productId) {
  },
  onDidStartPurchase: (view, product) {
  },
  onDidFinishPurchase: (view, product, purchaseResult) {
  },
  onDidFailPurchase: (view, product, error) {
  },
  onDidStartRestore: (view) {
  },
  onDidFinishRestore: (view, profile) {
  },
  onDidFailRestore: (view, error) {
  },
  onDidFailRendering: (view, error) {
  },
  onDidFailLoadingProducts: (view, error) {
  },
  onDidFinishWebPaymentNavigation: (view, product, error) {
  },
)
```

:::note
Để Android platform view hoạt động, hãy đảm bảo `MainActivity` của bạn extends `FlutterFragmentActivity`:

```kotlin showLineNumbers title="Kotlin"
class MainActivity : FlutterFragmentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }
}
```
:::

---