11

iBooks のようなブックシェルフ ビューを持つアプリを作成しています。

問題は次のとおりです。本をある場所から別の場所にドラッグ アンド ドロップできます。

  1. スクロールビューを下にスクロールします
  2. 本は私の指に従ってください
  3. スプリングボードでアプリを動かすようなアニメーションで、他の本を適切な場所に配置します

Github に AQGridView があることは知っていますが、スプリングボードのデモではスクロールと移動を同時にサポートしていないようです (既に scrollEnable を YES に設定しています)。

4

1 に答える 1

17

ソリューションを提供しますが、全体が非常に大きいため、関連するスニペットのみを提供します。

また、ドラッグにジェスチャ認識機能 (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 )、ユーザーが指を動かしたポイントの量を取得し、そのデルタをユーザーの指の位置と一緒に使用して、scrollView を 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 を使用して scrollview をスクロールすることです。もちろん、ドラッグされたビューは一緒に移動するので、中心の反対側のオフセットでそれを補正します。

うまくいけば、これはあなたを助けることができます.

于 2011-07-24T09:13:08.220 に答える