今天,我爱模板网用mui做app时,遇到了可能各位都遇到过的头疼问题:底部中间图标凸起,如下图:
其实官方已经给出详细解决方案: tab选项卡示例教程-基于subnview模式的原生tab(含底部凸起大图标)
但是官方的案例首页是写死的,并且图标是字体图标,不是图片,还有其他一些效果都和我们平时的需求不同,所以,我爱模板网对其进行了改良,下面是相关代码,具体就不解释了:
1、mainifest.json代码修改如下,主要就是将官方 mui tab底部凸起案例 的字体图标换成了图片:
2、util.js代码修改如下(主要将字体颜色配置都换成了图片,并且将subpages变成了对象数组,增加了id和url字段,这样更加符合实际需求,新增了首页,并且初始化显示第一页):
3、index.html代码修改如下(主要将中间凸起的效果有原来的字体图标改成了图片):
下面是源码下载:
nativeTab_5imoban
注:代码注释非常详细,可以对比着官方demo进行修改,也可以直接使用我爱模板网修改的demo,将图片替换即可。
其实官方已经给出详细解决方案: tab选项卡示例教程-基于subnview模式的原生tab(含底部凸起大图标)
但是官方的案例首页是写死的,并且图标是字体图标,不是图片,还有其他一些效果都和我们平时的需求不同,所以,我爱模板网对其进行了改良,下面是相关代码,具体就不解释了:
1、mainifest.json代码修改如下,主要就是将官方 mui tab底部凸起案例 的字体图标换成了图片:
01 | "launchwebview" : { |
02 | "bottom" : "0px" , |
03 | "background" : "#fff" , |
04 | "subNViews" : [ |
05 | { |
06 | "id" : "tabBar" , |
07 | "styles" : { |
08 | "bottom" : "0px" , |
09 | "left" : "0" , |
10 | "height" : "50px" , |
11 | "width" : "100%" , |
12 | "backgroundColor" : "#fff" |
13 | }, |
14 | "tags" : [ |
15 | { |
16 | "tag" : "img" , |
17 | "id" : "homeIcon" , |
18 | "src" : "images/home_nor.png" , |
19 | "position" : { |
20 | "top" : "4px" , |
21 | "left" : "10%" , |
22 | "width" : "25px" , |
23 | "height" : "40px" |
24 | } |
25 | },{ |
26 | "tag" : "img" , |
27 | "id" : "scheduleIcon" , |
28 | "src" : "images/schedule_nor.png" , |
29 | "position" : { |
30 | "top" : "4px" , |
31 | "left" : "30%" , |
32 | "width" : "25px" , |
33 | "height" : "40px" |
34 | } |
35 | },{ |
36 | "tag" : "img" , |
37 | "id" : "goodsIcon" , |
38 | "src" : "images/goods_nor.png" , |
39 | "position" : { |
40 | "top" : "4px" , |
41 | "left" : "65%" , |
42 | "width" : "25px" , |
43 | "height" : "40px" |
44 | } |
45 | },{ |
46 | "tag" : "img" , |
47 | "id" : "mineIcon" , |
48 | "src" : "images/mine_nor.png" , |
49 | "position" : { |
50 | "top" : "4px" , |
51 | "left" : "85%" , |
52 | "width" : "25px" , |
53 | "height" : "40px" |
54 | } |
55 | } |
56 | ] |
57 | } |
58 | ] |
59 | } |
001 | var util = { |
002 | options: { |
003 | ACTIVE_SRC1: "images/home_click.png" , |
004 | NORMAL_SRC1: "images/home_nor.png" , |
005 | ACTIVE_SRC2: "images/schedule_click.png" , |
006 | NORMAL_SRC2: "images/schedule_nor.png" , |
007 | ACTIVE_SRC3: "images/goods_click.png" , |
008 | NORMAL_SRC3: "images/goods_nor.png" , |
009 | ACTIVE_SRC4: "images/mine_click.png" , |
010 | NORMAL_SRC4: "images/mine_nor.png" , |
011 | subpages: [{ |
012 | url : 'pages/home.html' , |
013 | id : 'home' |
014 | },{ |
015 | url : 'pages/schedule.html' , |
016 | id : 'schedule' |
017 | },{ |
018 | url : 'pages/goods.html' , |
019 | id : 'goods' |
020 | },{ |
021 | url : 'pages/mine.html' , |
022 | id : 'mine' |
023 | },] |
024 | }, |
025 | /** |
026 | * 简单封装了绘制原生view控件的方法 |
027 | * 绘制内容支持font(文本,字体图标),图片img , 矩形区域rect |
028 | */ |
029 | drawNative: function (id, styles, tags) { |
030 | var view = new plus.nativeObj.View(id, styles, tags); |
031 | return view; |
032 | }, |
033 | /** |
034 | * 初始化首个tab窗口 和 创建子webview窗口 |
035 | */ |
036 | initSubpage: function (aniShow) { |
037 | var subpage_style = { |
038 | top: 0, |
039 | bottom: 51 |
040 | }, |
041 | subpages = util.options.subpages, |
042 | self = plus.webview.currentWebview(), |
043 | temp = {}; |
044 | //兼容安卓上添加titleNView 和 设置沉浸式模式会遮盖子webview内容 |
045 | if (mui.os.android) { |
046 | if (plus.navigator.isImmersedStatusbar()) { |
047 | subpage_style.top += plus.navigator.getStatusbarHeight(); |
048 | } |
049 | if (self.getTitleNView()) { |
050 | subpage_style.top += 40; |
051 | } |
052 | } |
053 |
054 | // 初始化第一个tab项为首次显示 |
055 | temp[self.id] = "true" ; |
056 | mui.extend(aniShow, temp); |
057 |
058 | // 初始化绘制首个tab按钮 |
059 | util.toggleNview(0); |
060 |
061 | //预加载所有子页面 |
062 | for ( var i = 0, len = subpages.length; i < len; i++) { |
063 | if (!plus.webview.getWebviewById(subpages[i].id)) { |
064 | var sub = plus.webview.create(subpages[i].url, subpages[i].id, subpage_style); |
065 | //初始化隐藏 |
066 | sub.hide(); |
067 | // append到当前父webview |
068 | self.append(sub); |
069 | } |
070 | } |
071 |
072 | //初始化显示第一个子页面 |
073 | plus.webview.show(plus.webview.getWebviewById(subpages[0].id)); |
074 |
075 | }, |
076 | /** |
077 | * 点击切换tab窗口 |
078 | */ |
079 | changeSubpage: function (targetPage, activePage, aniShow) { |
080 | //若为iOS平台或非首次显示,则直接显示 |
081 | if (mui.os.ios || aniShow[targetPage]) { |
082 | plus.webview.show(targetPage); |
083 | } else { |
084 | //否则,使用fade-in动画,且保存变量 |
085 | var temp = {}; |
086 | temp[targetPage] = "true" ; |
087 | mui.extend(aniShow, temp); |
088 | plus.webview.show(targetPage, "fade-in" , 300); |
089 | } |
090 | //隐藏当前 除了第一个父窗口 |
091 | if (activePage !== plus.webview.getLaunchWebview()) { |
092 | plus.webview.hide(activePage); |
093 | } |
094 | }, |
095 | /** |
096 | * 点击重绘底部tab (view控件) |
097 | */ |
098 | toggleNview: function (currIndex) { |
099 | // 重绘当前tag 包括icon和text,所以执行两个重绘操作 |
100 | switch (currIndex){ |
101 | case 0 : |
102 | util.updateSubNView(0, util.options.ACTIVE_SRC1); |
103 | util.updateSubNView(1, util.options.NORMAL_SRC2); |
104 | util.updateSubNView(2, util.options.NORMAL_SRC3); |
105 | util.updateSubNView(3, util.options.NORMAL_SRC4); |
106 | break ; |
107 | case 1 : |
108 | util.updateSubNView(0, util.options.NORMAL_SRC1); |
109 | util.updateSubNView(1, util.options.ACTIVE_SRC2); |
110 | util.updateSubNView(2, util.options.NORMAL_SRC3); |
111 | util.updateSubNView(3, util.options.NORMAL_SRC4); |
112 | break ; |
113 | case 2 : |
114 | util.updateSubNView(0, util.options.NORMAL_SRC1); |
115 | util.updateSubNView(1, util.options.NORMAL_SRC2); |
116 | util.updateSubNView(2, util.options.ACTIVE_SRC3); |
117 | util.updateSubNView(3, util.options.NORMAL_SRC4); |
118 | break ; |
119 | case 3 : |
120 | util.updateSubNView(0, util.options.NORMAL_SRC1); |
121 | util.updateSubNView(1, util.options.NORMAL_SRC2); |
122 | util.updateSubNView(2, util.options.NORMAL_SRC3); |
123 | util.updateSubNView(3, util.options.ACTIVE_SRC4); |
124 | break ; |
125 | } |
126 | }, |
127 | /* |
128 | * 利用 plus.nativeObj.View 提供的 drawBitmap 方法更新 view 控件 |
129 | */ |
130 | updateSubNView: function (currIndex, src) { |
131 | var self = plus.webview.currentWebview(), |
132 | nviewEvent = plus.nativeObj.View.getViewById( "tabBar" ), // 获取nview控件对象 |
133 | nviewObj = self.getStyle().subNViews[0], // 获取nview对象的属性 |
134 | currTag = nviewObj.tags[currIndex]; // 获取当前需重绘的tag |
135 | nviewEvent.drawBitmap(src, '' ,currTag.position, currTag.id); |
136 | } |
137 | }; |
001 | <!DOCTYPE html> |
002 | < html > |
003 | < head > |
004 | < meta charset = "UTF-8" > |
005 | < meta name = "viewport" content = "width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> |
006 | < title >首页</ title > |
007 | < script src = "js/mui.min.js" ></ script > |
008 | < link href = "css/mui.min.css" rel = "stylesheet" /> |
009 | < style > |
010 | html, |
011 | body { |
012 | background-color: #efeff4; |
013 | } |
014 |
015 | .title { |
016 | margin: 20px 15px 10px; |
017 | color: #6d6d72; |
018 | font-size: 15px; |
019 | padding-bottom: 51px; |
020 | } |
021 | </ style > |
022 | </ head > |
023 |
024 | < body > |
025 | < script src = "js/util.js" ></ script > |
026 | < script type = "text/javascript" > |
027 | (function() { |
028 | mui.init({ |
029 | swipeBack: true //启用右滑关闭功能 |
030 | }); |
031 | mui.plusReady(function() { |
032 | var self = plus.webview.currentWebview(), |
033 | leftPos = Math.ceil((window.innerWidth - 60) / 2); // 设置凸起大图标为水平居中 |
034 | /** |
035 | * drawNativeIcon 绘制凸起圆, |
036 | * 实现原理: |
037 | * id为bg的tag 创建带边框的圆 |
038 | * id为bg2的tag 创建白色矩形遮住圆下半部分,只显示凸起带边框部分 |
039 | * id为iconBg的红色背景图 |
040 | * id为icon的字体图标 |
041 | * 注意创建先后顺序,创建越晚的层级越高 |
042 | */ |
043 | var drawNativeIcon = util.drawNative('icon', { |
044 | bottom: '5px', |
045 | left: leftPos + 'px', |
046 | width: '60px', |
047 | height: '60px' |
048 | }, [{ |
049 | tag: 'rect', |
050 | id: 'bg', |
051 | position: { |
052 | top: '1px', |
053 | left: '0px', |
054 | width: '100%', |
055 | height: '100%' |
056 | }, |
057 | rectStyles: { |
058 | color: '#fff', |
059 | radius: '50%', |
060 | borderColor: '#ccc', |
061 | borderWidth: '1px' |
062 | } |
063 | }, { |
064 | tag: 'rect', |
065 | id: 'bg2', |
066 | position: { |
067 | bottom: '-0.5px', |
068 | left: '0px', |
069 | width: '100%', |
070 | height: '45px' |
071 | }, |
072 | rectStyles: { |
073 | color: '#fff' |
074 | } |
075 | }, { |
076 | tag: 'rect', |
077 | id: 'iconBg', |
078 | position: { |
079 | top: '5px', |
080 | left: '5px', |
081 | width: '50px', |
082 | height: '50px' |
083 | }, |
084 | rectStyles: { |
085 | color: '#0ab88e', |
086 | radius: '50%' |
087 | } |
088 | },{ |
089 | tag: 'img', |
090 | id: 'icon', |
091 | position: { |
092 | top: '15px', |
093 | left: '15px', |
094 | width: '30px', |
095 | height: '30px' |
096 | }, |
097 | src: 'images/icon_scan.png' |
098 | }]); |
099 | // 将绘制的凸起 append 到父webview中 |
100 | self.append(drawNativeIcon); |
101 |
102 |
103 | //凸起圆的点击事件 |
104 | var active_color = '#fff'; |
105 | drawNativeIcon.addEventListener('click', function(e) { |
106 | mui.openWindow({ |
107 | id : 'scan', |
108 | url : 'pages/scan.html' |
109 | }) |
110 | }); |
111 | // 中间凸起图标绘制及监听点击 完毕 |
112 |
113 | // 创建子webview窗口 并初始化 |
114 | var aniShow = {}; |
115 | util.initSubpage(aniShow); |
116 | |
117 | //初始化相关参数 |
118 | var nview = plus.nativeObj.View.getViewById('tabBar'), |
119 | activePage = plus.webview.currentWebview(), |
120 | targetPage, |
121 | subpages = util.options.subpages, |
122 | pageW = window.innerWidth, |
123 | currIndex = 0; |
124 | |
125 | /** |
126 | * 根据判断view控件点击位置判断切换的tab |
127 | */ |
128 | nview.addEventListener('click', function(e) { |
129 | var clientX = e.clientX; |
130 | if(clientX >= 0 && clientX <= parseInt(pageW * 0.25)) { |
131 | currIndex = 0; |
132 | } else if(clientX > parseInt(pageW * 0.25) && clientX <= parseInt(pageW * 0.45)) { |
133 | currIndex = 1; |
134 | } else if(clientX > parseInt(pageW * 0.45) && clientX <= parseInt(pageW * 0.8)) { |
135 | currIndex = 2; |
136 | } else { |
137 | currIndex = 3; |
138 | } |
139 | // 匹配对应tab窗口 |
140 | if(plus.webview.getWebviewById(subpages[currIndex].id) == plus.webview.currentWebview()){ |
141 | return; |
142 | }else{ |
143 | targetPage = plus.webview.getWebviewById(subpages[currIndex].id); |
144 | } |
145 |
146 | //底部选项卡切换 |
147 | util.toggleNview(currIndex); |
148 | // 子页面切换 |
149 | util.changeSubpage(targetPage, activePage, aniShow); |
150 | //更新当前活跃的页面 |
151 | activePage = targetPage; |
152 |
153 | }); |
154 | }); |
155 | })(); |
156 | </ script > |
157 | </ body > |
158 | </ html > |
nativeTab_5imoban
注:代码注释非常详细,可以对比着官方demo进行修改,也可以直接使用我爱模板网修改的demo,将图片替换即可。