在Android中平滑地滚动画布

时间:2010-01-16 23:21:17

标签: android android-canvas smooth-scrolling

我是Android的新手。

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

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

更直接的方法是将线条,形状等直接绘制到缓冲区中Bitmap然后将该缓冲区(带有移位)绘制到Canvas上,但我可以看到各种方法:drawLine(), drawShape()等不能用于绘制到Bitmap ...仅用于Canvas。

我可以有2幅画布吗?其中一个是从缓冲区位图构造的,仅用于绘制线条,形状等,然后缓冲区位图将被绘制到另一个Canvas中以便在View中显示?

我应该欢迎任何建议!

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

5 个答案:

答案 0 :(得分:12)

我似乎找到了答案。我把大量的绘图代码(以前在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。

这似乎是实现平滑滚动所需的全部内容。或者我过度看东西了??

答案 1 :(得分: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 :(得分:1)

无需重新启动活动! (每个prepbgg的1月27日10回复他的1月17日10'答案')而不是回收位图并产生重新加载活动的开销,你可以通过放置如下所示的'android:configChanges'属性来避免加载应用程序,在应用程序的AndroidManifest.xml文件的'activity'元素中。这告诉系统应用程序将处理方向更改,并且不需要重新启动应用程序。

<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

答案 3 :(得分:1)

继续回复Viktor ......

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

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

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

然而,我发现Toaster从未出现或闪过如此简短以至于无法读取。我的解决方法是使用时间检查处理程序强制程序在显示Toast和调用doDrawing()之间休眠200毫秒。虽然这略微延迟了重绘的开始,但我觉得这是一个值得付出的代价,因为用户知道发生了什么。 reDrawBuffer()现在读取:

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

和Handler代码(嵌套在我的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);
    }
}`

答案 4 :(得分:0)

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

如果我错了,请纠正我!