Pergunta

Estou usando o método OnScroll de GesturedEtector.SimpLoNgoSteListener para rolar um grande bitmap em uma tela. Quando o rolo terminar, quero redesenhar o bitmap, caso o usuário queira rolar ainda mais ... fora da borda do bitmap, mas não consigo ver como detectar quando o pergaminho terminou (o usuário levantou o dedo da tela).

e2.getAction () sempre parece retornar o valor 2, então isso não ajuda. O E2.GetPressure parece retornar valores razoavelmente constantes (cerca de 0,25) até a chamada final do Scroll quando a pressão parece cair para cerca de 0,13. Suponho que poderia detectar essa redução na pressão, mas isso estará longe de ser infalível.

Deve haver uma maneira melhor: alguém pode ajudar, por favor?

Foi útil?

Solução

Aqui está como eu resolvi o problema. Espero que isto ajude.

// declare class member variables
private GestureDetector mGestureDetector;
private OnTouchListener mGestureListener;
private boolean mIsScrolling = false;


public void initGestureDetection() {
        // Gesture detection
    mGestureDetector = new GestureDetector(new SimpleOnGestureListener() {
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            handleDoubleTap(e);
            return true;
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            handleSingleTap(e);
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            // i'm only scrolling along the X axis
            mIsScrolling = true;                
            handleScroll(Math.round((e2.getX() - e1.getX())));
            return true;
        }

        @Override
        /**
         * Don't know why but we need to intercept this guy and return true so that the other gestures are handled.
         * https://code.google.com/p/android/issues/detail?id=8233
         */
        public boolean onDown(MotionEvent e) {
            Log.d("GestureDetector --> onDown");
            return true;
        }
    });

    mGestureListener = new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {

            if (mGestureDetector.onTouchEvent(event)) {
                return true;
            }

            if(event.getAction() == MotionEvent.ACTION_UP) {
                if(mIsScrolling ) {
                    Log.d("OnTouchListener --> onTouch ACTION_UP");
                    mIsScrolling  = false;
                    handleScrollFinished();
                };
            }

            return false;
        }
    };

    // attach the OnTouchListener to the image view
    mImageView.setOnTouchListener(mGestureListener);
}

Outras dicas

Você deve dar uma olhada em http://developer.android.com/reference/android/widget/scroller.html. Especialmente isso pode ser útil (classificado por relevância):

isFinished();
computeScrollOffset();
getFinalY(); getFinalX(); and getCurrY() getCurrX()
getDuration()

Isso implica que você precisa criar um roller.

Se você quiser usar o toque, também pode usar o GesturedEtector e definir sua própria rolagem de lona. A amostra a seguir está criando um scrollableImageView e, para usá -lo, você deve definir as medidas da sua imagem. Você pode definir seu próprio alcance de rolagem e, depois de terminar a rolagem, a imagem é redesenhada.

http://www.anddev.org/viewtopic.php?p=31487#31487

Dependendo do seu código, considere invalidar (int l, int t, int r, int b); para a invalidação.

SimpleOnGestureListener.onFling() 

Parece ocorrer quando um rolagem termina (ou seja, o usuário deixa o dedo ir), é isso que estou usando e funciona muito bem para mim.

Voltando a isso depois de alguns meses, agora segui uma abordagem diferente: usar um manipulador (como na amostra de cobra Android) para enviar uma mensagem ao aplicativo a cada 125 milissegundos, o que o leva a verificar se um rolagem foi iniciado e Se mais de 100 milissegundos se passaram desde o último evento de rolagem.

Isso parece funcionar muito bem, mas se alguém puder ver alguma desvantagem ou possíveis melhorias, eu deveria agradecer por ouvi -las.

O código relevante está na classe MyView:

public class MyView extends android.view.View {

...

private long timeCheckInterval = 125; // milliseconds
private long scrollEndInterval = 100;
public long latestScrollEventTime;
public boolean scrollInProgress = false;

public MyView(Context context) {
    super(context);
}

private timeCheckHandler mTimeCheckHandler = new timeCheckHandler();

class timeCheckHandler extends Handler{

        @Override
        public void handleMessage(Message msg) {
        long now = System.currentTimeMillis();
        if (scrollInProgress && (now>latestScrollEventTime+scrollEndInterval)) {
                    scrollInProgress = false;

// Scroll terminou, então insira o código aqui

// que chama o método Dodrawing ()

// Para redrair o bitmap re-centrado onde o rolagem terminou

                    [ layout or view ].invalidate();
        }
        this.sleep(timeCheckInterval);
        }

        public void sleep(long delayMillis) {
            this.removeMessages(0);
            sendMessageDelayed(obtainMessage(0), delayMillis);
            }
    }
}

@Override protected void onDraw(Canvas canvas){
        super.onDraw(canvas);

// Código para desenhar bitmap de buffer grande na tela da vista // posicionado para levar em consideração qualquer pergaminho que esteja em andamento

}

public void doDrawing() {

// código para fazer desenho detalhado (e demorado) // em bitmap buffer grande

// A instrução a seguir redefine o relógio de verificação de tempo // o relógio é iniciado pela primeira vez quando // a atividade principal chama esse método quando o aplicativo inicia

        mTimeCheckHandler.sleep(timeCheckInterval);
}

// RESTENHA DA MYVIEW CLASSE

}

e na aula de mineesturetector

public class MyGestureDetector extends SimpleOnGestureListener {

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
        float distanceY) {

    [MyView].scrollInProgress = true;
        long now = System.currentTimeMillis();  
    [MyView].latestScrollEventTime =now;

    [MyView].scrollX += (int) distanceX;
    [MyView].scrollY += (int) distanceY;

// A próxima instrução faz com que o método OnDraw da exibição seja chamado // que plota o bitmap buffer na tela // mudou para levar em conta o rolagem

    [MyView].invalidate();

}

// Resto da aula de MyestureTector

}

Eu estava olhando para o mesmo problema. Eu vi Akos CZ responder à sua pergunta. Criei algo semelhante, mas com a minha versão notei que ela só funcionava para um rolagem regular - significando um que não gera uma aventura. Mas se uma aventura foi gerada - independentemente de eu processar uma aventura ou não, ela não detectou a "ação_up" em "OnTouchEvent". Agora, talvez isso tenha sido apenas algo com minha implementação, mas se fosse, eu não conseguia descobrir o porquê.

Após uma investigação mais aprofundada, notei que, durante uma aventura, o "Action_up" foi passado para "Onfling" em "E2" todas as vezes. Então, achei que deveria ser por isso que não estava sendo tratado em "OnTouchEvent" nesses casos.

Para fazer funcionar para mim, eu só precisava chamar um método para lidar com o "Action_up" em "Onfling" e, em seguida, funcionou para os dois tipos de rolagem. Abaixo estão as etapas exatas que tomei para implementar no meu aplicativo:

-Initializou um booleano "gesturescrolling" para "falso" em um construtor.

-Eu defini -o como "true" em "OnScroll"

-Criou um método para lidar com o evento "Action_up". Dentro desse evento, redefino "gesturescrolling" para False e depois fiz o restante do processamento que precisava fazer.

-in "OnTouchEvent", se um "action_up" foi detectado e "gestrescrolling" = true, então chamei meu método para lidar com "action_up"

-E a parte que eu fiz isso foi diferente foi: também chamei meu método para lidar com "Action_up" dentro de "onfling".

Tenho certeza de que é tarde demais para você, no entanto, parece que encontrei a solução certa para sua pergunta original e não é necessária a intenção.

Se você estiver usando o objeto Scroller/Overcroller para rolagem, verifique o valor de retorno da seguinte função.

public boolean computeScrollOffset() 

desfrutar

Harvinder

Isto é o que funcionou para mim.

Eu enriqueci o existente GesturedEtector.ongestureListener com onfingerup () método. Esse ouvinte faz tudo como o gesturedEtector interno e também pode ouvir o evento Dídio (não é onfling (), pois isso é chamado apenas quando o dedo é levantado junto com uma ação rápida de deslizamento).

import android.content.Context;
import android.os.Handler;
import android.view.GestureDetector;
import android.view.MotionEvent;

public class FingerUpGestureDetector extends GestureDetector {
    FingerUpGestureDetector.OnGestureListener fListener;
    public FingerUpGestureDetector(Context context, OnGestureListener listener) {
        super(context, listener);
        fListener = listener;
    }

    public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, OnGestureListener fListener) {
        super(context, listener);
        this.fListener = fListener;
    }

    public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler, OnGestureListener fListener) {
        super(context, listener, handler);
        this.fListener = fListener;
    }

    public FingerUpGestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler, boolean unused, OnGestureListener fListener) {
        super(context, listener, handler, unused);
        this.fListener = fListener;
    }

    public interface OnGestureListener extends GestureDetector.OnGestureListener {
        boolean onFingerUp(MotionEvent e);
    }

    public static class SimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements FingerUpGestureDetector.OnGestureListener {
        @Override
        public boolean onFingerUp(MotionEvent e) {
            return false;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (super.onTouchEvent(ev)) return true;
        if (ev.getAction() == MotionEvent.ACTION_UP) {
            return fListener.onFingerUp(ev);
        }
        return false;
    }
}

Eu não fiz isso eu mesmo, mas olhando para o oTouch () você sempre obtém uma sequência 0 <2> 1, então o final deve ser um 1 para levantar os dedos.

Não conheço o Android, mas olhando para a documentação parece que Rob está certo: Android Action_Up constante Tente verificar o Action_up de getAction ()?

EDIT: O que o e1.getAction () mostra? Ele já retorna Action_up? A documentação diz que mantém o evento inicial inicial, então talvez ele também notifique quando o ponteiro está pronto

EDIT: Apenas mais duas coisas que eu consigo pensar. Você está retornando false em algum momento? Isso pode impedir o Action_up

A única outra coisa que eu tentaria é ter um evento separado, talvez ondown, e definir uma bandeira dentro do scroll, como o ISSCROLLING. Quando o Action_Up é dado ao Ondown e o ISSCrolling é definido, você pode fazer o que quiser e redefinir o ISSCrolling para false. Isto é, assumindo que o Ondown é chamado junto com o Scroll, e o GetAction retornará Action_up durante o Ondown

Eu não tentei / usei isso, mas uma ideia para uma abordagem:

Pare / interrompa a tela de redefinição em todos os eventos de rolagem aguarde 1s e, em seguida, comece a redesenhar a tela em cada rolagem.

Isso levará a realizar o redesenho apenas na extremidade de rolagem, pois apenas o último pergaminho será realmente ininterrupto para a conclusão do Redraw.

Espero que essa ideia ajude você :)

Extrato do evento OnScroll da API GestureListener: Texto do link

abstrato público boolean onScroll (MotionEvent E1, MotionEvent E2, Float Distancex, Float Doursey) desde: API Nível 1

Retorna * true se o evento for consumido, senão falso

Talvez uma vez que o evento tenha sido consumido, a ação está concluída e o usuário tirou o dedo da tela ou, pelo menos, terminou esta ação de scroll

Você pode usar isso em uma instrução IF para digitalizar == true e depois começar com a próxima ação.

Eu acho que isso vai funcionar como você precisa

protected class SnappingGestureDetectorListener extends SimpleOnGestureListener{

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY){
        boolean result = super.onScroll(e1, e2, distanceX, distanceY);

        if(!result){
            //Do what you need to do when the scrolling stop here
        }

        return result;
    }

}

Minha tentativa de adicionar funcionalidade adicional ao detector de gestos. Espero que ajude alguém a dedicar seu tempo a usar melhor ...

https://gist.github.com/wildorangutan/043807ddbd68978179b7cea3b53c71e8

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top