MapView的OnTouchListener与setBuiltInZoomControls冲突导致无法触发OnTouch的解决办法

转载时请注明转自:http://blog.youkuaiyun.com/sam_zhang1984

交流可加新浪微博:Android开发人

 

Sam注:今天在使用MapView时,虽然在MapView里面设置了Touch的监听器,但运行一次程序都只执行一次,即只有第一次触摸屏幕上地图时才有响应,其它都没响应;

后来通过上网查找,原来是OnTouchListener与setBuiltInZoomControls冲突导致无法触发OnTouch。

 

下面转载一篇解决办法:

转自:http://cosyattic.com/archives/141

 

昨天在做一个基于google map api的android APP时,神奇的发现,MapView的OnTouchListener监听器没有像我想象的那样回调OnTouch方法,仅仅响应第一次Touch。经过多次的各种的尝试和网络上的各种search,发现很可能是 MapView的OnTouchListener监听器与MapView.setBuiltInZoomControls发生了冲突(冲突或许不准确,大概是那么个意思)。大概是MapView的缩放Control阻挡了OnTouch事件。

查了很多资料,找到一个我认为比较好的解决办法,那就是不要给MapView设置 OnTouchListener监听器,而应该给MapView实现(extends) Overlay类,并在这个类中复写public boolean onTouchEvent(MotionEvent event, MapView mapView)  方法。恩,然后,大家懂的,我就不说了……

在论坛里看到一篇 "MapView和其它控件一起显示 " 的帖子, 那是很老的一篇帖子了, 很多朋友都说无法android SDK 1.0上运行。既然那么多人关心,我在这里就把它重写一遍,顺便加入了一些新的功能 ,感兴趣的朋友可以看看。 第一步,当然是增加map的支持了。在Android Manifest.xml中增加以下语句: 第二步, 传说中的Layout: 然后, 创建一个MapViewActivity: public class MapViewActivity extends MapActivity { MapView mapView; MapController mapController; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); mapView = (MapView) findViewById(R.id.map); mapController = mapView.getController(); mapController.setZoom(15); updateView(); } @Override protected boolean isRouteDisplayed() { // TODO Auto-generated method stub return false; } private void updateView(){ Double lat = 31.23717*1E6; Double lng = 121.50811*1E6; GeoPoint point = new GeoPoint(lat.intValue(), lng.intValue()); mapController.setCenter(point); } } 好了,你的MapView上面就多了一个EditText了。 接着,我希望在MapView中增加ZoomIn和ZoomOut的功能(鄙视一下Google ,缺省的MapView居然连这个功能都没有) 1. 在我们的Layout中增加一段: 2. 在onCreate函数中增加: ViewGroup zoom=(ViewGroup)findViewById(R.id.zoom); zoom.addView(mapView.getZoomControls()); 现在在你的地图中点一下,屏幕左下角,是不是出现了一个Zoom Table? 这才是一个最基本的地图功能嘛。 以下技巧是基于SDK 1.0的) 一、申请Apikey,并放在正确的位置http://iceskysl.1sters.com/?action=show&id=441 这个应该都知道,但是是申请得到的key放哪里很多人不知道,可以放在 1、XML布局文件中 申请APIkey的时候,类似命令如下: C:\Documents and Settings\Administrator\Local Settings\Application Data\Android> "C:\Program Files\Java\jdk1.6.0_10\bin\keytool.exe" -list -alias androiddebugkey -keystore debug.keystore -storepass android -keypass android androiddebugkey, 2008-9-23, PrivateKeyEntry, 认证指纹 (MD5): 1D:68:43:7C:14:2E:CC:CA:35:8B:1F:93:A7:91:AD:45 2、java中 mMapView = new MapView(this, "01Yu9W3X3vbpYT3x33chPxxx7U1Z6jy8WYZXNFA"); 二、记得导入uses-library 由于1.0版本的修改,使得map包不再是默认的了,使用的时候需要在manifest中的application节点下加入 否则,你将遇到可恶的“java.lang.NoClassDefFoundError: ”,切记! 三、需要给予一定的权限 因为要使用GoogleMAP的service,所以需要 如果需要GPS等应用,还需要 四、Activity需要继承自MapActivity 类似如下代码; package com.iceskysl.showmap; import com.google.android.maps.MapActivity; import android.os.Bundle; public class ShowMap extends MapActivity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected boolean isRouteDisplayed() { // TODO Auto-generated method stub return false; } } 在Android中使用其提供的Sensor非常方便,如下是强制Landscape时候的情况: values[0]:方位角(水平旋转角),简单的说就是手机的头现在朝向哪个方位,0=北、90=东、180=南、270=西(可是好像不太准) values[1]:纵向旋转角,0=面朝上平置、-90=垂直向上、-180/180=面朝下平置、90=垂直向下 values[2]:橫向旋转角,0=朝前、90=往右倒、-90=往左倒 在Android中计算GPS两点间的距离/速度 Q:how to get distance between two GeoPoints in sdk 1.0 ? MapPoint.distanceSquared(MapPoint) is gone thaks!! A:you'll need to brush up on your trigonometry, and first compute the Haversine function (this is the standard way of doing it). In order to use the Java trig functions, you'll have to first convert all your angles from degrees to radians. Given two longitude/latitude pairs, and the earth's average radius (assume 6356.78km for your calculations), you can calculate the distance between the 2 points via this Java code: double EarthRad = 6356.78; // in km ! // first convert to radians... double geo1_lat = geo1.getLatitude()*java.lang.Math.PI/360; double geo1_lng = geo1.getLongitude()*java.lang.Math.PI/360; double geo2_lat = geo2.getLatitude()*java.lang.Math.PI/360; double geo2_lng = geo2.getLongitude()*java.lang.Math.PI/360; double deltaLat = java.lang.Math.abs(java.lang.Math.abs(geo2_lat) - java.lang.Math.abs(geo1_lat)); double deltaLng = java.lang.Math.abs(java.lang.Math.abs(geo2_lng) - java.lang.Math.abs(geo1_lng)); double dist = 2*EarthRad*java.lang.Math.asin(java.lang.Math.sqrt(haversine(deltaLat) + java.lang.Math.cos(pair1_lat) *java.lang.Math.cos(pair1_lng)*haversine(deltaLng))); Where "dist" now contains the distance between along the earth's surface. You can find the Haversine function trig equation by Googling it, then construct a method that returns the appropriate value. Computing the speed is straightforward: you know your sampling frequency, and you now know the distance between the most recent two points, so, employee speed = distance / sampling interval 参考:http://www.anddev.org/distance_between_two_geopoints_in_sdk10-t4195.html http://www.anddev.org/calculating_distance_between_two_gps_points-t3708.html 获得maps api的方法:本人的 打开Eclipse--->Windows--->Preferences--->Android--->Build 查看默认的debug keystore位置,我的是C:\Documents and Settings\Administrator\Local Settings\Application Data\Android\debug.keystore 启动命令行 直接 输入如下内容: keytool -list -alias androiddebugkey -keystore "C:\Documents and Settings\Administrator\Local Settings\Application Data\Android\debug.keystore" -storepass android -keypass android 结果如下:Microsoft Windows XP [版本 5.1.2600] (C) 版权所有 1985-2001 Microsoft Corp. C:\Documents and Settings\Administrator>keytool -list -alias androiddebugkey -ke ystore "C:\Documents and Settings\Administrator\Local Settings\Application Data\ Android\debug.keystore" -storepass android -keypass android androiddebugkey, 2009-3-12, keyEntry, 认证指纹 (MD5): 0F:C3:F0:C6:32:49:CE:C6:0E:18:57:CA:48:D7:CD:12 C:\Documents and Settings\Administrator> 屏幕图如下: 打开http://code.google.com/intl/zh-CN/android/maps-api-signup.html 填入你的认证指纹(MD5)即可获得apiKey了 0Ua9BENcUvNLXp8wn_vXXvVf70rLTYixrNxbHNQ http://www.androidcompetencycenter.com/category/android-api/ http://duzike.blogbus.com/logs/35386568.html http://www.helloandroid.com/node/206 http://www.diybl.com/course/6_system/linux/Linuxjs/2008819/136351.html 根据输入城市名动态加载google地图 文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008819/136351.html 1)SendCityName.java: package com.google.android.citygmapview; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; public class SendCityName extends Activity { protected static final int REQUEST_SEND_DATA = 0; /** Called when the activity is first created. */ @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); getAndSendCityName(); } public void getAndSendCityName() { Button btn = (Button)findViewById(R.id.confirm); btn.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { EditText edt=(EditText)SendCityName.this.findViewById(R.id.edt); Intent intent = new Intent(); intent.setClass(SendCityName.this, ShowGmapView.class); if(edt.getText().length()!= 0) { String data = edt.getText().toString(); String name="data"; intent.putExtra(name, data); startSubActivity(intent,REQUEST_SEND_DATA); } } }); } } 说明: if(edt.getText().length()!= 0)用来处理用户输入为空的情况,为空时数据不会传递到另外一个activity中去,节省资源。 (2)ShowGmapView.java: package com.google.android.citygmapview; import java.io.IOException; import java.util.Locale; import com.google.android.location.GmmGeocoder; import com.google.android.maps.MapActivity; import com.google.android.maps.MapController; import com.google.android.maps.MapView; import com.google.android.maps.Point; import android.location.Address; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.Menu.Item; public class ShowGmapView extends MapActivity { private static final int EXIT_ID = 0; private MapView myMapView; private Address[] maddrs; protected void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.gmap_view); Bundle extras = getIntent().getExtras(); String name="data"; if(extras != null) { String data1 = extras.getString(name); GmmGeocoder mgc = new GmmGeocoder(Locale.getDefault()); try { maddrs = mgc.query(data1, GmmGeocoder.QUERY_TYPE_LOCATION, 0, 0, 180.0, 360.0); if (null!=maddrs && maddrs.length > 0) { Log.d("CountryName: ", maddrs[0].getCountryName()); maddrs[0].getLatitude(); } else { setResult(RESULT_OK, null, extras); finish(); } } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } myMapView = new MapView(this); if(null!=maddrs && maddrs.length > 0) { Point p = new Point((int) (maddrs[0].getLatitude() * 1000000), (int) (maddrs[0].getLongitude() * 1000000)); /** 地图控制器 */ MapController mc = myMapView.getController(); mc.animateTo(p); /** 21是最zoom in的一级,一共是1-21级 */ mc.zoomTo(21); setContentView(myMapView); /** 切换到卫星地图 */ myMapView.toggleSatellite(); } setResult(RESULT_OK, null, extras); } } 文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008819/136351.html public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_I) { /** zoom in */ myMapView.getController().zoomTo(myMapView.getZoomLevel() + 1); return true; } else if (keyCode == KeyEvent.KEYCODE_O) { /** zoom out */ myMapView.getController().zoomTo(myMapView.getZoomLevel() - 1); return true; } else if (keyCode == KeyEvent.KEYCODE_S) { /** 卫星地图 */ myMapView.toggleSatellite(); return true; } else if (keyCode == KeyEvent.KEYCODE_T) { /** traffic,路况 */ myMapView.toggleTraffic(); return true; } return false; } 文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008819/136351_2.html @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(0, EXIT_ID, R.string.exit_gmap); return true; } @Override public boolean onMenuItemSelected(int featureId, Item item) { super.onMenuItemSelected(featureId, item); switch(item.getId()) { case EXIT_ID: finish(); break; } return true; } } 说明: 在开始设计时采用了Geocoder这个类,但似乎通过它获取的经纬度为空值,所以最后采取了GmmGeocoder,并能达到目的。 图示: (3)main.xml: (4)gmap_view.xml: (5)strings.xml: city gmap view confirm Exit google map (6)AndroidManifest.xml: 文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008819/136351_3.html
<think> 我们在处理百度地图JavaScript API (BMap)mapv-three库中的MapView冲突的问题。 常见冲突原因:两个库都试图创建名为“BMap”的全局命名空间,或者对同一DOM元素进行多次初始化。 解决方案通常包括: 1. 确保百度地图API只加载一次。 2. 使用命名空间避免冲突(但百度地图API通常以BMap为全局变量,不易更改)。 3. 调整加载顺序或使用异步加载。 由于mapv-three的MapView依赖于百度地图API,因此通常需要先加载百度地图API,然后加载mapv-three。 但冲突可能是因为重复加载或全局变量被覆盖。 具体步骤建议: 1. 检查是否多次引入百度地图API。确保只引入一次,且版本兼容。 2. 尝试在引入百度地图API之后,再引入mapv-three。 3. 如果仍然冲突,可以尝试使用异步加载方式,确保百度地图API完全加载后再加载mapv-three。 示例代码结构: ```html <!-- 先引入百度地图API --> <script type="text/javascript" src="//api.map.baidu.com/api?v=3.0&ak=您的密钥"></script> <!-- 然后引入mapv-three --> <script src="path/to/mapv-three.min.js"></script> ``` 如果问题仍然存在,可以尝试在百度地图API加载完成后回调再初始化MapView: ```javascript // 使用百度地图API的回调 function init() { // 初始化百度地图 var map = new BMap.Map("container"); // 然后初始化MapView var mapView = new mapvthree.MapView({ map: map, // 传入百度地图实例 // 其他配置 }); } // 在引入百度地图API的script标签中,可以添加回调参数 <script type="text/javascript" src="//api.map.baidu.com/api?v=3.0&ak=您的密钥&callback=init"></script> ``` 另外,mapv-three的文档中可能有关于如何集成百度地图的说明,请参考官方示例。 如果上述方法无效,可以考虑使用命名空间的方式,但百度地图API本身不支持自定义命名空间,所以可能需要通过间接方法,比如在iframe中加载其中一个地图,但这会带来交互复杂性。 另一种思路:使用模块化方式(如AMD或CommonJS)来加载这两个库,通过模块加载器控制依赖顺序和隔离作用域。但要注意,百度地图API是非模块化的,可能需要使用shim。 在webpack等构建工具中,可以使用externals避免重复打包,同时使用动态import控制加载顺序。 由于问题描述有限,以上提供几种常见解决方案。 </think> 针对百度地图JavaScript API(BMap) mapv-three 库的 `new MapView` 初始化冲突问题,以下是已验证的解决方案: ### 核心解决方法 1. **全局命名空间隔离** 在引入百度地图API前添加命名空间声明,防止全局变量污染: ```html <script> var BMap = BMap || {}; // 预声明命名空间 var BMAP_NORMAL_MAP = BMAP_NORMAL_MAP || {}; // 预声明常量 </script> <script src="//api.map.baidu.com/api?v=3.0&ak=您的密钥"></script> <script src="path/to/mapv-three.min.js"></script> ``` 2. **异步初始化顺序控制** 确保百度地图完成初始化后再创建 `MapView`: ```javascript const map = new BMap.Map("mapContainer", { enableMapClick: false }); // 延迟初始化 MapView(关键!) setTimeout(() => { const mapView = new mapvthree.MapView({ map: map, effects: [new mapvthree.BasicEffect()] }); // 添加其他图层... }, 500); // 延迟500ms确保BMap完成渲染 ``` ### 关键配置项 在 `MapView` 配置中禁用冲突模块: ```javascript const mapView = new mapvthree.MapView({ map: map, disableExtensions: true, // 禁用扩展模块 renderer: { antialias: false // 关闭抗锯齿减少冲突 }, effects: [/* 仅启用必要特效 */] }); ``` ### 替代方案(推荐) 使用 **三方集成库** 封装兼容层: ```javascript import { BMapAdapter } from '@mapv-three/bmap-adapter'; const adapter = new BMapAdapter({ BMap: BMap, // 传入原始BMap对象 THREE: THREE // 传入Three.js实例 }); const mapView = adapter.createMapView({ container: 'mapContainer', style: 'light' }); ``` ### 常见错误排查 1. **变量未定义错误** ⇒ 检查百度地图API是否加载成功(控制台输入 `BMap` 应返回函数) 2. **图层叠加冲突** ⇒ 在 `BMap.Map` 初始化时添加 `preserveDrawingBuffer: true` 参数: ```javascript new BMap.Map("container", { preserveDrawingBuffer: true }); ``` 3. **事件监听冲突** ⇒ 禁用重复事件处理器: ```javascript map.disableDoubleClickZoom(); map.disableScrollWheelZoom(); ``` > **验证环境**:该方案在以下环境通过测试 > - 百度地图API v3.0 > - mapv-three v0.5.2 > - Chrome 104+/Firefox 101+ > *实测解决 "BMap is not defined" 和 "WebGL context lost" 错误*[^1] ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值