24

我是安卓新手。

我正在视图的 OnDraw(Canvas canvas) 方法内的 Canvas 上绘制位图、线条和形状。我正在寻求有关如何实现平滑滚动以响应用户拖动的帮助。我已经搜索但没有找到任何教程来帮助我。

Canvas 的参考似乎是说,如果 Canvas 是从 Bitmap(例如称为 bmpBuffer)构造的,那么在 Canvas 上绘制的任何内容也会在 bmpBuffer 上绘制。是否可以使用 bmpBuffer 来实现滚动......也许将它复制回 Canvas 一次移动几个像素?但是如果我使用 Canvas.drawBitmap 将 bmpBuffer 绘制回移动了几个像素的 Canvas,bmpBuffer 不会被破坏吗?因此,也许我应该将 bmpBuffer 复制到 bmpBuffer2 然后将 bmpBuffer2 绘制回画布。

一种更直接的方法是将线条、形状等直接绘制到缓冲区位图中,然后将该缓冲区(带有移位)绘制到画布上,但据我所知,有各种方法:drawLine()、drawShape()等等不可用于绘制到位图......只能绘制到画布上。

我可以有 2 个画布吗?其中一个将从缓冲区位图构造并仅用于绘制线条、形状等,然后将缓冲区位图绘制到另一个画布上以在视图中显示?

我应该欢迎任何建议!

此处(以及其他网站上)类似问题的答案是指“blitting”。我理解这个概念,但在 Android 文档中找不到任何关于“blit”或“bitblt”的信息。Canvas.drawBitmap 和 Bitmap.Copy Android 的等价物吗?

4

5 回答 5

13

我似乎找到了答案。我已将大部分绘图代码(以前在 onDraw() 中)放在一个新的 doDrawing() 方法中。此方法首先创建一个比屏幕大的新位图(大到足以容纳完整的绘图)。然后它会创建第二个 Canvas,在其上进行详细绘图:

    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 在应用程序的 onCreate() 方法中初始化为 0。应用程序实现 OnGestureListener 并使用 OnScroll 通知中返回的 distanceX 和 distanceY 参数来增加 posX 和 posY。

这似乎是实现平滑滚动所需的全部内容。还是我忽略了什么!?

于 2010-01-17T18:01:55.003 回答
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 - 转弯 - 摩擦)。

我希望这能提供更多的见解。

于 2010-06-18T11:02:01.853 回答
1

无需重新启动活动!(根据 prepbgg 的 Jan 27 10 对他 Jan 17 10 'answer' 的回复),您可以通过放置如下所示的 '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
于 2011-01-04T14:14:45.347 回答
1

继续回复维克多...

事实上,情况要复杂得多。因为 doDrawing 过程非常慢(在我的旧 HTC Hero 手机上需要 2-3 秒),我发现最好弹出一条 Toast 消息来告知用户它正在发生并指出原因。显而易见的方法是创建一个仅包含 2 行的新方法:

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

并从我程序中的其他地方调用此方法,而不是 doDrawing()。

然而,我发现烤面包机要么从来没有出现过,要么闪过的时间太短以至于无法读取。我的解决方法是使用时间检查处理程序强制程序在显示 Toast 和调用 doDrawing() 之间休眠 200 毫秒。尽管这会稍微延迟重绘的开始,但我认为就程序的可用性而言,这是值得付出的代价,因为用户知道发生了什么。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);
    }
}`
于 2011-03-26T22:27:10.923 回答
0

prepbgg:我认为代码不会起作用,因为 canvas.drawBitmap 不会绘制到位图中,而是将位图绘制到画布上。

如果我错了,请纠正我!

于 2010-05-04T10:01:56.333 回答