Vá uma Tela suavemente no Android
-
21-09-2019 - |
Pergunta
Eu sou novo para o Android.
Estou desenhando mapas de bits, linhas e formas para uma Tela dentro do OnDraw(Lona lona) método de meu ponto de vista.Estou à procura de ajuda sobre como implementar a rolagem suave em resposta a um arrastar pelo usuário.Eu procurei, mas não encontrei nenhum tutorial para me ajudar com isso.
A referência para a Tela, parece dizer que, se uma Tela é construído a partir de um mapa de bits (chamado de bmpBuffer, por exemplo), então qualquer coisa desenhada sobre a Tela também é desenhado no bmpBuffer.Seria possível usar bmpBuffer para implementar um pergaminho ...talvez copiá-lo de volta para a Tela mudou por alguns pixels de cada vez?Mas se eu usar Lona.drawBitmap para desenhar bmpBuffer de volta para a Tela mudou por alguns pixels, não bmpBuffer ser corrompido?Talvez por isso, eu deveria copiar bmpBuffer para bmpBuffer2, em seguida, desenhar bmpBuffer2 de volta para a Tela.
Uma abordagem mais simples seria para desenhar as linhas, as formas, etc.em linha reta em um buffer de mapa de bits, em seguida, desenhar buffer (com uma mudança) para a Tela, mas tão longe quanto eu possa ver os vários métodos:drawLine(), drawShape() e assim por diante não estão disponíveis para o desenho em um Bitmap ...apenas a uma Tela.
Eu poderia ter 2 Telas?Um dos quais seria construída a partir de um buffer de mapa de bits e simplesmente utilizado para plotar as linhas, as formas, etc.e, em seguida, o buffer de bitmap deve ser desenhado para a outra Tela para exibir no modo de exibição?
Eu as boas-vindas a qualquer conselho!
Respostas para perguntas semelhantes aqui (e em outros sites) consulte "blitting".Eu entendo o conceito, mas não consigo encontrar nada sobre "blit" ou "bitblt" no Android documentação.São De Lona.drawBitmap e de Bitmap.Cópia do Android equivalentes?
Solução
Eu tive esse problema também,
Eu fiz o desenho assim:
Canvas BigCanvas = new Canvas();
Bitmap BigBitmap = new Bitmap(width,height);
int ScrollPosX , ScrollPosY // (calculate these with the onScrollEvent handler)
void onCreate()
{
BigCanvas.SetBitmap(BigBitmap);
}
onDraw(Canvas TargetCanvas)
{
// do drawing stuff
// ie. BigCanvas.Draw.... line/bitmap/anything
//draw to the screen with the scrolloffset
//drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)
TargetCanvas.DrawBitmap(BigBitmap(new Rect(ScrollPosX,ScrollPosY,ScrollPosX + BigBitmap.getWidth(),ScrollPosY + BigBitmap.getHeight(),new Rect(0,0,ScreenWidth,ScreenHeight),null);
}
Para rolagem suave, você precisaria fazer algum tipo de método que leva alguns pontos após a rolagem (ou seja, o primeiro ponto de rolagem e o 10º), subtrai -los e role por esse número em um loop que o torna gradualmente mais lento (roldição - turnos - atrito).
Espero que isso dê mais informações.
Outras dicas
Parece-me ter encontrado uma resposta.Coloquei a massa do código de desenho (que foi anteriormente no onDraw()) em um novo doDrawing() método.Este método começa por criar um novo mapa de bits maior do que a tela (grande o suficiente para manter o completo de desenho).Em seguida, ele cria uma segunda Tela em que para fazer o desenho detalhado:
BufferBitmap = Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888);
Canvas BufferCanvas = new Canvas(BufferBitmap);
O resto do doDrawing() o método é tomado com desenho detalhado para BufferCanvas.
Todo o onDraw() o método agora o seguinte:
@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(BufferBitmap, (float) -posX, (float) -posY, null);
}
A posição de variáveis, posX e posY, são inicializadas a 0 na aplicação do onCreate()método.A aplicação implementa OnGestureListener e usa o distanceX e distanceY argumentos devolvidos em OnScroll notificação para incrementar posX e posY.
Essa parece ser sobre tudo o que é necessário para implementar a rolagem suave.Ou eu sou sobre-procurando alguma coisa!?
Continuação da resposta a Viktor ...
De fato, a situação é mais complicada. Como o processo de Dodrawing é bastante lento (levando 2-3 segundos no meu lento e antigo telefone HTC Hero), achei desejável exibir uma mensagem de brinde para aconselhar o usuário que estava acontecendo e indicar o motivo. A maneira óbvia de fazer isso foi criar um novo método contendo apenas 2 linhas:
public void redrawBuffer(String strReason) {
Toaster.Toast(strReason, "Short");`
doDrawing();
}
e chamar esse método de outros lugares do meu programa em vez de Dodrawing ().
No entanto, descobri que a torradeira nunca apareceu ou apareceu tão brevemente que não podia ser lida. Minha solução alternativa foi usar um manipulador de cheques de tempo para forçar o programa a dormir por 200 milissegundos entre exibir o brinde e chamar Dodrawing (). Embora isso atrase um pouco o início de um redesenho, sinto que esse é um preço que vale a pena pagar em termos da usabilidade do programa porque o usuário sabe o que está acontecendo. RedrawBuffer () agora diz:
public void redrawBuffer(String strReason) {
Toaster.Toast(strReason, "Short");
mTimeCheckHandler.sleep(200);
}`
E o código do manipulador (que está aninhado na minha classe de visualização) é:
private timeCheckHandler mTimeCheckHandler = new timeCheckHandler();
class timeCheckHandler extends Handler {
@Override
public void handleMessage(Message msg) {
doDrawing();
}
public void sleep(long delayMillis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
}`
Não há necessidade de a atividade ser reiniciada! (De acordo com 27 de janeiro de Jan 10 de janeiro de 17 de janeiro, 'Resposta') Em vez de reciclar o bitmap e incorrer na sobrecarga de ter a atividade recarregada, você pode evitar que o aplicativo seja carregado pela colocação do atributo 'Android: ConfigChanges' mostrado abaixo, No elemento 'atividade' do arquivo Androidmanifest.xml para o aplicativo. Isso informa ao sistema que o aplicativo lidará com as alterações de orientação e que não precisa reiniciar o aplicativo.
<activity android:name=".ANote"
android:label="@string/app_name"
android:configChanges="orientation|screenLayout">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Este método pode ser usado para obter uma notificação quando a orienação é alterada:
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
prt("onConfigurationChanged: "+newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
prt(" PORTRAIT");
} else {
prt(" LANDSCAPE");
}
} // end of onConfigurationChanged
PrepBGG: Não acho que o código funcione porque o Canvas.drawbitmap não se baseia no bitmap, mas desenha o bitmap na tela.
Me corrija se eu estiver errado!