Прокрутка холста плавно в Android - PullRequest
24 голосов
/ 17 января 2010

Я новичок в Android.

Я рисую растровые изображения, линии и формы на холсте внутри метода OnDraw (холст холста) моего представления. Я ищу помощь о том, как реализовать плавную прокрутку в ответ на перетаскивание пользователем. Я искал, но не нашел учебников, которые могли бы помочь мне с этим.

Ссылка на Canvas, по-видимому, говорит о том, что если Canvas создается из растрового изображения (скажем, bmpBuffer), то все, что нарисовано на Canvas, также рисуется в bmpBuffer. Можно ли использовать bmpBuffer для реализации прокрутки ... возможно, скопировать его обратно на холст, сдвинутый на несколько пикселей за раз? Но если я использую Canvas.drawBitmap, чтобы нарисовать bmpBuffer обратно в Canvas, сдвинутый на несколько пикселей, не будет ли bmpBuffer поврежден? Возможно, поэтому я должен скопировать bmpBuffer в bmpBuffer2, а затем нарисовать bmpBuffer2 обратно на холст.

Более простым подходом было бы нарисовать линии, фигуры и т. Д. Прямо в буфере Bitmap, а затем нарисовать этот буфер (со смещением) на Canvas, но насколько я вижу различные методы: drawLine (), drawShape () и т. д. недоступны для рисования в растровое изображение ... только для Canvas.

Могу ли я иметь 2 холста? Один из которых будет построен из растрового изображения буфера и использован просто для построения линий, фигур и т. Д., А затем растровое изображение буфера будет нарисовано на другом холсте для отображения в представлении?

Я должен приветствовать любой совет!

Ответы на аналогичные вопросы здесь (и на других сайтах) относятся к «блинтингу». Я понимаю концепцию, но не могу найти ничего о "blit" или "bitblt" в документации Android. Являются ли Canvas.drawBitmap и Bitmap.Copy для Android эквивалентами?

Ответы [ 5 ]

12 голосов
/ 17 января 2010

Кажется, я нашел ответ. Я поместил основную часть кода рисования (который ранее был в onDraw ()) в новый метод doDrawing (). Этот метод начинается с создания нового растрового изображения, большего, чем экран (достаточно большого, чтобы вместить весь рисунок). Затем он создает второй холст для детального рисования:

    BufferBitmap = Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888);
    Canvas BufferCanvas = new Canvas(BufferBitmap);

Остальная часть метода doDrawing () переносится с подробным рисунком в BufferCanvas.

Весь метод onDraw () теперь выглядит следующим образом:

    @Override protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawBitmap(BufferBitmap, (float) -posX, (float) -posY, null);
}

Переменные положения posX и posY инициализируются в 0 в методе приложения onCreate (). Приложение реализует OnGestureListener и использует аргументы distanceX и distanceY, возвращенные в уведомлении OnScroll, для увеличения posX и posY.

Похоже, это все, что нужно для реализации плавной прокрутки. Или я что-то упускаю !?

1 голос
/ 27 марта 2011

Продолжение ответа Виктору ...

На самом деле ситуация сложнее. Поскольку процесс doDrawing довольно медленный (занимает 2-3 секунды на моем медленном старом телефоне HTC Hero), я посчитал желательным вывести всплывающее сообщение, чтобы сообщить пользователю, что это происходит, и указать причину. Очевидный способ сделать это - создать новый метод, содержащий всего две строки:

public void redrawBuffer(String strReason) {
    Toaster.Toast(strReason, "Short");`
    doDrawing();
}

и вызывать этот метод из других мест моей программы вместо doDrawing ().

Однако я обнаружил, что Тостер либо никогда не появлялся, либо вспыхивал так коротко, что его нельзя было прочитать. Мой обходной путь - использовать обработчик проверки времени, чтобы заставить программу спать в течение 200 миллисекунд между отображением Toast и вызовом doDrawing (). Хотя это немного задерживает начало перерисовки, я чувствую, что это цена, которую стоит заплатить с точки зрения удобства использования программы, потому что пользователь знает, что происходит. reDrawBuffer () теперь читает:

public void redrawBuffer(String strReason) {
    Toaster.Toast(strReason, "Short");
    mTimeCheckHandler.sleep(200);    
}`

и код обработчика (который вложен в мой класс View):

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);
    }
}`
1 голос
/ 04 января 2011

Нет необходимости перезапускать активность! (В соответствии с ответом 27 января 10 Prepbgg на его «ответ» от 17 января 10) Вместо того, чтобы перерабатывать растровое изображение и нести дополнительные затраты на перезагрузку действия, вы можете избежать загрузки приложения, добавив атрибут «android: configChanges», показанный ниже в элементе Activity файла AndroidManifest.xml для приложения. Это сообщает системе, что приложение будет обрабатывать изменения ориентации и что ему не нужно перезапускать приложение.

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

Этот метод можно использовать для получения уведомления об изменении ориентации:

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
1 голос
/ 18 июня 2010

У меня тоже была эта проблема,

Я сделал рисунок так:

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

для плавной прокрутки вам нужно создать какой-то метод, который займет несколько точек после прокрутки (т.е. первую точку прокрутки и десятую), вычесть их и прокрутить по этому числу в каждом цикле, что делает его постепенно медленнее (ScrollAmount - повороты - трение).

Надеюсь, это даст немного больше понимания.

0 голосов
/ 04 мая 2010

prepbgg: я не думаю, что код будет работать, потому что canvas.drawBitmap не рисует в растровом изображении, а рисует растровое изображение на холсте.

Поправь меня, если я ошибаюсь!

...