Плавная прокрутка холста в Android
-
21-09-2019 - |
Вопрос
Я новичок в Android.
Я рисую растровые изображения, линии и фигуры на холсте внутри метода OnDraw (холст холста) моего представления.Мне нужна помощь, как реализовать плавную прокрутку в ответ на перетаскивание пользователем.Я искал, но не нашел никаких руководств, которые могли бы помочь мне в этом.
В ссылке на Canvas говорится, что если Canvas создан из растрового изображения (скажем, называемого bmpBuffer), то все, что нарисовано на Canvas, также рисуется в bmpBuffer.Можно ли использовать bmpBuffer для реализации прокрутки...возможно, скопировать его обратно на холст, сдвинутый на несколько пикселей за раз?Но если я использую Canvas.drawBitmap для отрисовки bmpBuffer обратно в Canvas, сдвинутого на несколько пикселей, не будет ли bmpBuffer поврежден?Поэтому, возможно, мне следует скопировать bmpBuffer в bmpBuffer2, а затем нарисовать bmpBuffer2 обратно на холст.
Более простой подход — нарисовать линии, формы и т. д.прямо в растровое изображение буфера, затем нарисуйте этот буфер (со сдвигом) на холсте, но, насколько я вижу, различные методы:drawLine(), drawShape() и т. д. недоступны для рисования в растровом изображении...только на холст.
Могу ли я получить 2 холста?Один из них будет создан из растрового изображения буфера и использован просто для построения линий, фигур и т. д.а затем растровое изображение буфера будет нарисовано на другом холсте для отображения в представлении?
Буду рад любому совету!
Ответы на подобные вопросы здесь (и на других сайтах) относятся к «блитингу».Я понимаю эту концепцию, но не могу найти ничего о «blit» или «bitblt» в документации Android.Являются ли Canvas.drawBitmap и Bitmap.Copy эквивалентами Android?
Решение
У меня тоже была эта пробема,
Рисунок я делал так:
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 - повороты - Трение).
Надеюсь, это даст больше понимания.
Другие советы
Кажется, я нашел ответ.Я поместил большую часть кода рисования (который ранее находился в 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.
Кажется, это все, что нужно для реализации плавной прокрутки.Или я что-то упускаю!?
Продолжение ответа Виктору...
На самом деле ситуация сложнее.Поскольку процесс doDrawing довольно медленный (на моем старом медленном телефоне HTC Hero он занимает 2-3 секунды), я счел желательным вывести всплывающее сообщение, чтобы сообщить пользователю, что это происходит, и указать причину.Очевидный способ сделать это — создать новый метод, содержащий всего две строки:
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);
}
}`
Нет необходимости перезапускать действие!(Согласно ответу prepbgg от 27 10 января на его «ответ» от 17 10 января). Вместо того, чтобы перерабатывать растровое изображение и нести накладные расходы на перезагрузку активности, вы можете избежать загрузки приложения, поместив атрибут «android: configChanges», показанный ниже: в элементе «активность» файла 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
препбгг:Я не думаю, что код будет работать, потому что Canvas.drawBitmap не рисует растровое изображение, а рисует его на холсте.
Поправьте меня, если я ошибаюсь!