ㅇㅇ
import UIKit
import SnapKit
// MARK: - Protocols
protocol LearningElementProtocol: UIView {
var elementType: LearningElementType { get }
func interact()
}
protocol LearningElementFactory {
func createElement(ofType type: LearningElementType, withContent content: Any) -> LearningElementProtocol
}
// MARK: - Enums
enum LearningElementType {
case text
case quiz
case codeEditor
case interactiveDiagram
}
// MARK: - Concrete Learning Elements
class TextElement: UIView, LearningElementProtocol {
let elementType: LearningElementType = .text
private let textView: UITextView
init(content: String) {
textView = UITextView()
textView.text = content
textView.isEditable = false
super.init(frame: .zero)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupViews() {
addSubview(textView)
textView.snp.makeConstraints {
$0.edges.equalToSuperview()
}
}
func interact() {
// 텍스트 하이라이팅 등의 인터랙션
}
}
class QuizElement: UIView, LearningElementProtocol {
let elementType: LearningElementType = .quiz
private let questionLabel: UILabel
private let answerButtons: [UIButton]
init(question: String, answers: [String]) {
questionLabel = UILabel()
questionLabel.text = question
answerButtons = answers.map { answer in
let button = UIButton(type: .system)
button.setTitle(answer, for: .normal)
return button
}
super.init(frame: .zero)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupViews() {
addSubview(questionLabel)
questionLabel.snp.makeConstraints {
$0.top.leading.trailing.equalToSuperview().inset(8)
}
let stackView = UIStackView(arrangedSubviews: answerButtons)
stackView.axis = .vertical
stackView.spacing = 8
addSubview(stackView)
stackView.snp.makeConstraints {
$0.top.equalTo(questionLabel.snp.bottom).offset(16)
$0.leading.trailing.bottom.equalToSuperview().inset(8)
}
}
func interact() {
// 퀴즈 답변 처리
}
}
class CodeEditorElement: UIView, LearningElementProtocol {
let elementType: LearningElementType = .codeEditor
private let codeTextView: UITextView
private let runButton: UIButton
init(initialCode: String) {
codeTextView = UITextView()
codeTextView.text = initialCode
codeTextView.font = UIFont.monospacedSystemFont(ofSize: 14, weight: .regular)
runButton = UIButton(type: .system)
runButton.setTitle("Run Code", for: .normal)
super.init(frame: .zero)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupViews() {
addSubview(codeTextView)
addSubview(runButton)
codeTextView.snp.makeConstraints {
$0.top.leading.trailing.equalToSuperview().inset(8)
$0.height.equalTo(200)
}
runButton.snp.makeConstraints {
$0.top.equalTo(codeTextView.snp.bottom).offset(8)
$0.trailing.bottom.equalToSuperview().inset(8)
$0.height.equalTo(44)
}
}
func interact() {
// 코드 실행 로직
}
}
// MARK: - Learning Element Factory
class LearningElementFactory치: LearningElementFactory {
func createElement(ofType type: LearningElementType, withContent content: Any) -> LearningElementProtocol {
switch type {
case .text:
guard let textContent = content as? String else {
fatalError("Invalid content for text element")
}
return TextElement(content: textContent)
case .quiz:
guard let quizContent = content as? (question: String, answers: [String]) else {
fatalError("Invalid content for quiz element")
}
return QuizElement(question: quizContent.question, answers: quizContent.answers)
case .codeEditor:
guard let codeContent = content as? String else {
fatalError("Invalid content for code editor element")
}
return CodeEditorElement(initialCode: codeContent)
case .interactiveDiagram:
fatalError("Interactive diagram not implemented")
}
}
}
// MARK: - Test View Controller
class TestViewController: UIViewController {
private let scrollView = UIScrollView()
private let contentView = UIView()
private let elementFactory: LearningElementFactory
private var learningElements: [LearningElementProtocol] = []
init() {
self.elementFactory = LearningElementFactory치()
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
createLearningElements()
}
private func setupViews() {
view.backgroundColor = .white
view.addSubview(scrollView)
scrollView.addSubview(contentView)
scrollView.snp.makeConstraints {
$0.edges.equalToSuperview()
}
contentView.snp.makeConstraints {
$0.edges.equalToSuperview()
$0.width.equalTo(view)
}
}
private func createLearningElements() {
let elementConfigs: [(LearningElementType, Any)] = [
(.quiz, (question: "프랑스의 수도는?", answers: ["런던", "베를린", "파리", "마드리드"])),
(.codeEditor, "")
]
var previousElement: UIView?
for (type, content) in elementConfigs {
let element = elementFactory.createElement(ofType: type, withContent: content)
learningElements.append(element)
contentView.addSubview(element)
element.snp.makeConstraints {
if let previousElement = previousElement {
$0.top.equalTo(previousElement.snp.bottom).offset(20)
} else {
$0.top.equalToSuperview().offset(20)
}
$0.leading.trailing.equalToSuperview().inset(20)
}
previousElement = element
}
if let lastElement = previousElement {
lastElement.snp.makeConstraints {
$0.bottom.equalToSuperview().offset(-20)
}
}
}
}