我是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的等价物吗?
答案 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不会绘制到位图中,而是将位图绘制到画布上。
如果我错了,请纠正我!