Обратный звонок для MSSticker Peels в приложении iOS 10 iMessage
Я экспериментирую с приложениями iMessage наклейки в iOS 10, и я столкнулся с проблемой с методом override func didStartSending(_ message: MSMessage, conversation: MSConversation)
в MSMessagesAppViewController
. Когда "пилинг" стикера с MSStickerView
, я ожидаю получить какой-то обратный вызов по методу didStartSending
. Но, похоже, это не так. Кто-нибудь знает, является ли это ожидаемым поведением и/или если есть другой способ подписаться на обратные вызовы, когда эти наклейки очищаются, перетаскиваются и удаляются в MSConversation
? Я понимаю, что didStartSending
зарезервирован для того, когда пользователь нажимает кнопку отправки, но наверняка должен быть некоторый способ узнать, когда пользователи перетаскивают MSStickers без взлома нескольких эвристик UIView для перетаскивания/исправления.
Контроллер представления сообщений:
class MessagesViewController: MSMessagesAppViewController {
var nYCStickersBroswerViewController: NYCStickersBroswerViewController!
override func viewDidLoad() {
super.viewDidLoad()
nYCStickersBroswerViewController = NYCStickersBroswerViewController(stickerSize: .regular)
nYCStickersBroswerViewController.view.frame = self.view.frame
self.addChildViewController(nYCStickersBroswerViewController)
nYCStickersBroswerViewController.didMove(toParentViewController: self)
self.view.addSubview(nYCStickersBroswerViewController.view)
nYCStickersBroswerViewController.loadStickers()
nYCStickersBroswerViewController.stickerBrowserView.reloadData()
}
...
override func didStartSending(_ message: MSMessage, conversation: MSConversation) {
// Called when the user taps the send button.
print(message) // should this not contain the sticker that is peeled, dragged, and dropped into the conversation?
}
}
Браузер наклейки:
import Foundation
import UIKit
import Messages
class ASSticker: MSSticker {
var identifier: String?
}
class NYCStickersBroswerViewController: MSStickerBrowserViewController {
var stickers = [ASSticker]()
override func viewDidLoad() {
super.viewDidLoad()
}
func changeBrowswerViewBackgroundColor(color: UIColor) {
stickerBrowserView.backgroundColor = color
}
func loadStickers() {
createSticker(name: "brooklyn", localizedDescription: "Brooklyn Bridge Sticker")
createSticker(name: "liberty", localizedDescription: "Statue of Liberty Sticker")
createSticker(name: "love", localizedDescription: "I Love New York Sticker")
createSticker(name: "mets", localizedDescription: "New York Mets Sticker")
createSticker(name: "rangers", localizedDescription: "New York Rangers Sticker")
createSticker(name: "subway", localizedDescription: "New York City MTA Subway Train Sticker")
}
func createSticker(name: String, localizedDescription: String) {
guard let stickerPath = Bundle.main.pathForResource(name, ofType: "png") else {
print("Call ae cab, you're intoxicated.")
return
}
let stickerURL = URL(fileURLWithPath: stickerPath)
let sticker: ASSticker
do {
try sticker = ASSticker(contentsOfFileURL: stickerURL, localizedDescription: localizedDescription)
sticker.identifier = "something unique"
stickers.append(sticker)
} catch {
print("Call a cab, you're intoxicated.")
}
}
override func numberOfStickers(in stickerBrowserView: MSStickerBrowserView) -> Int {
return self.stickers.count
}
override func stickerBrowserView(_ stickerBrowserView: MSStickerBrowserView, stickerAt index: Int) -> MSSticker {
return self.stickers[index]
}
}
Ответы
Ответ 1
Здесь подкласс и делегат, который будет привязан к крану и длинным распознавателям жестов нажатия, которые MSStickerView
использует для выбора и взаимодействия кожи. Если реализация MSStickerView
изменится, это может больше не предоставлять события, но не должно терпеть крах.
import UIKit
import Messages
protocol InstrumentedStickerViewDelegate: class {
func stickerViewDidSelect(stickerView: MSStickerView)
func stickerViewDidPeel(stickerView: MSStickerView)
}
class InstrumentedStickerView: MSStickerView {
weak var delegate: InstrumentedStickerViewDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
for gestureRecognizer in gestureRecognizers ?? [] {
if let tapGestureRecognizer = gestureRecognizer as? UITapGestureRecognizer {
tapGestureRecognizer.addTarget(self, action: #selector(didTap))
} else if let longPressGestureRecognizer = gestureRecognizer as? UILongPressGestureRecognizer {
longPressGestureRecognizer.addTarget(self, action: #selector(didLongPress))
}
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func didTap(tapGestureRecognizer: UITapGestureRecognizer) {
if tapGestureRecognizer.state == .Recognized {
delegate?.stickerViewDidSelect(self)
}
}
func didLongPress(longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == .Began {
delegate?.stickerViewDidPeel(self)
}
}
}
Ответ 2
Это обходной путь для стираемых и набранных событий наклейки, не гарантируется, что конкретная наклейка будет вставлена, но приближение таких точек данных - вам придется использовать свой подкласс MSStickerView. Это решение не является будущим, но работает пока ИМХО, поэтому я приветствую другие идеи.
import UIKit
import Messages
class CustomStickerView : MSStickerView{
class GestureRecognizerReceiver : NSObject, UIGestureRecognizerDelegate{
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
let _recognizerDelegate = GestureRecognizerReceiver()
weak var _recognizer: UITapGestureRecognizer? = nil
func setupTapRecognizer(){
if _recognizer == nil {
let r = UITapGestureRecognizer(target: self, action: #selector(_customTapReceived))
r.cancelsTouchesInView = false
r.delegate = _recognizerDelegate
addGestureRecognizer(r)
_recognizer = r
}
}
func _customTapReceived(){
if let s = sticker{
Analytics.shared.reportEvent(name: "Sticker Inserted", description: s.localizedDescription)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
if let s = sticker{
Analytics.shared.reportEvent(name: "Sticker Peeled", description: s.localizedDescription)
}
}
}
Использование:
let sv = CustomStickerView(frame: _stickerViewHolder.bounds, sticker: sticker)
sv.setupTapRecognizer()
_stickerViewHolder.addSubview(sv)
sv.startAnimating()