-
Notifications
You must be signed in to change notification settings - Fork 0
Custom UI Sample iOS
Hudson_BuildService edited this page Jan 9, 2026
·
1 revision
class ViewController: UIViewController {
private var surveyFrame: SurveyFrame!
private var contentLayout: UIStackView!
private var pageLayout: UIStackView!
private var buttonLayout: UIStackView!
private var nextButton: UIButton!
private var backButton: UIButton!
private var quitButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
createViews()
// Binding Program Lifecycle Listener
let serverId = ConfirmitServer.uk.serverId
let programKey = "<Program Key>"
TriggerSDK.setCallback(serverId: serverId, programKey: programKey, callback: self)
// Initialize Survey Frame
surveyFrame = SurveyFrame()
// Binding Survey Lifecycle Listener to be notified events
surveyFrame.delegate = self
}
private func createViews() {
let bound = view.bounds
contentLayout = UIStackView(frame: CGRect(x: 40, y: 40, width: bound.width - 80, height: 400))
contentLayout.axis = .vertical
pageLayout = UIStackView()
pageLayout.axis = .vertical
buttonLayout = UIStackView()
buttonLayout.axis = .horizontal
buttonLayout.distribution = .fillEqually
nextButton = createNavButton(title: "Next", tag: 0)
backButton = createNavButton(title: "Back", tag: 1)
quitButton = createNavButton(title: "Quit", tag: 2)
buttonLayout.addArrangedSubview(backButton)
buttonLayout.addArrangedSubview(quitButton)
buttonLayout.addArrangedSubview(nextButton)
contentLayout.addArrangedSubview(pageLayout)
contentLayout.addArrangedSubview(buttonLayout)
view.addSubview(contentLayout)
}
@objc func onNavButtonPressed(sender: UIButton!) {
switch sender.tag {
case 0:
surveyFrame.next()
case 1:
surveyFrame.back()
case 2:
surveyFrame.quit(upload: false)
default:
break
}
}
private func createNavButton(title: String, tag: Int) -> UIButton {
let button = UIButton(type: .roundedRect)
button.setTitle(title, for: .normal)
button.tag = tag
button.addTarget(self, action: #selector(onNavButtonPressed(sender:)), for: .touchUpInside)
return button
}
private func showAlert(message: String) {
let alertController = UIAlertController(title: message, message: "", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .default))
present(alertController, animated: true, completion: nil)
}
}
extension ViewController: ProgramCallback {
func onScenarioLoad(triggerInfo: TriggerInfo, error: Error?) {
// On scenario script starts
}
func onScenarioError(triggerInfo: TriggerInfo, error: Error) {
// When scenario scripting contains error
}
func onSurveyDownloadCompleted(triggerInfo: TriggerInfo, surveyId: String, error: Error?) {
// Survey download completed
}
func onWebSurveyStart(surveyWebView: SurveyWebViewController) {
// Show web survey
}
func onSurveyStart(config: SurveyFrameConfig) {
try! surveyFrame.load(config: config) // This is example. In your project, error should be handled
surveyFrame.start()
}
func onAppFeedback(triggerInfo: TriggerInfo, data: [String: String?]) {
// When AppFeedback action triggered
}
}
extension ViewController: SurveyFrameDelegate {
func onSurveyPageReady(page: SurveyPage) {
// Clear question views
pageLayout.arrangedSubviews.forEach { $0.removeFromSuperview() }
// Set visibilities for navigation buttons
nextButton.isHidden = !page.showForward
backButton.isHidden = !page.showBackward
let questions = page.questions
// Loop through question in current survey page, and generate Views
for question in questions {
// If question type is TEXT
if question.nodeType == .text {
// Question model is passed to view for:
// 1. To display the question
// 2. Interaction like answering question
let textQuestion = TextQuestionLayout()
textQuestion.setup(question: question as! TextQuestion)
pageLayout.addArrangedSubview(textQuestion)
}
// ... More question type integrations
}
}
func onSurveyErrored(values: [String: String?], error: Error) {
showAlert(message: "Survey contains error")
}
func onSurveyFinished(values: [String: String?]) {
showAlert(message: "Survey completed")
}
func onSurveyQuit(values: [String: String?]) {
showAlert(message: "Survey quit by user")
}
}
class TextQuestionLayout: UIView, UITextFieldDelegate {
private var question: TextQuestion!
func setup(question: TextQuestion) {
self.question = question
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
label.font = UIFont.systemFont(ofSize: 16)
label.text = question.title.get()
let textField = UITextField(frame: CGRect(x: 0, y: 70, width: 300, height: 200))
textField.font = UIFont.systemFont(ofSize: 16)
textField.borderStyle = .roundedRect
textField.delegate = self
addSubview(label)
addSubview(textField)
}
func textFieldDidEndEditing(_ textField: UITextField) {
question.setValue(value: textField.text)
}
}Copyright © 2026 Forsta. All rights reserved.
- Initializing the SDK
- Download a Program
- Sending App Events
- Sending Journey Log
- Survey Triggering
- Displaying a Survey
- Forsta Plus Server
- Program Lifecycle Monitoring
- Starting and Updating a Program
- Advanced Trigger Control