如何在UIScrollView中拖动和移动某些内容并同时滚动

ult*_*gtx 11 iphone uiscrollview ios aqgridview

我正在写一个有iBooks书架视图的应用程序.

现在的问题是:我可以将一本书从一个地方拖放到另一个地方.但是当我将书籍拖到滚动视图的底部时,如何让它们同时发生:

  1. 滚动视图向下滚动
  2. 让书跟着我的手指
  3. 将其他书籍放在正确的位置,使用动画,例如在跳板中移动应用程序

我知道在Github中有一个AQGridView,但似乎跳板演示不支持同时滚动和移动.(我已经将scrollEnable设置为YES)

Jor*_*ans 16

我会给你我的解决方案,但由于整个事情都很大,我只会给你相关的片段.

此外,请注意我使用手势识别器进行拖动(UILongPressGestureRecognizer),因为这是用户通过将手指按在对象上来启动在我的应用中拖动的方式.因此,您可以拖动的每个子视图都有自己的UILongPressGestureRecognizer,并且该识别器的目标/选择器位于管理scrollview和子视图的另一个类中.

这是手势识别器的目标:

-(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
    }
}
Run Code Online (Sandbox Code Playgroud)

与您相关的事情:

  • 当我开始拖动时,我存储了我在dragView中拖动的视图,并将其中心设置为手指相对于它所在的滚动视图的位置.
  • startDrag对你来说并不重要,它会在屏幕上更改一些内容以显示他正在拖动的用户
  • 当我们实际移动对象(UIGestureRecognizerStateChanged)时,我得到用户移动手指的点数,并将该delta与用户的手指位置一起使用,以检查是否需要在scrollIfNeeded中移动scrollview.

这是代码

-(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;
}
Run Code Online (Sandbox Code Playgroud)

这个东西只做水平滚动,但处理垂直是非常相似的.它的作用是:

  • 检查是否拖动到scrollview的边界区域(我使用30%左右边框作为应该进行滚动的区域).但只有当用户朝那个方向移动时(xDelta <0表示左侧,xDelta> 0表示右侧)
  • 接下来我计算移动滚动视图的数量,使用速度常数并根据用户离滚动视图的实际边界的距离进行缩放,以便速度与用户边缘的距离成比例.
  • 最后一步是使用非动画scrollRectToVisible滚动滚动视图.当然你拖动的视图会移动,所以我们用它的中心的相反偏移来补偿它.

希望这可以帮助你.