-
Notifications
You must be signed in to change notification settings - Fork 330
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[question] Custom element with custom view #304
Comments
I solve the problem, but i still need click on buttons and it is not clickable, can anyone help me? import UIKit
import Down
class MainViewController: UIViewController {
private var textView: UITextView!
private let exampleMarkdown = """
Aqui está um link para um produto: [produto](ubook-app://product/123).
Aqui está um link para um outro produto: [produto](ubook-app://product/456) que também é um produto bom.
"""
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupTextView()
parseMarkdown()
}
private func setupTextView() {
textView = UITextView()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.isEditable = false
textView.backgroundColor = .white
textView.textColor = .black
textView.isScrollEnabled = true
textView.textContainerInset = .zero
textView.textContainer.lineFragmentPadding = 0
textView.delegate = self
textView.isUserInteractionEnabled = true
textView.isSelectable = false
view.addSubview(textView)
NSLayoutConstraint.activate([
textView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
textView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
textView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
])
}
private func parseMarkdown() {
let down = Down(markdownString: exampleMarkdown)
if let attributedString = try? down.toAttributedString() {
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedString)
let fullRange = NSRange(location: 0, length: attributedString.length)
mutableAttributedString.enumerateAttributes(in: fullRange, options: []) { attributes, range, _ in
if let link = attributes[.link] as? URL, link.scheme == "ubook-app", link.host == "product" {
let productId = link.lastPathComponent
let attachment = NSTextAttachment()
let productView = createProductView(productId: productId)
attachment.image = imageFromView(view: productView)
let attachmentString = NSAttributedString(attachment: attachment)
mutableAttributedString.replaceCharacters(in: range, with: attachmentString)
self.textView.attributedText = mutableAttributedString
// Carregar os dados do produto de forma assíncrona
self.loadProductData(productId: productId) { product in
DispatchQueue.main.async {
self.updateProductView(productView: productView, product: product)
attachment.image = self.imageFromView(view: productView)
self.textView.attributedText = mutableAttributedString // Atualizar o texto após carregar o produto
self.textView.layoutIfNeeded() // Garantir que a UI seja atualizada
}
}
}
}
}
}
private func createProductView(productId: String) -> UIView {
let productView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 80))
productView.backgroundColor = .red
productView.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(productViewTapped(_:)))
productView.addGestureRecognizer(tapGesture)
let loadingView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 80))
loadingView.backgroundColor = .green
loadingView.translatesAutoresizingMaskIntoConstraints = false
loadingView.tag = 1
productView.addSubview(loadingView)
let activityIndicator = UIActivityIndicatorView(style: .large)
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
activityIndicator.startAnimating()
loadingView.addSubview(activityIndicator)
NSLayoutConstraint.activate([
activityIndicator.centerXAnchor.constraint(equalTo: loadingView.centerXAnchor),
activityIndicator.centerYAnchor.constraint(equalTo: loadingView.centerYAnchor),
loadingView.topAnchor.constraint(equalTo: productView.topAnchor),
loadingView.leadingAnchor.constraint(equalTo: productView.leadingAnchor),
loadingView.trailingAnchor.constraint(equalTo: productView.trailingAnchor),
loadingView.bottomAnchor.constraint(equalTo: productView.bottomAnchor)
])
let productContentView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 80))
productContentView.backgroundColor = .blue
productContentView.translatesAutoresizingMaskIntoConstraints = false
productContentView.isHidden = true
productContentView.tag = 2
productView.addSubview(productContentView)
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.tag = 3
productContentView.addSubview(imageView)
let titleLabel = UILabel()
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.textColor = .white
titleLabel.tag = 4
productContentView.addSubview(titleLabel)
let listenButton = UIButton(type: .system)
listenButton.setTitle("OUVIR", for: .normal)
listenButton.backgroundColor = .white
listenButton.setTitleColor(.blue, for: .normal)
listenButton.translatesAutoresizingMaskIntoConstraints = false
listenButton.tag = 5
listenButton.addTarget(self, action: #selector(listenButtonTapped(_:)), for: .touchUpInside)
productContentView.addSubview(listenButton)
let viewButton = UIButton(type: .system)
viewButton.setTitle("VER", for: .normal)
viewButton.backgroundColor = .white
viewButton.setTitleColor(.blue, for: .normal)
viewButton.translatesAutoresizingMaskIntoConstraints = false
viewButton.tag = 6
viewButton.addTarget(self, action: #selector(viewButtonTapped(_:)), for: .touchUpInside)
productContentView.addSubview(viewButton)
NSLayoutConstraint.activate([
activityIndicator.centerXAnchor.constraint(equalTo: loadingView.centerXAnchor),
activityIndicator.centerYAnchor.constraint(equalTo: loadingView.centerYAnchor),
loadingView.topAnchor.constraint(equalTo: productView.topAnchor),
loadingView.leadingAnchor.constraint(equalTo: productView.leadingAnchor),
loadingView.trailingAnchor.constraint(equalTo: productView.trailingAnchor),
loadingView.bottomAnchor.constraint(equalTo: productView.bottomAnchor),
imageView.topAnchor.constraint(equalTo: productContentView.topAnchor, constant: 10),
imageView.leadingAnchor.constraint(equalTo: productContentView.leadingAnchor, constant: 10),
imageView.widthAnchor.constraint(equalToConstant: 50),
imageView.heightAnchor.constraint(equalToConstant: 60),
titleLabel.topAnchor.constraint(equalTo: productContentView.topAnchor, constant: 10),
titleLabel.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 10),
titleLabel.trailingAnchor.constraint(equalTo: productContentView.trailingAnchor, constant: -10),
listenButton.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 10),
listenButton.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 10),
listenButton.widthAnchor.constraint(equalToConstant: 80),
viewButton.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 10),
viewButton.leadingAnchor.constraint(equalTo: listenButton.trailingAnchor, constant: 10),
viewButton.trailingAnchor.constraint(equalTo: productContentView.trailingAnchor, constant: -10),
productContentView.topAnchor.constraint(equalTo: productView.topAnchor),
productContentView.leadingAnchor.constraint(equalTo: productView.leadingAnchor),
productContentView.trailingAnchor.constraint(equalTo: productView.trailingAnchor),
productContentView.bottomAnchor.constraint(equalTo: productView.bottomAnchor)
])
return productView
}
@objc private func listenButtonTapped(_ sender: UIButton) {
if let productView = sender.superview?.superview as? UIView,
let titleLabel = productView.viewWithTag(4) as? UILabel {
print("OUVIR botão clicado para o produto: \(titleLabel.text ?? "")")
}
}
@objc private func viewButtonTapped(_ sender: UIButton) {
if let productView = sender.superview?.superview as? UIView,
let titleLabel = productView.viewWithTag(4) as? UILabel {
print("VER botão clicado para o produto: \(titleLabel.text ?? "")")
}
}
@objc private func productViewTapped(_ gesture: UITapGestureRecognizer) {
if let productView = gesture.view,
let titleLabel = productView.viewWithTag(4) as? UILabel {
print("Produto clicado: \(titleLabel.text ?? "")")
}
}
private func updateProductView(productView: UIView, product: Product) {
if let loadingView = productView.viewWithTag(1),
let productContentView = productView.viewWithTag(2),
let imageView = productContentView.viewWithTag(3) as? UIImageView,
let titleLabel = productContentView.viewWithTag(4) as? UILabel {
print("Atualizando a view do produto")
loadingView.isHidden = true
productContentView.isHidden = false
imageView.image = product.image
titleLabel.text = "\(product.title) (\(product.id))"
productView.setNeedsLayout()
productView.layoutIfNeeded()
} else {
print("Não foi possível encontrar as views para atualizar")
}
}
private func imageFromView(view: UIView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0)
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image ?? UIImage()
}
private func loadProductData(productId: String, completion: @escaping (Product) -> Void) {
// Simula carregamento assíncrono de dados
DispatchQueue.global().asyncAfter(deadline: .now() + 2.0) {
let product = Product(id: productId, title: "Produto \(productId)", image: UIImage(systemName: "book")!)
DispatchQueue.main.async {
completion(product)
}
}
}
}
struct Product {
let id: String
let title: String
let image: UIImage
}
extension MainViewController: UITextViewDelegate {
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
return false
}
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello,
I need a lib for Swift markdown parser/display where when interpreting a link where the href is "ubook-app://product/123", a custom view is placed inside that displays a loading, then loads the product by the link id (ex: 123), and then show the product cover, title and two buttons (read/listen) within the view.
Can you tell me how to do this with this component?
Thanks.
The text was updated successfully, but these errors were encountered: