Android:获取旋转的 OSM 地图以填充整个屏幕
我正在开发一个应用程序,该应用程序使用 OpenStreetMap (OSM) API 在由静态图块组成的离线地图上显示各种兴趣点。
我目前正在实现的功能之一是让地图根据手机(通过 GPS)确定的方位进行旋转。我不需要太多的努力就能实现实际的旋转,但由于我的代码旋转整个画布——也许是一种相当幼稚的方法——我现在屏幕上有空白的角落,没有加载新的图块来补偿这一事实旋转的图块不再填充这些像素。
经过一番谷歌搜索后,我发现了一些关于如何解决这个问题的建议,但到目前为止还没有运气。
先生之一。 Romain Guy 的帖子,他提到了以下内容:
我过去曾这样做过,它需要创建一个自定义 在dispatchDraw()方法中旋转Canvas的ViewGroup。你 还需要增加MapView的大小(以便它绘制足够的 旋转时的像素。)您还需要旋转触摸事件 调度触摸事件()。或者,如果您使用 Android 3.0,您可以简单地调用 theMapView.rotate()
采纳他关于地图旋转的建议,我已经按照建议实现了dispatchDraw()和dispatchTouchEvent(),但是我在他提到我需要增加MapView的大小的部分遇到了麻烦?
这是我在 XML 文件中执行的操作吗,就像 这个线程?
或者,我可以以某种方式重写处理地图旋转的子类RelativeLayout 类中的onMeasure() 函数吗?
非常欢迎建议和提示。
更新:
为了找到此问题的可接受的解决方案,我尝试更改画布的大小。我的想法是,如果画布尺寸大于实际屏幕尺寸,我也许能够将空白角完全移出屏幕。不幸的是,似乎没有实际的 canvas.size() 选项;我发现最好的是canvas.scale()。
使用 canvas.scale(),我能够将画布的水平和垂直尺寸的比例增加 2 倍。然而,这意味着图像被有效地放大,导致地图图块出现不可接受的像素化。
有谁知道画布的大小在哪里声明,以及更改画布的大小是否实际上可以解决我的问题?
I'm working on an application that uses the OpenStreetMap (OSM) API to display various points of interest on an offline map, composed of static tiles.
One of the features that I am currently implementing is having the map rotate in accordance with the bearing determined by the phone (via GPS). I was able to implement the actual rotation without too much effort, but since my code rotates the entire canvas -- perhaps a rather naive approach -- I now have blank corners on the screen where no new tiles are being loaded to compensate for the fact that the rotated tiles no longer fill these pixels.
After a bit of Googling, I found a few suggestions as to how I might be able to solve this issue, but so far no luck.
In one of Mr. Romain Guy's posts, he mentions the following:
I have done this in the past and it requires to create a custom
ViewGroup that rotates the Canvas in the dispatchDraw() method. You
also need to increase the size of the MapView (so that it draws enough
pixels when rotated.) You will also need to rotate the touch events in
dispatchTouchEvent(). Or if you use Android 3.0 you can simply call
theMapView.rotate()
Taking his advice on map rotation, I have implemented dispatchDraw() and dispatchTouchEvent() as suggested, but I'm having trouble with the part where he mentions that I need to increase the size of the MapView?
Is this something that I do in the XML file, like suggested in this thread?
Or, can I somehow override the onMeasure() function in my subclassed RelativeLayout class that handles my map rotation?
Suggestions and hints are most welcome.
UPDATE:
In an attempt to find an acceptable solution to this problem, I tried to change the size of the canvas. The thinking was that with a canvas size that is bigger than the actual screen size, I might be able to move the blank corners off the screen entirely. Unfortunately, there does not appear to be an actual canvas.size() option; the best I found was canvas.scale().
Using canvas.scale(), I was able to increase the scale of the canvas by a factor of 2 in both the horizontal as well as vertical dimensions. This means, however, that the image is effectively zoomed in, causing unacceptable pixelation to the map tiles.
Does anyone know where the size of the canvas gets declared, and if changing the size of the canvas might actually solve my problem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我最终遵循了罗曼·盖伊的建议(与我在问题中发布的建议相同)。也就是说,我通过扩展
RelativeLayout
创建了自己的自定义ViewGroup
,然后增加了mapView
的大小以覆盖整个屏幕。扩展RelativeLayout ViewGroup
是必要的,这样我就可以覆盖dispatchDraw(...)
、onMeasure(...)
以及作为dispatchTouchEvent(...)
函数来为我的应用程序启用所需的地图旋转功能。dispatchDraw(...)
函数本质上拦截对onDraw(...)
函数的调用,对该函数的输入执行一些特定操作,然后释放它待处理。在我们的例子中,我们需要在mapView
画布到达实际的onDraw(...)
函数之前旋转它。这就是为什么我们需要重写这个函数。具体来说,
dispatchDraw(...)
函数将画布对象作为输入,该对象(在本例中)表示 OSMmapView
对象(如下面的 XML 文件中所定义) )。如果要对画布应用旋转,我们需要找到地图的中心,平移(即移动)地图,使地图的中心位于坐标系的原点上,然后将地图旋转坐标系的原点,然后,最后,我们希望将这个修改后的画布分派到渲染管道中的下一个阶段。我的代码如下;请注意,
Manager
是我自己创建的单例,除非您自己编写,否则它不会存在于您的实现中!接下来,我们需要重写
dispatchTouchEvent(...)
,因为 OSMmapView
画布的任何旋转最终不仅会旋转地图的图形表示,还会旋转与该活动相关的所有其他内容(这是我的具体实现的副作用);也就是说,触摸事件坐标在旋转后仍然相对于mapView
画布,而不是相对于实际手机。例如,如果我们想象画布旋转 180 度,那么如果用户尝试将地图平移到左侧,它会移动到右侧的地图,因为一切都是颠倒的!在代码中,您可以按如下方式更正此问题:
最后,获取地图活动的相应 XML 使其正常工作的技巧是利用
FrameLayout
作为我的所有其他 GUI 元素的父级。布局。这使我能够使mapView
尺寸远大于 Nexus One 上显示屏的尺寸(480 x 800)。此解决方案还允许我在FrameLayout
中嵌套RelativeLayout
,同时在使用match_parent
和类似参数时仍然尊重设备的实际显示尺寸。我的 XML 布局的相关部分如下所示:
我想指出的是,该解决方案绝不是最好的解决方案,但它对于我的概念验证应用程序来说效果很好!
I ended up following Romain Guy's advice (the same advice that I posted in my question). That is, I created my own custom
ViewGroup
by extending theRelativeLayout
, and I then increased the size of mymapView
to provide coverage of the entire screen. Extending theRelativeLayout ViewGroup
was necessary so that I could override thedispatchDraw(...)
, theonMeasure(...)
, as well as thedispatchTouchEvent(...)
functions to enable the desired map rotation features for my application.The
dispatchDraw(...)
function essentially intercepts calls to theonDraw(...)
function, performs a few specific manipulations on the input to that function and then releases it to be processed. In our case, we'll want to rotate themapView
canvas before it makes its way to the actualonDraw(...)
function. This is why we'll need to override this function.Specifically, the
dispatchDraw(...)
function takes as input a canvas object, which (in this case) represents the OSMmapView
object (as defined in the XML file below). If a rotation is to be applied to the canvas, we'll want to locate the center of the map, translate (i.e. move) the map so that the center of the map sits on the origin of the coordinate system, rotated the map about the origin of the coordinate system, and then, finally, we'll want to dispatch this modified canvas to the next stage in the rendering pipeline.My code for this is below; note that
Manager
is my own singleton creation that won't exist in your implementation unless you write one yourself!Next we'll need to override
dispatchTouchEvent(...)
, because any rotation of the OSMmapView
canvas ends up rotating not only the graphical representation of the map, but also everything else related to that Activity (this occurs as a side effect of my specific implementation); that is, touch event coordinates remain relative to themapView
canvas after being rotated and not relative to the actual phone. For example, if we imagine the canvas being rotated by 180 degrees, then if the user attempts to pan the map to the left, it will instead move to the map to the right, since everything is upside-down!In code, you might correct for this problem as follows:
Finally, the trick to getting the corresponding XML for the map activity to work properly is to utilize a
FrameLayout
as the parent to all other GUI elements in my layout. This allowed me to make themapView
dimensions considerably larger than the dimensions of the display on my Nexus One (480 by 800). This solution also allowed me to nest aRelativeLayout
inside myFrameLayout
while still respecting the device's actual display dimensions when usingmatch_parent
and similar parameters.The relevant portion of my XML layout looks like this:
I'd like to remark that this solution is by no means the best solution, but that it worked out fine for my proof-of-concept application!