Мне нужна помощь, я сделал вид, который я разделил линиями, и когда я касаюсь его, делаю прямоугольник между линиями, как на этом изображении,
и я сделал жест панорамирования, чтобы переместить прямоугольники, которые я рисую, между линиями, это работает, но это не то, что я хочу, когда я немного двигаю пальцем, он перемещается, и в этом проблемы, даже когда я двигаюсь только y он распознает наименьшее количество x и переместить оба, мне нужно переместить мой прямоугольник после того, как панорамирование больше, чем деления, затем переместить прямоугольник, я хочу, когда я выбираю свой прямоугольник и перемещаю палец в верхний или нижний раздел, влево или вправо один из существующего, в котором я нахожусь, затем переместите. так что я придумал это, но это не работает правильно, высота разделения - noteheight, а ширина между ними - timeSlotWidtho ,
@objc func handlePanGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
let touchLocation = gestureRecognizer.location(in: self)
let location = touchLocation
let timeSlotWidtho = bounds.width / CGFloat(numT)
let note = CGFloat(numN) - location.y / noteHeight
let startTime = Double(Int(location.x / timeSlotWidtho))
let duration = Double(numT) / Double(numT)
let noteHeight = bounds.height / CGFloat(numN)
var lastPanY: CGFloat = 0
var lastPanx: CGFloat = 0
switch gestureRecognizer.state {
case .began:
// Check if the user has touched a note rectangle
// Check if a note with the same parameters already exists
for (index, existingNote) in notes.enumerated() {
if existingNote.note == Int(note) && existingNote.startTime == startTime && existingNote.duration == duration {
lastPanY = location.y
lastPanx = location.x
selectedNoteIndex = index
setNeedsDisplay()
}
}
case .changed:
// Move the selected note rectangle
let translation = gestureRecognizer.translation(in: self)
// Check if a note with the same parameters already exists
for (index, existingNote) in notes.enumerated() {
if existingNote.note == Int(note) && existingNote.startTime == startTime && existingNote.duration == duration {
let deltaY = lastPanY - translation.y
let deltax = lastPanx - translation.x
if abs(deltaY) > noteHeight {
let direction = deltaY > lastPanY ? 1 : -1
let newValue = existingNote.note + direction
if newValue >= 0 && newValue <= numN - 1 {
notes[index].note = newValue
// do something with intValue
lastPanY = translation.y
selectedNoteIndex = index
setNeedsDisplay()
}
}
if abs(deltax) > timeSlotWidtho {
let directionl = deltax < lastPanx ? 1.0 : -1.0
let newValuel = existingNote.startTime + directionl
if newValuel >= 0 && Int(newValuel) <= numT {
notes[index].startTime = newValuel
// do something with intValue
lastPanx = translation.x
selectedNoteIndex = index
setNeedsDisplay()
}
}
selectedNoteIndex = index
setNeedsDisplay()
}
}
case .ended:
// the end
setNeedsDisplay()
default:
print("wef")
break
}
}
Спасибо за ваш ответ, хорошая идея, я сделал что-то подобное после прочтения вашего комментария, если вы посмотрите код, я определил let note = CGFloat (numN) - location.y / noteHeight, поэтому я определил новую переменную, которая является местоположением + перевод,тогда я нахожусь после кастрюли,поэтому сделал новую заметку,вместо локации это значение,работает нормально,пока я не делаю деление намного меньше,на фото 12/16,когда делаю 127/32, такой маленький, и мой прямоугольник такой маленький, и не работает, я могу выбрать прямоугольник, но не двигается, я не знаю, может ли место касания быть таким маленьким, или я неправильно определил примечание ,,
потому что, когда он большой, мне также нужно захватить край прямоугольника, чтобы работать, у вас есть идеи, и еще одна проблема, когда я панорамирую за пределы ноты, я имею в виду, что я не выбрал ноту, и я панорамирую и Я добираюсь до заметки, она будет двигаться, я этого не хочу, я хочу, только если я сначала выберу заметку и панорамирую, а затем перемещаю, но теперь, даже если не выбрано, и я панорамирую и дохожу до заметки, она будет выбрана и двигаться,
Заметка должна быть представлением, и это должна быть вещь, на которой есть распознаватель жестов панорамирования. Таким образом можно перетаскивать только заметку; жест, который начинается за пределами заметки, не будет затронут. Затем, как я уже говорил, в коде, который реагирует на перетаскивание, преобразуйте систему координат, чтобы «смотреть» на всю сетку, и выяснить, в каком квадрате вы находитесь в сетке, и переместить заметку туда тогда и только тогда, когда это площадь изменилась. Это действительно очень просто, не переусердствуйте. Отбросьте весь свой код «перевода», все это не имеет значения, просто посмотрите, где на самом деле сейчас находится палец.
Взгляните на мое приложение Diabelli's Theme (бесплатное), то, что я делаю, на самом деле сложнее, чем вам даже нужно, но все равно посмотрите на это: вы можете перетащить квадрат из сетки на любой другой квадрат, а затем поместить его туда. Это заменяет его квадратом, который уже был там, вам не нужна эта часть. И я на самом деле разрешаю физически перетаскивать квадрат и подсвечиваю квадрат, в который вы попадете, если отпустите сейчас, вы, похоже, тоже этого не хотите. Но что вам действительно нужно, так это осознание того, на чем сейчас закончился палец, как и то, что я делаю.
Вы имеете в виду, что каждая заметка должна быть представлением, а не cgrect? Другое дело, как мне посмотреть на всю сетку, как узнать, где мой палец? Есть ли открытый исходный код для вашего приложения Diabelli Theme? Я хотел бы изучить ваш код.
Вид — это рисунок плюс прикосновение. Прикосновение — это именно то, что вам нужно. Вы хотите перетащить рисунок; это вид. Что касается сетки: это просто элементарная арифметика.
Чувак, я не понимаю, что ты пытаешься сказать, было бы здорово увидеть пример, ты знаешь, я пытаюсь сделать пианоролл, посмотри пианоролл в GarageBand, ты поймешь, что я хочу, у меня может быть 100 нот на экране, которые Я получаю массив, для каждого из них, создающего представление, это было бы болью и ограничениями, и я использую прикосновение для создания заметок, для размещения заметок на сетке, другое дело, я не хочу свободно перемещаться как и ваше приложение, мне нужно привязываться к сетке и перемещаться на один шаг за раз,
Я почти уверен, что это то, что вы описываете:
(В конце «видео» я демонстрирую, что начало перетаскивания за пределами заметки не влияет на заметку.)
Если это то, что вам нужно, просто следуйте инструкциям, которые я уже дал вам в комментариях. Сделайте каждую заметку представлением с помощью распознавателя жестов панорамирования. В состоянии .changed
целевого метода этого распознавателя просто посмотрите на местоположение первого касания в представлении сетки и вычислите верхнюю левую точку прямоугольника сетки, в котором находится это касание. Если начало заметки не находится в этой точке, сделайте это так. .
Вот мой целевой метод распознавания жестов панорамирования. Предполагается, что, как я только что сказал, каждая заметка представляет собой представление со своим собственным распознавателем жестов панорамирования. Также предполагается, что у нас есть представление сетки под названием grid
, которое знает, как сообщить, где находятся верхние левые углы его прямоугольников, и что заметка является подпредставлением представления сетки:
@objc func dragged(_ g: UIPanGestureRecognizer) {
guard let note = g.view else { return }
if g.state == .changed {
let pt = g.location(ofTouch: 0, in: grid)
let targetOrigin = grid.divisionOriginFor(point: pt)
let currentOrigin = note.frame.origin
if currentOrigin != targetOrigin {
var newframe = note.frame
newframe.origin = targetOrigin
if grid.bounds.intersection(newframe) == newframe {
note.frame = newframe
}
}
}
}
В этом коде мы предполагаем, что divisionOriginFor(point:)
представления сетки — это метод, который смотрит, где находится point
, и решает, в каком прямоугольнике сетки («делении») он находится, и сообщает верхний левый угол этого прямоугольника. Это может выглядеть так (я предполагаю, что xct
и yct
— это свойства, определяющие количество линий/делений для сетки):
func divisionOriginFor(point pt: CGPoint) -> CGPoint {
let qx = Int(pt.x) / Int(bounds.width / CGFloat(xct))
let qy = Int(pt.y) / Int(bounds.height / CGFloat(yct))
return CGPoint(
x: bounds.width / CGFloat(xct) * CGFloat(qx),
y: bounds.height / CGFloat(yct) * CGFloat(qy)
)
}
братан, это работает хорошо, я изменяю ширину представления, если мое касание находится в начале представления, оно работает нормально, но если в середине или конце, то оно перейдет к положению моего касания, потому что вид больше, чем деления, я пробовал так много способов, но не работает, он должен двигаться на один шаг от того места, где он есть, независимо от направления касания, у вас есть идеи, пожалуйста, помогите, если вы можете
Вообще не смотрите вдаль. Не следи за пальцем. Просто посмотрите, в каком квадрате сейчас находится палец. Если заметки нет в этом квадрате, и этот квадрат пуст, переместите его туда. В противном случае ничего не делайте.