Как перетащить что-нибудь и прокрутить одновременно в UIScrollView - PullRequest
11 голосов
/ 24 июля 2011

Я пишу приложение, которое имеет вид книжной полки, как iBooks.

Проблема теперь в том, что я могу перетаскивать книгу из одного места в другое. Но как мне сделать это одновременно, когда я перетаскиваю книгу в конец прокрутки:

  1. сделать прокрутку вниз
  2. держи книгу за моим пальцем
  3. Поместите другие книги в нужное место с анимацией, как движущиеся приложения в трамплине

Я знаю, что в Github есть AQGridView, но похоже, что демонстрационная версия трамплина не поддерживает прокрутку и перемещение одновременно (я уже установил scrollEnable в YES)

1 Ответ

16 голосов
/ 24 июля 2011

Я дам вам свое решение, но, поскольку все это довольно большое, я просто дам вам соответствующие фрагменты.

Кроме того, учтите, что я использую распознаватель жестов для перетаскивания (UILongPressGestureRecognizer) какименно так пользователь инициирует перетаскивание в моем приложении, удерживая палец на объекте.Таким образом, каждому подпредставлению, которое вы можете перетащить, назначен собственный UILongPressGestureRecognizer, а цель / селектор этого распознавателя находится в другом классе, который управляет как прокруткой, так и подпредставлениями.

здесь - цель распознавателя жестов.:

-(void)dragged:(UILongPressGestureRecognizer *)panRecog
{
    if (panRecog.state == UIGestureRecognizerStateBegan)
    {
        UIView * pannedView = panRecog.view;

        dragView = pannedView;
        dragView.center = [panRecog locationInView:scrollView];

        [scrollView bringSubviewToFront:dragView];

        [self startDrag]; // Not important, changes some stuff on screen to show the user he is dragging 
        return;
    }

    if (panRecog.state == UIGestureRecognizerStateChanged)
    {
        int xDelta  = dragView.center.x - [panRecog locationInView:scrollView].x;
        dragView.center = [panRecog locationInView:scrollView];

        [self scrollIfNeeded:[panRecog locationInView:scrollView.superview] withDelta:xDelta];

        return;
    }

    if (panRecog.state == UIGestureRecognizerStateEnded)
    {
        [self endDrag]; // Not important, changes some stuff on screen to show the user he is not dragging anymore
    }
}

Вещи, которые актуальны для вас:

  • При запуске перетаскивания я сохраняю вид, который перетаскиваю в dragView и устанавливаю его центр в положение, в котором находится ваш палец.относительно вида прокрутки, в котором он находится.
  • startDrag не важен для вас, он меняет некоторые вещи на экране, чтобы показать пользователю, что он перетаскивает
  • Когда мы фактически перемещаем наш объект (UIGestureRecognizerStateChanged) Iполучить количество баллов, которое пользователь переместил пальцем, и использовать эту дельту вместе с позицией пальца пользователя, чтобы проверить, нужно ли перемещать представление прокрутки в scrollIfNeeded.

Это код

-(void)scrollIfNeeded:(CGPoint)locationInScrollSuperview withDelta:(int)xDelta
{
    UIView * scrollSuperview = scrollView.superview;
    CGRect bounds = scrollSuperview.bounds;
    CGPoint scrollOffset = scrollView.contentOffset;
    int xOfs = 0;
    int speed = 10;

    if ((locationInScrollSuperview.x > bounds.size.width * 0.7) && (xDelta < 0))
    {
        xOfs = speed * locationInScrollSuperview.x/bounds.size.width;
    }

    if ((locationInScrollSuperview.x < bounds.size.width * 0.3) && (xDelta > 0))
    {
        xOfs = -speed * (1.0f - locationInScrollSuperview.x/bounds.size.width);
    }

    if (xOfs < 0)
    {
        if (scrollOffset.x == 0)    return;
        if (xOfs < -scrollOffset.x) xOfs = -scrollOffset.x;
    }
    scrollOffset.x += xOfs;
    CGRect rect = CGRectMake(scrollOffset.x, 0, scrollView.bounds.size.width, scrollView.bounds.size.height);
    [scrollView scrollRectToVisible:rect animated:NO];
    CGPoint center = dragView.center;
    center.x += xOfs;
    dragView.center=center;
}

Эта вещь делает только горизонтальную прокрутку, но обработка по вертикали была бы очень похожа.Что он делает:

  • Проверьте, перетаскиваете ли вы в граничную область скроллвью (я использую 30% границу влево и вправо в качестве зоны, где должна происходить прокрутка).Но только если пользователь переместился в этом направлении (xDelta <0 для левого, xDelta> 0 для правого)
  • далее я вычисляю, сколько нужно переместить прокрутку, используя постоянную скорости и масштабируя ее в зависимости от того, как далеко пользовательот фактической границы прокрутки, поэтому скорость пропорциональна тому, как далеко от края находится пользователь.
  • Последним шагом является прокрутка прокрутки с помощью неанимированного scrollRectToVisible.Конечно, ваш перетаскиваемый вид движется, поэтому мы компенсируем это с противоположным смещением от его центра.

Надеюсь, это поможет вам.

...