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


Я новичок в Android.

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

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

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

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

Я буду рад любому совету!

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

5 23

5 ответов:

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

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

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-turns-Friction).

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

Я, кажется, нашел ответ. Я поместил большую часть кода чертежа (который ранее был в 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);
}

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

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

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

На самом деле ситуация гораздо сложнее. Поскольку процесс doDrawing довольно медленный (занимает 2-3 секунды на моем старом медленном телефоне HTC Hero), я счел желательным всплывающее сообщение тоста, чтобы сообщить пользователю, что это происходит, и указать причину. Очевидным способом сделать это было создать новый метод, содержащий всего 2 строки:
public void redrawBuffer(String strReason) {
    Toaster.Toast(strReason, "Short");`
    doDrawing();
}

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

Однако я обнаружил, что тостер либо никогда не появлялся, либо вспыхивал так быстро, что его невозможно было прочитать. Мой обходной путь состоял в использовании обработчика проверки времени, чтобы заставить программу спать в течение 200 миллисекунд между отображением тоста и вызовом 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);
    }
}`

Нет необходимости перезапускать действие! (В соответствии с ответом 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

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

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