web-dev-qa-db-ja.com

UITableViewからUITableViewにアイテムをドラッグアンドドロップする方法に関するチュートリアル

私はしばらくこれに頭をぶつけて、それを理解しました。私はこのウェブサイトから多くの助けを得たので、コミュニティに還元したいと思います:)。

あるUITableViewから別のUITableViewにアイテムをコピーしようとしていますが、これを行う方法に関してWebで見た情報は、概して大雑把です。私はそれを自分で考え出したので、私の小さなアーキテクチャについて説明します。

  • マスターUIView
    • UITableViewを備えたUIView
      • カスタムUITableViewCell
        • コピーされるカスタムUIView(私の場合はPersonオブジェクト)
    • UITableViewを備えたUIView
      • カスタムUITableViewCell
        • コピーされるカスタムUIView(私の場合はPersonオブジェクト)

UITableViewにあるpersonオブジェクトは、あるテーブルから別のテーブルにドラッグアンドドロップするオブジェクトです。テーブルからアイテムをポップし、1回のスムーズなモーションでドラッグする方法を理解するのが最も困難でした。長い間、操作を実行するのに2つのタッチが必要でした。

Personオブジェクトから始めて、これは画像を含む単純なオブジェクトです。ドラッグが行われているときにPersonの中心位置を変更するには、独自のtouchesMovedメソッドを実装する必要がありました。

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
    if( m_moveable == YES ){
        UITouch *touch = [touches anyObject];
        CGPoint location = [touch locationInView:self.superview];

        if( 0 < location.x-50 && location.x+50 < 768 ){ 
            if( 0 < location.y-50 && location.y+150 < 1004 ){
                self.center = location;
            }
        }
    }
}

PersonオブジェクトのuserInteractionEnabledフラグを初期化時にNOに設定して、テーブル内のクリックがPersonオブジェクトにキャッチされないようにしました。その場合、Personオブジェクトはテーブル内を移動し、目的を達成できなくなります。

次のオブジェクトは、カスタムUITableViewCellです。このオブジェクトは、ユーザーの最初のタッチをキャッチします。それがやるべきことは、このタッチをキャッチして人を「ポップ」することです。 Personは、カスタムUITableViewCellに属するサブビューの1つです。

 - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UIView *parent = self.superview.superview.superview;    

    Person *s = nil;
    for( UIView *child in self.subviews ){
        if( [child isKindOfClass:[Person class]] ){
            s = child;
            s removeFromSuperview];
            break;
        }        
    }

    if( s != nil ){
        self.userInteractionEnabled = NO;
        s.userInteractionEnabled = YES;
        UITableView *subParent = self.superview;   //EDIT #1
        subParent.scrollEnabled = NO;              //EDIT #1

        [parent addSubview:s];
        //[self touchesEnded:touches withEvent:event]; //EDIT #1
    }
}

上記のメソッドでuserInteractionEnabledフラグが反転することに注意することが重要です。タッチする前は、Personオブジェクトはタッチに「立ち入り禁止」になっています。カスタムセルが移動をキャッチした後、Personは親のビューに追加して解放され、アクティブ化されます(userInteractionEnabled = YES)。その後、Personオブジェクトは「生まれ」、自身の移動タッチを処理できます。

これには、Personオブジェクトが左上隅で点滅するが、すぐにユーザーの指に落ちるという小さな不具合があります。

このデザインの最後の部分は、マスターUIViewが「タッチ遷移」を処理する必要があることです。ユーザーがテーブルに触れているときにPersonオブジェクトがポップアウトされると、アプリはフォーカスをテーブルから削除してPersonオブジェクトに向ける必要があることを認識する必要があります。これが行われた方法は、マスターUIViewのhitTestメソッドが次のようにオーバーロードされたことです。

- (UIView*) hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *rv = nil;
    for(UIView *child in self.subviews){
        if( [child isKindOfClass:[Person class]] ){
            rv = child;
            child.center = point;
            break;
        }
    }
    if( rv == nil ){
        rv = [super hitTest:point withEvent:event];
    }   
    return rv;
}

このコードが機能する方法は、Personがテーブルからポップアウトされるとき、それにフォーカスされたタッチがないということです。タッチは、PersonがポップアウトされたUITableViewによって「所有」されます。 hitTestメソッドは、そのタッチに再び焦点を合わせるための鍵です。定期的に、システムはどのUIViewがタッチのフォーカスであるかを確認します。 hitTestメソッドは、そのUIViewを識別するためにシステムによって呼び出されます。 Personがマスタービューにアタッチされると、このhitTest関数はすべてのサブビューを反復処理し、Personの存在を検出して、「優勢」なタッチされたオブジェクトとして返します。指の動きはすぐにPersonに報告され、UITableViewには報告されません。

これは実装の要点です。 UITableViewを「キャッチ」するために、移動するオブジェクトは簡単になりました。試してみることにしましょう!質問があれば投稿してください!

編集#1 Personオブジェクトの削除は、思ったより難しくなります:) UITableViewがすべての移動イベントを吸い込んでいるため、親が移動されているときにUITableViewがスクロールしないように線を追加する必要がありました。
touchesEnded関数は、カスタムUITableViewCellクラスで発生します。
mj

47
mj_

こんにちは、UITableViewの行を同じテーブルの別の行にドラッグアンドドロップして作成しました。 (テーブルから削除されなかった)移動するアイテムを表すuiImageViewを作成し、それを最前面のUIViewにアタッチして、画面全体でドラッグできるようにしました。ここに私が直面した痛みについてのいくつかの投稿があります:

  1. ITableView:行を別の行にドラッグします
  2. ITableView:プログラムでコンテンツビューをスクロール
  3. ITableView:カスタムジェスチャーでスクロールしなくなります

これが役立つことを願っています^^

7
rano