微信小程序-如何根据缩放屏幕大小自适应icon图标更改marker


如何实现自适应大小图标

最近选了个小课设,要求实现小程序找附近停车位的功能,如下图所示。
在这里插入图片描述
每个车位都是一个marker,红色marker代表该车位已被占用,绿色marker代表还没被占用。

但是这样的图标有个问题,那就是宽度和高度都是固定死的,当地图缩放到一定程度,图标会堆积在一起,很影响观感:
在这里插入图片描述
故我开始在网上找自适应icon的方法,但没怎么找到教程,遂打算根据自己的思路写篇教程,希望对后来者有所帮助。(代码放在教程末尾)


提示:以下是本篇文章正文内容,下面案例可供参考

1、自适应图标icon/marker的原理是什么?

我最初的思路是:用户每次缩放地图的时候,都会触发后台一个函数scaleChange(),该函数能调用微信小程序提供的API(MapContext.getScale())来获取当前地图的缩放程度scale。

在这里插入图片描述
(虽然我后面发现不需要用到 MapContext.getScale() 就可以直接获取到scale )

我们拿到这个scale后,根据scale数值大小,对marker里icon图标的width和height数值进行修改,从而达到“自适应”的效果。比如scale数值变小(即缩小地图),那么图标的高度和宽度就要跟着变小。那么具体是怎么实现的呢?

2、实现过程

2.1、如何监听用户是否有缩放页面

首先,微信小程序的map组件,即地图在进行缩放的时候,会触发一个事件:
在这里插入图片描述
该事件使用方法如下:
我们首先要在wxml里的map组件里加上属性 bindregionchange,并且绑定后台的 scaleChange() 函数,这样当用户对地图进行拖拽或缩放时,就会触发==scaleChange()==函数。

//.wxml页面
<map id="map" style="width:100vw; height:100vh"  
			  bindregionchange="scaleChange">
</map>

然后我们在js页面添加以下函数:

//.js页面添加函数
scaleChange(e) {
    
    
	console.log(e)
}

接着我们用鼠标拖动缩放地图,移动视野,就可以看到控制台输出两行信息:
在这里插入图片描述
(电脑端的微信小程序有些问题,缩放可能没法第一时间显示信息,还需要移动一下视野才能显示end信息)

begin代表视野变化前,即用户拖拽或缩放屏幕前的时候
end代表视野变化后,即用户拖拽或缩放屏幕后的时候

在本篇教程中,我们只需要用到end信息。

故我们将代码修改为:

scaleChange(e) {
    
    
	if (e.type == 'end') {
    
        // 这个事件的type有'begin'和'end'2种类型,,我们滑动一下地图,会有2次响应。但我们只关注'end'!!!
        console.log(e)
	}
}

即可看到end的具体信息
在这里插入图片描述
causedBy表示用户执行的行为,比如移动地图为“drag”,如果是缩放地图则为“scale”。这里我是移动地图后产生的信息,故显示为drag
detail.scale是我们需要用到的数据,因为这代表的就是当前的地图缩放程度scale。

至此,我们已经做到了如何实时监听用户是否缩放屏幕,以及获取地图的缩放程度scale数值。

2.2、如何根据scale来修改图标的宽和高

有了缩放程度scale的数值后,如何根据该数值自适应修改icon的宽度和高度呢?

以下是实现代码,我们对代码拆分讲解:

//scaleChange() 总代码
scaleChange(e) {
    
    
	var that = this//后面用到的this是在闭包里的,而不是指当前页面,故要先保存为that,方便下面使用
	if (e.type == 'end') {
    
    
        console.log(e)
		if(e.causedBy == "scale")	//如果用户执行的是缩放操作
        {
    
    //或者用e.detail.scale != this.data.scale也可以
          let newwidth = parseInt(3.33*e.detail.scale - 36.6)	
          let newheight = newwidth		//建立映射关系,得到新的宽度和高度
          
          //遍历markers数组,批量修改数组里的宽度和高度
          this.data.markers.forEach(function(item, index) {
    
    
            that.setData({
    
    
              [`markers[${
      
      index}].width`]: newwidth,
              [`markers[${
      
      index}].height`]: newheight,
            })
         })
        }
	}
}

我的代码思路是:先利用if条件判定当前用户是否执行“scale“缩放操作

if(e.causedBy == "scale") 或者 if(e.detail.scale != this.data.scale)

注意:我在电脑端用if(e.causedBy == “scale”)的时候遇到了个小问题,哪怕用户缩放了屏幕也无法进入if条件,所以我最后用的是if(e.detail.scale != this.data.scale),即每当当前的scale值与data存储的scale值不一样时,就判断用户进行了缩放地图操作。

当用户执行了缩放操作后,我们就对以下 markers 数组的widthheight进行批量修改宽度和高度
在这里插入图片描述
修改markers数组的高度和宽度很简单,直接用forEach函数进行遍历修改就好了。
注:这里不可以用this.setData,因为这里面的this非页面的this,所以需要先用变量保存为that。

		  var that = this
          this.data.markers.forEach(function(item, index) {
    
    
            that.setData({
    
    
              [`markers[${
      
      index}].width`]: newwidth,
              [`markers[${
      
      index}].height`]: newheight,
            })
         })

但是到了这一步我们还不知道修改成什么数值(新的宽度newwidth和新的高度newheight)观感好,故下一步就是要建立映射关系。

因为地图缩放越小,图标则要越小,可以将scale和width当作线性关系。故我们建立一个映射关系:y=kx+b
其中,y为宽度或高度,x为scale数值。

我经过实际测量,发现当缩放程度scale =20时,图片的width=height=30较合适,当缩放程度为scale = 17时,图片的width = height = 20较合适。

其实就相当于给你两个点(x=20,y=30),(x=17,y=20) ,求解方程。
得到y=3.33b-36.6

let newwidth = parseInt(3.33*this.data.scale - 36.6)
let newheight = newwidth

这里要用parseInt将结果强制转换为整数的原因是:width和height只能接受整数类型,不接受浮点数类型,故要进行强制转换。

到了这里,我们的映射关系就算是建立起来了,当scale越小,我们的width和height也会跟着变小。这样就达到了自适应的效果。

当然到了这一步还没有结束,我们观察这个式子 y=3.33b-36.6 可以发现,当b=10.99即scale=10.99的时候,y=0。而我们知道icon图标的宽度和高度是不可以为负数或零的,所以我们要在map组件里再添加一个缩放限制属性min-scale,来防止缩放到一定程度,宽度高度变为负数:

<map id="map" style="width:100vw; height:100vh"
			min-scale="10.99" 
			bindregionchange="scaleChange">
</map>

当然你也可以根据你的机型和实际情况作自己的调整,这一部分计算不需要十分精确。

至此,我们就实现了自适应icon图标的方法
在这里插入图片描述

3、完整源码

//.wxml页面
<map id="map" style="width:100vw; height:100vh"  
markers="{
    
    {markers}}" latitude="{
    
    {latitude}}" 
longitude="{
    
    {longitude}}" scale="{
    
    {scale}}" min-scale="10.5" 
show-location="true" bindmarkertap="handleMarkerTap" bindregionchange="scaleChange">
</map>

//.js页面
  scaleChange(e) {
    
    
    var that = this
    if (e.type == 'end') {
    
    
        console.log(e)
        if(e.detail.scale != this.data.scale)
        {
    
    
          let newwidth = parseInt(3.33*this.data.scale - 36.6)
          let newheight = newwidth
          this.data.markers.forEach(function(item, index) {
    
    
            that.setData({
    
    
              [`markers[${
      
      index}].width`]: newwidth,
              [`markers[${
      
      index}].height`]: newheight,
            })
         })
        }
    }
  },

猜你喜欢

转载自blog.csdn.net/Bartender_VA11/article/details/128050968
今日推荐