Tutorial sobre como arrastar e soltar itens do UITableView para UITableView [fechado]

Eu tenho batido minha cabeça nessa por um tempo e eu descobri. Quero retribuir à comunidade, pois recebi muita ajuda deste site :).

Estou tentando copiar um item de um UITableView para outro UITableView e as informações que eu vi na Web sobre como fazer isso foram, na melhor das hipóteses, incompletas. Eu descobri por conta própria e, portanto, descreverei minha pequena arquitetura.

Master UIViewUIView com UITableViewUITableViewCell personalizadoUIView personalizado que é copiado (objeto Pessoa no meu caso)UIView com UITableViewUITableViewCell personalizadoUIView personalizado que é copiado (objeto Pessoa no meu caso)

O objeto de pessoa que eu tenho no UITableView é o objeto que eu quero arrastar e soltar de uma tabela e para outra. Eu tive o mais difícil de descobrir como tirar o item da mesa e arrastá-lo em um único movimento suave. Durante muito tempo, levei dois toques para executar a operação.

Começando com o objeto Pessoa, esse é um objeto simples que contém uma imagem. Eu tive que implementar meu próprio método touchesMoved para alterar a posição central da Pessoa quando um arrasto está ocorrendo.

-(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;
            }
        }
    }
}

Defino o sinalizador userInteractionEnabled do objeto Person como NO na inicialização, para que quaisquer cliques na tabela não sejam capturados pelo objeto Person. O objeto Person nesse caso se moveria dentro da tabela que anula o objetivo.

O próximo objeto é meu UITableViewCell personalizado. Esse objeto é responsável por capturar o primeiro toque do usuário. O que ele deve fazer é pegar esse toque e "estourar" a Pessoa. A Pessoa é uma das subvisões pertencentes ao UITableViewCell personalizado.

 - (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
    }
}

É importante observar que o sinalizador userInteractionEnabled é ativado no método acima. Antes do toque, o objeto Pessoa está "fora dos limites" ao toque de uma pessoa. Após a célula personalizada capturar uma movimentação, a Pessoa é liberada adicionando-a à visualização dos pais e ativada (userInteractionEnabled = YES). O objeto Person é "nascido" e pode lidar com os toques por si próprio.

Isso tem uma pequena falha, pois o objeto Person pisca no canto superior esquerdo, mas desce imediatamente para o dedo do usuário.

A parte final desse design é que o UIView mestre precisa lidar com uma "transição de toque". Quando o usuário está tocando na mesa e o objeto Pessoa é exibido, o aplicativo precisa perceber que o foco precisa ser removido da tabela e direcionado ao objeto Pessoa. A maneira como isso foi feito é que o método hitTest no UIView mestre foi sobrecarregado com o seguinte.

- (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;
}

A maneira como esse código funciona é que, quando a Pessoa é removida da tabela, ele não tem um toque focado nela. O toque é "de propriedade" do UITableView do qual a Pessoa foi retirada. O método hitTest é a chave para reorientar esse toque. Regularmente, o sistema verifica se o UIView é o foco de um toque. O método hitTest é chamado pelo sistema para identificar esse UIView. Quando a Pessoa é anexada à visualização principal, essa função hitTest repete todas as subvisões e detecta a presença da Pessoa e a retorna como o objeto tocado "dominante". Qualquer movimento do seu dedo será imediatamente relatado à Pessoa e não ao UITableView.

Isso é coragem da implementação. Para ter um "catch" do UITableView, o objeto em movimento é simples agora e deixarei para você tentar! Se você tiver alguma dúvida, poste-a!

EDIT # 1 Soltar o objeto Person está se mostrando mais difícil do que eu pensava :). Eu tive que adicionar uma linha para impedir que o UITableView rolasse quando o pai estiver sendo movido, porque o UITableView está sugando todos os eventos de movimento.
A função touchesEnded é acionada na classe UITableViewCell personalizada.
mj

questionAnswers(1)

yourAnswerToTheQuestion