运项目难点之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

相关文章

百度/小米/滴滴/京东,中台架构比较

小米中台建设实践 01 小米的三大中台建设:业务+数据+技术 业务中台--从业务说起 在中台建设中,需要规范化的服务接口、一致整合化的数据、容器化的技术组件以及弹性的基础设施。并结合业务情况,判定是否真的需要中台。 小米参考了业界优秀的案例包括移动中台、数据中台、业务中台、技术中台等,再结合其业务发展历程及业务现状,整理了中台架构的核心方法论,一是企业如何共享服务,二是如何为业务提供便利。

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

hdu1254(嵌套bfs,两次bfs)

/*第一次做这种题感觉很有压力,思路还是有点混乱,总是wa,改了好多次才ac的思路:把箱子的移动当做第一层bfs,队列节点要用到当前箱子坐标(x,y),走的次数step,当前人的weizhi(man_x,man_y),要判断人能否将箱子推到某点时要嵌套第二层bfs(人的移动);代码如下:

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

SpringBoot项目是如何启动

启动步骤 概念 运行main方法,初始化SpringApplication 从spring.factories读取listener ApplicationContentInitializer运行run方法读取环境变量,配置信息创建SpringApplication上下文预初始化上下文,将启动类作为配置类进行读取调用 refresh 加载 IOC容器,加载所有的自动配置类,创建容器在这个过程

Maven创建项目中的groupId, artifactId, 和 version的意思

文章目录 groupIdartifactIdversionname groupId 定义:groupId 是 Maven 项目坐标的第一个部分,它通常表示项目的组织或公司的域名反转写法。例如,如果你为公司 example.com 开发软件,groupId 可能是 com.example。作用:groupId 被用来组织和分组相关的 Maven artifacts,这样可以避免

2. 下载rknn-toolkit2项目

官网链接: https://github.com/airockchip/rknn-toolkit2 安装好git:[[1. Git的安装]] 下载项目: git clone https://github.com/airockchip/rknn-toolkit2.git 或者直接去github下载压缩文件,解压即可。