微信小程序-如何根据缩放屏幕大小自适应icon图标更改marker
微信小程序如何根据用户的缩放屏幕来改变marker图标icon的大小,实现icon自适应屏幕缩放的效果
如何实现自适应大小图标
最近选了个小课设,要求实现小程序找附近停车位的功能,如下图所示。
每个车位都是一个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 数组的width和height进行批量修改宽度和高度
修改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,
})
})
}
}
},
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)