Подтвердить что ты не робот

Прокрутка холста плавно в Android

Я новичок в Android.

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

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

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

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

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

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

4b9b3361

Ответ 1

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

Я сделал рисунок следующим образом:

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

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

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

Ответ 2

Кажется, я нашел ответ. Я поместил основную часть кода чертежа (который ранее был в 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 в методе applicationCreate(). Приложение реализует OnGestureListener и использует аргументы distanceX и distanceY, возвращаемые в уведомлении OnScroll, для увеличения posX и posY.

Это похоже на все, что нужно для обеспечения плавной прокрутки. Или я слишком-то смотрю!?

Ответ 3

Нет необходимости перезапускать активность! (Per prepbgg 27 января 10 ответ на его ответ 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

Ответ 4

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

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

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

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

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

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

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

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

Ответ 5

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

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