运项目难点之ScrollView中嵌套百度地图(BaiduMap)的解决方案

本文主要是介绍运项目难点之ScrollView中嵌套百度地图(BaiduMap)的解决方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

由于产品的需求,有时候不得不在ScrollView中嵌套百度地图(BaiduMap)。但是,嵌套之后会存在一些问题,两个比较突出的问题是:1)ScrollView中事件处理与BaiduMap存在冲突。2)在BaiduMap随着ScrollView拖动的时候,存在黑影问题。很多人遇到过这两个问题,也比较棘手,所以希望百度能给出官方的解决方案。下面说说我的处理办法。

1)ScrollView中事件处理与BaiduMap存在冲突

想要了解产生事件冲突的原因,就必须明白安卓的事件传递与处理机制。http://blog.csdn.net/theone10211024/article/details/43270455 这片文章是我见过讲的最好的。还不明白的同学不妨移步这里。这里我只简单说一下传递流程:

Events->Activity.dispatchTouchEvent()->(顶层)ViewGroup.dispatchTouchEvent()->(顶层)ViewGroup.onInterceptTouchEvent()->childView1.dispatchTouchEvent()->childView1.OnTouchListener.OnTouch(如果定义了)->childView1.onTouchEvent()->childView2.....->childView n.....->(顶层)ViewGroup.onTouchListener.onTouch()(如果定义了)->(顶层)ViewGroup.onTouchEvent()->Activity.onTouchEvent();

中间任何一步如果事件被消费了,就会停止传递。

下面,我们来看看ScrollView的源代码

[html]  view plain copy
  1. @Override  
  2.   public boolean onInterceptTouchEvent(MotionEvent ev) {  
  3.       /*  
  4.        * This method JUST determines whether we want to intercept the motion.  
  5.        * If we return true, onMotionEvent will be called and we do the actual  
  6.        * scrolling there.  
  7.        */  
  8.   
  9.       /*  
  10.       * Shortcut the most recurring case: the user is in the dragging  
  11.       * state and he is moving his finger.  We want to intercept this  
  12.       * motion.  
  13.       */  
  14.       final int action = ev.getAction();  
  15.       if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {  
  16.           return true;  
  17.       }  
  18.   
  19.       switch (action & MotionEvent.ACTION_MASK) {  
  20.           case MotionEvent.ACTION_MOVE: {  
  21.               /*  
  22.                * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check  
  23.                * whether the user has moved far enough from his original down touch.  
  24.                */  
  25.   
  26.               /*  
  27.               * Locally do absolute value. mLastMotionY is set to the y value  
  28.               * of the down event.  
  29.               */  
  30.               final int activePointerId = mActivePointerId;  
  31.               if (activePointerId == INVALID_POINTER) {  
  32.                   // If we don't have a valid id, the touch down wasn't on content.  
  33.                   break;  
  34.               }  
  35.   
  36.               final int pointerIndex = ev.findPointerIndex(activePointerId);  
  37.               final float y = ev.getY(pointerIndex);  
  38.               final int yDiff = (int) Math.abs(y - mLastMotionY);  
  39.               if (yDiff > mTouchSlop) {  
  40.                   mIsBeingDragged = true;  
  41.                   mLastMotionY = y;  
  42.                   initVelocityTrackerIfNotExists();  
  43.                   mVelocityTracker.addMovement(ev);  
  44.                   if (mScrollStrictSpan == null) {  
  45.                       mScrollStrictSpan = StrictMode.enterCriticalSpan("ScrollView-scroll");  
  46.                   }  
  47.               }  
  48.               break;  
  49.           }  
  50.   
  51.           case MotionEvent.ACTION_DOWN: {  
  52.               final float y = ev.getY();  
  53.               if (!inChild((int) ev.getX(), (int) y)) {  
  54.                   mIsBeingDragged = false;  
  55.                   recycleVelocityTracker();  
  56.                   break;  
  57.               }  
  58.   
  59.               /*  
  60.                * Remember location of down touch.  
  61.                * ACTION_DOWN always refers to pointer index 0.  
  62.                */  
  63.               mLastMotionY = y;  
  64.               mActivePointerId = ev.getPointerId(0);  
  65.   
  66.               initOrResetVelocityTracker();  
  67.               mVelocityTracker.addMovement(ev);  
  68.               /*  
  69.               * If being flinged and user touches the screen, initiate drag;  
  70.               * otherwise don't.  mScroller.isFinished should be false when  
  71.               * being flinged.  
  72.               */  
  73.               mIsBeingDragged = !mScroller.isFinished();  
  74.               if (mIsBeingDragged && mScrollStrictSpan == null) {  
  75.                   mScrollStrictSpan = StrictMode.enterCriticalSpan("ScrollView-scroll");  
  76.               }  
  77.               break;  
  78.           }  
  79.   
  80.           case MotionEvent.ACTION_CANCEL:  
  81.           case MotionEvent.ACTION_UP:  
  82.               /* Release the drag */  
  83.               mIsBeingDragged = false;  
  84.               mActivePointerId = INVALID_POINTER;  
  85.               recycleVelocityTracker();  
  86.               if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {  
  87.                   invalidate();  
  88.               }  
  89.               break;  
  90.           case MotionEvent.ACTION_POINTER_UP:  
  91.               onSecondaryPointerUp(ev);  
  92.               break;  
  93.       }  
  94.   
  95.       /*  
  96.       * The only time we want to intercept motion events is if we are in the  
  97.       * drag mode.  
  98.       */  
  99.       return mIsBeingDragged;  
  100.   }  

从该函数中可以看出,当处于拖动中(BeingDragged)的时候,ScrollView.onInterceptTouchEvent()返回true。事件就被父View即ScrollView消费了。ScrollView中的BaiduMap(实际上是其中的MapView)就不会再接收到该事件了。所以,解决该问题的核心思路就是:当ScrollView处于拖动事件中,且拖动区域在BaiduMap中的时候,让事件不要被父View消费,而是交给BaiduMap处理。

解决方案:

1)重写ScrollView.onInterceptTouchEvent()函数。当发现手指在BaiduMap中时,返回false(即未被消费)其他时候交由super.onInterceptTouchEvent()处理。我没有采用这类解决方案,原因之一是不好控制手指是否在BaiduMap中,大家可以试一试

2)我们发现android给view提供了一个函数requestDisallowInterceptTouchEvent().它的定义是这样的

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Called when a child does not want this parent and its ancestors to intercept touch events with ViewGroup.onInterceptTouchEvent(MotionEvent).   
  2.   
  3. This parent should pass this call onto its parents. This parent must obey this request for the duration of the touch (that is, only clear the flag after this parent has received an up or a cancel.  
意思是当child View不想它的父view消费事件,而是传递给自己的时候,可以调用该函数说“你不要把事件消费了,传给我再处理吧”。然后,我就按照http://blog.csdn.net/catoop/article/details/14233419这个博客写的做了,具体代码如下

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //       重写onTouch()事件,在事件里通过requestDisallowInterceptTouchEvent(boolean)方法来设置父类的不可用,true表示父类的不可用  
  2.         //解决地图的touch事件和scrollView的touch事件冲突问题  
  3.         mMapView.setOnTouchListener(new View.OnTouchListener() {  
  4.               
  5.             @Override  
  6.             public boolean onTouch(View v, MotionEvent event) {  
  7.                 if(event.getAction() == MotionEvent.ACTION_UP){  
  8.                     scrollView.requestDisallowInterceptTouchEvent(false);  
  9.                 }else{  
  10.                     scrollView.requestDisallowInterceptTouchEvent(true);  
  11.                 }  
  12.                 return false;  
  13.             }  
  14.         });  

但是,当我打了断点调试的时候才发现,触发事件的时候根本没有走到MapView的onTouch()中,换句话说就是MapView.OnTouchListener.onTouch()根本没有被调用。如果你熟悉事件的传递顺序,这时候你就会猜到,MapView是继承至ViewGroup,事件一定是被MapView中的某个childView消费了才不会传递给MapView。最后我找出了消费该事件的view。最后代码改进成了这样

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. 重写onTouch()事件,在事件里通过requestDisallowInterceptTouchEvent(boolean)方法来设置父类的不可用,true表示父类的不可用  
  2.     //解决地图的touch事件和scrollView的touch事件冲突问题  
[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. View v = mMapView.getChildAt(0);//这个view实际上就是我们看见的绘制在表面的地图图层  
[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. v.setOnTouchListener(new View.OnTouchListener() {  
  2.       
  3.     @Override  
  4.     public boolean onTouch(View v, MotionEvent event) {  
  5.         if(event.getAction() == MotionEvent.ACTION_UP){  
  6.             scrollView.requestDisallowInterceptTouchEvent(false);  
  7.         }else{  
  8.             scrollView.requestDisallowInterceptTouchEvent(true);  
  9.         }  
  10.         return false;  
  11.     }  
  12. });  
改进之后,顺利达到效果。

其实,当你一头雾水的时候,发现问题并解决是比较难的。当时我就反编译了百度的jar包,在半写半蒙中才找到了正确答案。

2)在BaiduMap随着ScrollView拖动的时候,存在黑影问题

据我分析,由于百度地图是用openGl绘制的,黑影可能是在拖动过程中不断重绘才导致的。其实,百度工程师是不建议在ScrollView中使用百度地图,除非你逼不得已。

这个如果非得用动态的百度map,那解决可能还得等百度工程师的佳音了 


原文地址:http://blog.csdn.net/theone10211024/article/details/44649289

这篇关于运项目难点之ScrollView中嵌套百度地图(BaiduMap)的解决方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1130166

相关文章

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志

《SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志》在SpringBoot项目中,使用logback-spring.xml配置屏蔽特定路径的日志有两种常用方式,文中的... 目录方案一:基础配置(直接关闭目标路径日志)方案二:结合 Spring Profile 按环境屏蔽关

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

Java死锁问题解决方案及示例详解

《Java死锁问题解决方案及示例详解》死锁是指两个或多个线程因争夺资源而相互等待,导致所有线程都无法继续执行的一种状态,本文给大家详细介绍了Java死锁问题解决方案详解及实践样例,需要的朋友可以参考下... 目录1、简述死锁的四个必要条件:2、死锁示例代码3、如何检测死锁?3.1 使用 jstack3.2

html 滚动条滚动过快会留下边框线的解决方案

《html滚动条滚动过快会留下边框线的解决方案》:本文主要介绍了html滚动条滚动过快会留下边框线的解决方案,解决方法很简单,详细内容请阅读本文,希望能对你有所帮助... 滚动条滚动过快时,会留下边框线但其实大部分时候是这样的,没有多出边框线的滚动条滚动过快时留下边框线的问题通常与滚动条样式和滚动行

Oracle修改端口号之后无法启动的解决方案

《Oracle修改端口号之后无法启动的解决方案》Oracle数据库更改端口后出现监听器无法启动的问题确实较为常见,但并非必然发生,这一问题通常源于​​配置错误或环境冲突​​,而非端口修改本身,以下是系... 目录一、问题根源分析​​​二、保姆级解决方案​​​​步骤1:修正监听器配置文件 (listener.

MySQL版本问题导致项目无法启动问题的解决方案

《MySQL版本问题导致项目无法启动问题的解决方案》本文记录了一次因MySQL版本不一致导致项目启动失败的经历,详细解析了连接错误的原因,并提供了两种解决方案:调整连接字符串禁用SSL或统一MySQL... 目录本地项目启动报错报错原因:解决方案第一个:第二种:容器启动mysql的坑两种修改时区的方法:本地

安装centos8设置基础软件仓库时出错的解决方案

《安装centos8设置基础软件仓库时出错的解决方案》:本文主要介绍安装centos8设置基础软件仓库时出错的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录安装Centos8设置基础软件仓库时出错版本 8版本 8.2.200android4版本 javas

springboot项目中使用JOSN解析库的方法

《springboot项目中使用JOSN解析库的方法》JSON,全程是JavaScriptObjectNotation,是一种轻量级的数据交换格式,本文给大家介绍springboot项目中使用JOSN... 目录一、jsON解析简介二、Spring Boot项目中使用JSON解析1、pom.XML文件引入依